sync
[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                 "Roo.bootstrap",
705                 "Roo.bootstrap.dash");
706 /*
707  * Based on:
708  * Ext JS Library 1.1.1
709  * Copyright(c) 2006-2007, Ext JS, LLC.
710  *
711  * Originally Released Under LGPL - original licence link has changed is not relivant.
712  *
713  * Fork - LGPL
714  * <script type="text/javascript">
715  */
716
717 (function() {    
718     // wrappedn so fnCleanup is not in global scope...
719     if(Roo.isIE) {
720         function fnCleanUp() {
721             var p = Function.prototype;
722             delete p.createSequence;
723             delete p.defer;
724             delete p.createDelegate;
725             delete p.createCallback;
726             delete p.createInterceptor;
727
728             window.detachEvent("onunload", fnCleanUp);
729         }
730         window.attachEvent("onunload", fnCleanUp);
731     }
732 })();
733
734
735 /**
736  * @class Function
737  * These functions are available on every Function object (any JavaScript function).
738  */
739 Roo.apply(Function.prototype, {
740      /**
741      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743      * Will create a function that is bound to those 2 args.
744      * @return {Function} The new function
745     */
746     createCallback : function(/*args...*/){
747         // make args available, in function below
748         var args = arguments;
749         var method = this;
750         return function() {
751             return method.apply(window, args);
752         };
753     },
754
755     /**
756      * Creates a delegate (callback) that sets the scope to obj.
757      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758      * Will create a function that is automatically scoped to this.
759      * @param {Object} obj (optional) The object for which the scope is set
760      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762      *                                             if a number the args are inserted at the specified position
763      * @return {Function} The new function
764      */
765     createDelegate : function(obj, args, appendArgs){
766         var method = this;
767         return function() {
768             var callArgs = args || arguments;
769             if(appendArgs === true){
770                 callArgs = Array.prototype.slice.call(arguments, 0);
771                 callArgs = callArgs.concat(args);
772             }else if(typeof appendArgs == "number"){
773                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776             }
777             return method.apply(obj || window, callArgs);
778         };
779     },
780
781     /**
782      * Calls this function after the number of millseconds specified.
783      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784      * @param {Object} obj (optional) The object for which the scope is set
785      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787      *                                             if a number the args are inserted at the specified position
788      * @return {Number} The timeout id that can be used with clearTimeout
789      */
790     defer : function(millis, obj, args, appendArgs){
791         var fn = this.createDelegate(obj, args, appendArgs);
792         if(millis){
793             return setTimeout(fn, millis);
794         }
795         fn();
796         return 0;
797     },
798     /**
799      * Create a combined function call sequence of the original function + the passed function.
800      * The resulting function returns the results of the original function.
801      * The passed fcn is called with the parameters of the original function
802      * @param {Function} fcn The function to sequence
803      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804      * @return {Function} The new function
805      */
806     createSequence : function(fcn, scope){
807         if(typeof fcn != "function"){
808             return this;
809         }
810         var method = this;
811         return function() {
812             var retval = method.apply(this || window, arguments);
813             fcn.apply(scope || this || window, arguments);
814             return retval;
815         };
816     },
817
818     /**
819      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820      * The resulting function returns the results of the original function.
821      * The passed fcn is called with the parameters of the original function.
822      * @addon
823      * @param {Function} fcn The function to call before the original
824      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825      * @return {Function} The new function
826      */
827     createInterceptor : function(fcn, scope){
828         if(typeof fcn != "function"){
829             return this;
830         }
831         var method = this;
832         return function() {
833             fcn.target = this;
834             fcn.method = method;
835             if(fcn.apply(scope || this || window, arguments) === false){
836                 return;
837             }
838             return method.apply(this || window, arguments);
839         };
840     }
841 });
842 /*
843  * Based on:
844  * Ext JS Library 1.1.1
845  * Copyright(c) 2006-2007, Ext JS, LLC.
846  *
847  * Originally Released Under LGPL - original licence link has changed is not relivant.
848  *
849  * Fork - LGPL
850  * <script type="text/javascript">
851  */
852
853 Roo.applyIf(String, {
854     
855     /** @scope String */
856     
857     /**
858      * Escapes the passed string for ' and \
859      * @param {String} string The string to escape
860      * @return {String} The escaped string
861      * @static
862      */
863     escape : function(string) {
864         return string.replace(/('|\\)/g, "\\$1");
865     },
866
867     /**
868      * Pads the left side of a string with a specified character.  This is especially useful
869      * for normalizing number and date strings.  Example usage:
870      * <pre><code>
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
873 </code></pre>
874      * @param {String} string The original string
875      * @param {Number} size The total length of the output string
876      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877      * @return {String} The padded string
878      * @static
879      */
880     leftPad : function (val, size, ch) {
881         var result = new String(val);
882         if(ch === null || ch === undefined || ch === '') {
883             ch = " ";
884         }
885         while (result.length < size) {
886             result = ch + result;
887         }
888         return result;
889     },
890
891     /**
892      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
893      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
894      * <pre><code>
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
898 </code></pre>
899      * @param {String} string The tokenized string to be formatted
900      * @param {String} value1 The value to replace token {0}
901      * @param {String} value2 Etc...
902      * @return {String} The formatted string
903      * @static
904      */
905     format : function(format){
906         var args = Array.prototype.slice.call(arguments, 1);
907         return format.replace(/\{(\d+)\}/g, function(m, i){
908             return Roo.util.Format.htmlEncode(args[i]);
909         });
910     }
911   
912     
913 });
914
915 /**
916  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
917  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
918  * they are already different, the first value passed in is returned.  Note that this method returns the new value
919  * but does not change the current string.
920  * <pre><code>
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
923
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 </code></pre>
927  * @param {String} value The value to compare to the current string
928  * @param {String} other The new value to use if the string already equals the first value passed in
929  * @return {String} The new value
930  */
931  
932 String.prototype.toggle = function(value, other){
933     return this == value ? other : value;
934 };
935
936
937 /**
938   * Remove invalid unicode characters from a string 
939   *
940   * @return {String} The clean string
941   */
942 String.prototype.unicodeClean = function () {
943     return this.replace(/[\s\S]/g,
944         function(character) {
945             if (character.charCodeAt()< 256) {
946               return character;
947            }
948            try {
949                 encodeURIComponent(character);
950            } catch(e) { 
951               return '';
952            }
953            return character;
954         }
955     );
956 };
957   
958 /*
959  * Based on:
960  * Ext JS Library 1.1.1
961  * Copyright(c) 2006-2007, Ext JS, LLC.
962  *
963  * Originally Released Under LGPL - original licence link has changed is not relivant.
964  *
965  * Fork - LGPL
966  * <script type="text/javascript">
967  */
968
969  /**
970  * @class Number
971  */
972 Roo.applyIf(Number.prototype, {
973     /**
974      * Checks whether or not the current number is within a desired range.  If the number is already within the
975      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976      * exceeded.  Note that this method returns the constrained value but does not change the current number.
977      * @param {Number} min The minimum number in the range
978      * @param {Number} max The maximum number in the range
979      * @return {Number} The constrained value if outside the range, otherwise the current value
980      */
981     constrain : function(min, max){
982         return Math.min(Math.max(this, min), max);
983     }
984 });/*
985  * Based on:
986  * Ext JS Library 1.1.1
987  * Copyright(c) 2006-2007, Ext JS, LLC.
988  *
989  * Originally Released Under LGPL - original licence link has changed is not relivant.
990  *
991  * Fork - LGPL
992  * <script type="text/javascript">
993  */
994  /**
995  * @class Array
996  */
997 Roo.applyIf(Array.prototype, {
998     /**
999      * 
1000      * Checks whether or not the specified object exists in the array.
1001      * @param {Object} o The object to check for
1002      * @return {Number} The index of o in the array (or -1 if it is not found)
1003      */
1004     indexOf : function(o){
1005        for (var i = 0, len = this.length; i < len; i++){
1006               if(this[i] == o) { return i; }
1007        }
1008            return -1;
1009     },
1010
1011     /**
1012      * Removes the specified object from the array.  If the object is not found nothing happens.
1013      * @param {Object} o The object to remove
1014      */
1015     remove : function(o){
1016        var index = this.indexOf(o);
1017        if(index != -1){
1018            this.splice(index, 1);
1019        }
1020     },
1021     /**
1022      * Map (JS 1.6 compatibility)
1023      * @param {Function} function  to call
1024      */
1025     map : function(fun )
1026     {
1027         var len = this.length >>> 0;
1028         if (typeof fun != "function") {
1029             throw new TypeError();
1030         }
1031         var res = new Array(len);
1032         var thisp = arguments[1];
1033         for (var i = 0; i < len; i++)
1034         {
1035             if (i in this) {
1036                 res[i] = fun.call(thisp, this[i], i, this);
1037             }
1038         }
1039
1040         return res;
1041     },
1042     /**
1043      * equals
1044      * @param {Array} o The array to compare to
1045      * @returns {Boolean} true if the same
1046      */
1047     equals : function(b)
1048     {
1049             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1050         if (this === b) {
1051             return true;
1052         }
1053         if (b == null) {
1054             return false;
1055         }
1056         if (this.length !== b.length) {
1057             return false;
1058         }
1059           
1060         // sort?? a.sort().equals(b.sort());
1061           
1062         for (var i = 0; i < this.length; ++i) {
1063             if (this[i] !== b[i]) {
1064             return false;
1065             }
1066         }
1067         return true;
1068     } 
1069     
1070     
1071     
1072     
1073 });
1074
1075 Roo.applyIf(Array, {
1076  /**
1077      * from
1078      * @static
1079      * @param {Array} o Or Array like object (eg. nodelist)
1080      * @returns {Array} 
1081      */
1082     from : function(o)
1083     {
1084         var ret= [];
1085     
1086         for (var i =0; i < o.length; i++) { 
1087             ret[i] = o[i];
1088         }
1089         return ret;
1090       
1091     }
1092 });
1093 /*
1094  * Based on:
1095  * Ext JS Library 1.1.1
1096  * Copyright(c) 2006-2007, Ext JS, LLC.
1097  *
1098  * Originally Released Under LGPL - original licence link has changed is not relivant.
1099  *
1100  * Fork - LGPL
1101  * <script type="text/javascript">
1102  */
1103
1104 /**
1105  * @class Date
1106  *
1107  * The date parsing and format syntax is a subset of
1108  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1109  * supported will provide results equivalent to their PHP versions.
1110  *
1111  * Following is the list of all currently supported formats:
1112  *<pre>
1113 Sample date:
1114 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1115
1116 Format  Output      Description
1117 ------  ----------  --------------------------------------------------------------
1118   d      10         Day of the month, 2 digits with leading zeros
1119   D      Wed        A textual representation of a day, three letters
1120   j      10         Day of the month without leading zeros
1121   l      Wednesday  A full textual representation of the day of the week
1122   S      th         English ordinal day of month suffix, 2 chars (use with j)
1123   w      3          Numeric representation of the day of the week
1124   z      9          The julian date, or day of the year (0-365)
1125   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1126   F      January    A full textual representation of the month
1127   m      01         Numeric representation of a month, with leading zeros
1128   M      Jan        Month name abbreviation, three letters
1129   n      1          Numeric representation of a month, without leading zeros
1130   t      31         Number of days in the given month
1131   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1132   Y      2007       A full numeric representation of a year, 4 digits
1133   y      07         A two digit representation of a year
1134   a      pm         Lowercase Ante meridiem and Post meridiem
1135   A      PM         Uppercase Ante meridiem and Post meridiem
1136   g      3          12-hour format of an hour without leading zeros
1137   G      15         24-hour format of an hour without leading zeros
1138   h      03         12-hour format of an hour with leading zeros
1139   H      15         24-hour format of an hour with leading zeros
1140   i      05         Minutes with leading zeros
1141   s      01         Seconds, with leading zeros
1142   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1143   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1144   T      CST        Timezone setting of the machine running the code
1145   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1146 </pre>
1147  *
1148  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1149  * <pre><code>
1150 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1151 document.write(dt.format('Y-m-d'));                         //2007-01-10
1152 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1153 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
1154  </code></pre>
1155  *
1156  * Here are some standard date/time patterns that you might find helpful.  They
1157  * are not part of the source of Date.js, but to use them you can simply copy this
1158  * block of code into any script that is included after Date.js and they will also become
1159  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1160  * <pre><code>
1161 Date.patterns = {
1162     ISO8601Long:"Y-m-d H:i:s",
1163     ISO8601Short:"Y-m-d",
1164     ShortDate: "n/j/Y",
1165     LongDate: "l, F d, Y",
1166     FullDateTime: "l, F d, Y g:i:s A",
1167     MonthDay: "F d",
1168     ShortTime: "g:i A",
1169     LongTime: "g:i:s A",
1170     SortableDateTime: "Y-m-d\\TH:i:s",
1171     UniversalSortableDateTime: "Y-m-d H:i:sO",
1172     YearMonth: "F, Y"
1173 };
1174 </code></pre>
1175  *
1176  * Example usage:
1177  * <pre><code>
1178 var dt = new Date();
1179 document.write(dt.format(Date.patterns.ShortDate));
1180  </code></pre>
1181  */
1182
1183 /*
1184  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1185  * They generate precompiled functions from date formats instead of parsing and
1186  * processing the pattern every time you format a date.  These functions are available
1187  * on every Date object (any javascript function).
1188  *
1189  * The original article and download are here:
1190  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1191  *
1192  */
1193  
1194  
1195  // was in core
1196 /**
1197  Returns the number of milliseconds between this date and date
1198  @param {Date} date (optional) Defaults to now
1199  @return {Number} The diff in milliseconds
1200  @member Date getElapsed
1201  */
1202 Date.prototype.getElapsed = function(date) {
1203         return Math.abs((date || new Date()).getTime()-this.getTime());
1204 };
1205 // was in date file..
1206
1207
1208 // private
1209 Date.parseFunctions = {count:0};
1210 // private
1211 Date.parseRegexes = [];
1212 // private
1213 Date.formatFunctions = {count:0};
1214
1215 // private
1216 Date.prototype.dateFormat = function(format) {
1217     if (Date.formatFunctions[format] == null) {
1218         Date.createNewFormat(format);
1219     }
1220     var func = Date.formatFunctions[format];
1221     return this[func]();
1222 };
1223
1224
1225 /**
1226  * Formats a date given the supplied format string
1227  * @param {String} format The format string
1228  * @return {String} The formatted date
1229  * @method
1230  */
1231 Date.prototype.format = Date.prototype.dateFormat;
1232
1233 // private
1234 Date.createNewFormat = function(format) {
1235     var funcName = "format" + Date.formatFunctions.count++;
1236     Date.formatFunctions[format] = funcName;
1237     var code = "Date.prototype." + funcName + " = function(){return ";
1238     var special = false;
1239     var ch = '';
1240     for (var i = 0; i < format.length; ++i) {
1241         ch = format.charAt(i);
1242         if (!special && ch == "\\") {
1243             special = true;
1244         }
1245         else if (special) {
1246             special = false;
1247             code += "'" + String.escape(ch) + "' + ";
1248         }
1249         else {
1250             code += Date.getFormatCode(ch);
1251         }
1252     }
1253     /** eval:var:zzzzzzzzzzzzz */
1254     eval(code.substring(0, code.length - 3) + ";}");
1255 };
1256
1257 // private
1258 Date.getFormatCode = function(character) {
1259     switch (character) {
1260     case "d":
1261         return "String.leftPad(this.getDate(), 2, '0') + ";
1262     case "D":
1263         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1264     case "j":
1265         return "this.getDate() + ";
1266     case "l":
1267         return "Date.dayNames[this.getDay()] + ";
1268     case "S":
1269         return "this.getSuffix() + ";
1270     case "w":
1271         return "this.getDay() + ";
1272     case "z":
1273         return "this.getDayOfYear() + ";
1274     case "W":
1275         return "this.getWeekOfYear() + ";
1276     case "F":
1277         return "Date.monthNames[this.getMonth()] + ";
1278     case "m":
1279         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1280     case "M":
1281         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1282     case "n":
1283         return "(this.getMonth() + 1) + ";
1284     case "t":
1285         return "this.getDaysInMonth() + ";
1286     case "L":
1287         return "(this.isLeapYear() ? 1 : 0) + ";
1288     case "Y":
1289         return "this.getFullYear() + ";
1290     case "y":
1291         return "('' + this.getFullYear()).substring(2, 4) + ";
1292     case "a":
1293         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1294     case "A":
1295         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1296     case "g":
1297         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1298     case "G":
1299         return "this.getHours() + ";
1300     case "h":
1301         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1302     case "H":
1303         return "String.leftPad(this.getHours(), 2, '0') + ";
1304     case "i":
1305         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1306     case "s":
1307         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1308     case "O":
1309         return "this.getGMTOffset() + ";
1310     case "P":
1311         return "this.getGMTColonOffset() + ";
1312     case "T":
1313         return "this.getTimezone() + ";
1314     case "Z":
1315         return "(this.getTimezoneOffset() * -60) + ";
1316     default:
1317         return "'" + String.escape(character) + "' + ";
1318     }
1319 };
1320
1321 /**
1322  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1323  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1324  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1325  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1326  * string or the parse operation will fail.
1327  * Example Usage:
1328 <pre><code>
1329 //dt = Fri May 25 2007 (current date)
1330 var dt = new Date();
1331
1332 //dt = Thu May 25 2006 (today's month/day in 2006)
1333 dt = Date.parseDate("2006", "Y");
1334
1335 //dt = Sun Jan 15 2006 (all date parts specified)
1336 dt = Date.parseDate("2006-1-15", "Y-m-d");
1337
1338 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1339 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1340 </code></pre>
1341  * @param {String} input The unparsed date as a string
1342  * @param {String} format The format the date is in
1343  * @return {Date} The parsed date
1344  * @static
1345  */
1346 Date.parseDate = function(input, format) {
1347     if (Date.parseFunctions[format] == null) {
1348         Date.createParser(format);
1349     }
1350     var func = Date.parseFunctions[format];
1351     return Date[func](input);
1352 };
1353 /**
1354  * @private
1355  */
1356
1357 Date.createParser = function(format) {
1358     var funcName = "parse" + Date.parseFunctions.count++;
1359     var regexNum = Date.parseRegexes.length;
1360     var currentGroup = 1;
1361     Date.parseFunctions[format] = funcName;
1362
1363     var code = "Date." + funcName + " = function(input){\n"
1364         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1365         + "var d = new Date();\n"
1366         + "y = d.getFullYear();\n"
1367         + "m = d.getMonth();\n"
1368         + "d = d.getDate();\n"
1369         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1370         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1371         + "if (results && results.length > 0) {";
1372     var regex = "";
1373
1374     var special = false;
1375     var ch = '';
1376     for (var i = 0; i < format.length; ++i) {
1377         ch = format.charAt(i);
1378         if (!special && ch == "\\") {
1379             special = true;
1380         }
1381         else if (special) {
1382             special = false;
1383             regex += String.escape(ch);
1384         }
1385         else {
1386             var obj = Date.formatCodeToRegex(ch, currentGroup);
1387             currentGroup += obj.g;
1388             regex += obj.s;
1389             if (obj.g && obj.c) {
1390                 code += obj.c;
1391             }
1392         }
1393     }
1394
1395     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1396         + "{v = new Date(y, m, d, h, i, s);}\n"
1397         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1398         + "{v = new Date(y, m, d, h, i);}\n"
1399         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1400         + "{v = new Date(y, m, d, h);}\n"
1401         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1402         + "{v = new Date(y, m, d);}\n"
1403         + "else if (y >= 0 && m >= 0)\n"
1404         + "{v = new Date(y, m);}\n"
1405         + "else if (y >= 0)\n"
1406         + "{v = new Date(y);}\n"
1407         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1408         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1409         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1410         + ";}";
1411
1412     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1413     /** eval:var:zzzzzzzzzzzzz */
1414     eval(code);
1415 };
1416
1417 // private
1418 Date.formatCodeToRegex = function(character, currentGroup) {
1419     switch (character) {
1420     case "D":
1421         return {g:0,
1422         c:null,
1423         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1424     case "j":
1425         return {g:1,
1426             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1427             s:"(\\d{1,2})"}; // day of month without leading zeroes
1428     case "d":
1429         return {g:1,
1430             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1431             s:"(\\d{2})"}; // day of month with leading zeroes
1432     case "l":
1433         return {g:0,
1434             c:null,
1435             s:"(?:" + Date.dayNames.join("|") + ")"};
1436     case "S":
1437         return {g:0,
1438             c:null,
1439             s:"(?:st|nd|rd|th)"};
1440     case "w":
1441         return {g:0,
1442             c:null,
1443             s:"\\d"};
1444     case "z":
1445         return {g:0,
1446             c:null,
1447             s:"(?:\\d{1,3})"};
1448     case "W":
1449         return {g:0,
1450             c:null,
1451             s:"(?:\\d{2})"};
1452     case "F":
1453         return {g:1,
1454             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1455             s:"(" + Date.monthNames.join("|") + ")"};
1456     case "M":
1457         return {g:1,
1458             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1459             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1460     case "n":
1461         return {g:1,
1462             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1463             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1464     case "m":
1465         return {g:1,
1466             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1467             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1468     case "t":
1469         return {g:0,
1470             c:null,
1471             s:"\\d{1,2}"};
1472     case "L":
1473         return {g:0,
1474             c:null,
1475             s:"(?:1|0)"};
1476     case "Y":
1477         return {g:1,
1478             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1479             s:"(\\d{4})"};
1480     case "y":
1481         return {g:1,
1482             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1483                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1484             s:"(\\d{1,2})"};
1485     case "a":
1486         return {g:1,
1487             c:"if (results[" + currentGroup + "] == 'am') {\n"
1488                 + "if (h == 12) { h = 0; }\n"
1489                 + "} else { if (h < 12) { h += 12; }}",
1490             s:"(am|pm)"};
1491     case "A":
1492         return {g:1,
1493             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1494                 + "if (h == 12) { h = 0; }\n"
1495                 + "} else { if (h < 12) { h += 12; }}",
1496             s:"(AM|PM)"};
1497     case "g":
1498     case "G":
1499         return {g:1,
1500             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1501             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1502     case "h":
1503     case "H":
1504         return {g:1,
1505             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1506             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1507     case "i":
1508         return {g:1,
1509             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1510             s:"(\\d{2})"};
1511     case "s":
1512         return {g:1,
1513             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1514             s:"(\\d{2})"};
1515     case "O":
1516         return {g:1,
1517             c:[
1518                 "o = results[", currentGroup, "];\n",
1519                 "var sn = o.substring(0,1);\n", // get + / - sign
1520                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1521                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1522                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1523                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1524             ].join(""),
1525             s:"([+\-]\\d{2,4})"};
1526     
1527     
1528     case "P":
1529         return {g:1,
1530                 c:[
1531                    "o = results[", currentGroup, "];\n",
1532                    "var sn = o.substring(0,1);\n",
1533                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1534                    "var mn = o.substring(4,6) % 60;\n",
1535                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1536                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1537             ].join(""),
1538             s:"([+\-]\\d{4})"};
1539     case "T":
1540         return {g:0,
1541             c:null,
1542             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1543     case "Z":
1544         return {g:1,
1545             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1546                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1547             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1548     default:
1549         return {g:0,
1550             c:null,
1551             s:String.escape(character)};
1552     }
1553 };
1554
1555 /**
1556  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1557  * @return {String} The abbreviated timezone name (e.g. 'CST')
1558  */
1559 Date.prototype.getTimezone = function() {
1560     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1561 };
1562
1563 /**
1564  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1565  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1566  */
1567 Date.prototype.getGMTOffset = function() {
1568     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1569         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1570         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1571 };
1572
1573 /**
1574  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1575  * @return {String} 2-characters representing hours and 2-characters representing minutes
1576  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1577  */
1578 Date.prototype.getGMTColonOffset = function() {
1579         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1580                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1581                 + ":"
1582                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1583 }
1584
1585 /**
1586  * Get the numeric day number of the year, adjusted for leap year.
1587  * @return {Number} 0 through 364 (365 in leap years)
1588  */
1589 Date.prototype.getDayOfYear = function() {
1590     var num = 0;
1591     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1592     for (var i = 0; i < this.getMonth(); ++i) {
1593         num += Date.daysInMonth[i];
1594     }
1595     return num + this.getDate() - 1;
1596 };
1597
1598 /**
1599  * Get the string representation of the numeric week number of the year
1600  * (equivalent to the format specifier 'W').
1601  * @return {String} '00' through '52'
1602  */
1603 Date.prototype.getWeekOfYear = function() {
1604     // Skip to Thursday of this week
1605     var now = this.getDayOfYear() + (4 - this.getDay());
1606     // Find the first Thursday of the year
1607     var jan1 = new Date(this.getFullYear(), 0, 1);
1608     var then = (7 - jan1.getDay() + 4);
1609     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1610 };
1611
1612 /**
1613  * Whether or not the current date is in a leap year.
1614  * @return {Boolean} True if the current date is in a leap year, else false
1615  */
1616 Date.prototype.isLeapYear = function() {
1617     var year = this.getFullYear();
1618     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1619 };
1620
1621 /**
1622  * Get the first day of the current month, adjusted for leap year.  The returned value
1623  * is the numeric day index within the week (0-6) which can be used in conjunction with
1624  * the {@link #monthNames} array to retrieve the textual day name.
1625  * Example:
1626  *<pre><code>
1627 var dt = new Date('1/10/2007');
1628 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1629 </code></pre>
1630  * @return {Number} The day number (0-6)
1631  */
1632 Date.prototype.getFirstDayOfMonth = function() {
1633     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1634     return (day < 0) ? (day + 7) : day;
1635 };
1636
1637 /**
1638  * Get the last day of the current month, adjusted for leap year.  The returned value
1639  * is the numeric day index within the week (0-6) which can be used in conjunction with
1640  * the {@link #monthNames} array to retrieve the textual day name.
1641  * Example:
1642  *<pre><code>
1643 var dt = new Date('1/10/2007');
1644 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1645 </code></pre>
1646  * @return {Number} The day number (0-6)
1647  */
1648 Date.prototype.getLastDayOfMonth = function() {
1649     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1650     return (day < 0) ? (day + 7) : day;
1651 };
1652
1653
1654 /**
1655  * Get the first date of this date's month
1656  * @return {Date}
1657  */
1658 Date.prototype.getFirstDateOfMonth = function() {
1659     return new Date(this.getFullYear(), this.getMonth(), 1);
1660 };
1661
1662 /**
1663  * Get the last date of this date's month
1664  * @return {Date}
1665  */
1666 Date.prototype.getLastDateOfMonth = function() {
1667     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1668 };
1669 /**
1670  * Get the number of days in the current month, adjusted for leap year.
1671  * @return {Number} The number of days in the month
1672  */
1673 Date.prototype.getDaysInMonth = function() {
1674     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1675     return Date.daysInMonth[this.getMonth()];
1676 };
1677
1678 /**
1679  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1680  * @return {String} 'st, 'nd', 'rd' or 'th'
1681  */
1682 Date.prototype.getSuffix = function() {
1683     switch (this.getDate()) {
1684         case 1:
1685         case 21:
1686         case 31:
1687             return "st";
1688         case 2:
1689         case 22:
1690             return "nd";
1691         case 3:
1692         case 23:
1693             return "rd";
1694         default:
1695             return "th";
1696     }
1697 };
1698
1699 // private
1700 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1701
1702 /**
1703  * An array of textual month names.
1704  * Override these values for international dates, for example...
1705  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1706  * @type Array
1707  * @static
1708  */
1709 Date.monthNames =
1710    ["January",
1711     "February",
1712     "March",
1713     "April",
1714     "May",
1715     "June",
1716     "July",
1717     "August",
1718     "September",
1719     "October",
1720     "November",
1721     "December"];
1722
1723 /**
1724  * An array of textual day names.
1725  * Override these values for international dates, for example...
1726  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1727  * @type Array
1728  * @static
1729  */
1730 Date.dayNames =
1731    ["Sunday",
1732     "Monday",
1733     "Tuesday",
1734     "Wednesday",
1735     "Thursday",
1736     "Friday",
1737     "Saturday"];
1738
1739 // private
1740 Date.y2kYear = 50;
1741 // private
1742 Date.monthNumbers = {
1743     Jan:0,
1744     Feb:1,
1745     Mar:2,
1746     Apr:3,
1747     May:4,
1748     Jun:5,
1749     Jul:6,
1750     Aug:7,
1751     Sep:8,
1752     Oct:9,
1753     Nov:10,
1754     Dec:11};
1755
1756 /**
1757  * Creates and returns a new Date instance with the exact same date value as the called instance.
1758  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1759  * variable will also be changed.  When the intention is to create a new variable that will not
1760  * modify the original instance, you should create a clone.
1761  *
1762  * Example of correctly cloning a date:
1763  * <pre><code>
1764 //wrong way:
1765 var orig = new Date('10/1/2006');
1766 var copy = orig;
1767 copy.setDate(5);
1768 document.write(orig);  //returns 'Thu Oct 05 2006'!
1769
1770 //correct way:
1771 var orig = new Date('10/1/2006');
1772 var copy = orig.clone();
1773 copy.setDate(5);
1774 document.write(orig);  //returns 'Thu Oct 01 2006'
1775 </code></pre>
1776  * @return {Date} The new Date instance
1777  */
1778 Date.prototype.clone = function() {
1779         return new Date(this.getTime());
1780 };
1781
1782 /**
1783  * Clears any time information from this date
1784  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1785  @return {Date} this or the clone
1786  */
1787 Date.prototype.clearTime = function(clone){
1788     if(clone){
1789         return this.clone().clearTime();
1790     }
1791     this.setHours(0);
1792     this.setMinutes(0);
1793     this.setSeconds(0);
1794     this.setMilliseconds(0);
1795     return this;
1796 };
1797
1798 // private
1799 // safari setMonth is broken -- check that this is only donw once...
1800 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1801     Date.brokenSetMonth = Date.prototype.setMonth;
1802         Date.prototype.setMonth = function(num){
1803                 if(num <= -1){
1804                         var n = Math.ceil(-num);
1805                         var back_year = Math.ceil(n/12);
1806                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1807                         this.setFullYear(this.getFullYear() - back_year);
1808                         return Date.brokenSetMonth.call(this, month);
1809                 } else {
1810                         return Date.brokenSetMonth.apply(this, arguments);
1811                 }
1812         };
1813 }
1814
1815 /** Date interval constant 
1816 * @static 
1817 * @type String */
1818 Date.MILLI = "ms";
1819 /** Date interval constant 
1820 * @static 
1821 * @type String */
1822 Date.SECOND = "s";
1823 /** Date interval constant 
1824 * @static 
1825 * @type String */
1826 Date.MINUTE = "mi";
1827 /** Date interval constant 
1828 * @static 
1829 * @type String */
1830 Date.HOUR = "h";
1831 /** Date interval constant 
1832 * @static 
1833 * @type String */
1834 Date.DAY = "d";
1835 /** Date interval constant 
1836 * @static 
1837 * @type String */
1838 Date.MONTH = "mo";
1839 /** Date interval constant 
1840 * @static 
1841 * @type String */
1842 Date.YEAR = "y";
1843
1844 /**
1845  * Provides a convenient method of performing basic date arithmetic.  This method
1846  * does not modify the Date instance being called - it creates and returns
1847  * a new Date instance containing the resulting date value.
1848  *
1849  * Examples:
1850  * <pre><code>
1851 //Basic usage:
1852 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1853 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1854
1855 //Negative values will subtract correctly:
1856 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1857 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1858
1859 //You can even chain several calls together in one line!
1860 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1861 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1862  </code></pre>
1863  *
1864  * @param {String} interval   A valid date interval enum value
1865  * @param {Number} value      The amount to add to the current date
1866  * @return {Date} The new Date instance
1867  */
1868 Date.prototype.add = function(interval, value){
1869   var d = this.clone();
1870   if (!interval || value === 0) { return d; }
1871   switch(interval.toLowerCase()){
1872     case Date.MILLI:
1873       d.setMilliseconds(this.getMilliseconds() + value);
1874       break;
1875     case Date.SECOND:
1876       d.setSeconds(this.getSeconds() + value);
1877       break;
1878     case Date.MINUTE:
1879       d.setMinutes(this.getMinutes() + value);
1880       break;
1881     case Date.HOUR:
1882       d.setHours(this.getHours() + value);
1883       break;
1884     case Date.DAY:
1885       d.setDate(this.getDate() + value);
1886       break;
1887     case Date.MONTH:
1888       var day = this.getDate();
1889       if(day > 28){
1890           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1891       }
1892       d.setDate(day);
1893       d.setMonth(this.getMonth() + value);
1894       break;
1895     case Date.YEAR:
1896       d.setFullYear(this.getFullYear() + value);
1897       break;
1898   }
1899   return d;
1900 };
1901 /**
1902  * @class Roo.lib.Dom
1903  * @licence LGPL
1904  * @static
1905  * 
1906  * Dom utils (from YIU afaik)
1907  *
1908  * 
1909  **/
1910 Roo.lib.Dom = {
1911     /**
1912      * Get the view width
1913      * @param {Boolean} full True will get the full document, otherwise it's the view width
1914      * @return {Number} The width
1915      */
1916      
1917     getViewWidth : function(full) {
1918         return full ? this.getDocumentWidth() : this.getViewportWidth();
1919     },
1920     /**
1921      * Get the view height
1922      * @param {Boolean} full True will get the full document, otherwise it's the view height
1923      * @return {Number} The height
1924      */
1925     getViewHeight : function(full) {
1926         return full ? this.getDocumentHeight() : this.getViewportHeight();
1927     },
1928     /**
1929      * Get the Full Document height 
1930      * @return {Number} The height
1931      */
1932     getDocumentHeight: function() {
1933         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1934         return Math.max(scrollHeight, this.getViewportHeight());
1935     },
1936     /**
1937      * Get the Full Document width
1938      * @return {Number} The width
1939      */
1940     getDocumentWidth: function() {
1941         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1942         return Math.max(scrollWidth, this.getViewportWidth());
1943     },
1944     /**
1945      * Get the Window Viewport height
1946      * @return {Number} The height
1947      */
1948     getViewportHeight: function() {
1949         var height = self.innerHeight;
1950         var mode = document.compatMode;
1951
1952         if ((mode || Roo.isIE) && !Roo.isOpera) {
1953             height = (mode == "CSS1Compat") ?
1954                      document.documentElement.clientHeight :
1955                      document.body.clientHeight;
1956         }
1957
1958         return height;
1959     },
1960     /**
1961      * Get the Window Viewport width
1962      * @return {Number} The width
1963      */
1964     getViewportWidth: function() {
1965         var width = self.innerWidth;
1966         var mode = document.compatMode;
1967
1968         if (mode || Roo.isIE) {
1969             width = (mode == "CSS1Compat") ?
1970                     document.documentElement.clientWidth :
1971                     document.body.clientWidth;
1972         }
1973         return width;
1974     },
1975
1976     isAncestor : function(p, c) {
1977         p = Roo.getDom(p);
1978         c = Roo.getDom(c);
1979         if (!p || !c) {
1980             return false;
1981         }
1982
1983         if (p.contains && !Roo.isSafari) {
1984             return p.contains(c);
1985         } else if (p.compareDocumentPosition) {
1986             return !!(p.compareDocumentPosition(c) & 16);
1987         } else {
1988             var parent = c.parentNode;
1989             while (parent) {
1990                 if (parent == p) {
1991                     return true;
1992                 }
1993                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1994                     return false;
1995                 }
1996                 parent = parent.parentNode;
1997             }
1998             return false;
1999         }
2000     },
2001
2002     getRegion : function(el) {
2003         return Roo.lib.Region.getRegion(el);
2004     },
2005
2006     getY : function(el) {
2007         return this.getXY(el)[1];
2008     },
2009
2010     getX : function(el) {
2011         return this.getXY(el)[0];
2012     },
2013
2014     getXY : function(el) {
2015         var p, pe, b, scroll, bd = document.body;
2016         el = Roo.getDom(el);
2017         var fly = Roo.lib.AnimBase.fly;
2018         if (el.getBoundingClientRect) {
2019             b = el.getBoundingClientRect();
2020             scroll = fly(document).getScroll();
2021             return [b.left + scroll.left, b.top + scroll.top];
2022         }
2023         var x = 0, y = 0;
2024
2025         p = el;
2026
2027         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2028
2029         while (p) {
2030
2031             x += p.offsetLeft;
2032             y += p.offsetTop;
2033
2034             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2035                 hasAbsolute = true;
2036             }
2037
2038             if (Roo.isGecko) {
2039                 pe = fly(p);
2040
2041                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2042                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2043
2044
2045                 x += bl;
2046                 y += bt;
2047
2048
2049                 if (p != el && pe.getStyle('overflow') != 'visible') {
2050                     x += bl;
2051                     y += bt;
2052                 }
2053             }
2054             p = p.offsetParent;
2055         }
2056
2057         if (Roo.isSafari && hasAbsolute) {
2058             x -= bd.offsetLeft;
2059             y -= bd.offsetTop;
2060         }
2061
2062         if (Roo.isGecko && !hasAbsolute) {
2063             var dbd = fly(bd);
2064             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2065             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2066         }
2067
2068         p = el.parentNode;
2069         while (p && p != bd) {
2070             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2071                 x -= p.scrollLeft;
2072                 y -= p.scrollTop;
2073             }
2074             p = p.parentNode;
2075         }
2076         return [x, y];
2077     },
2078  
2079   
2080
2081
2082     setXY : function(el, xy) {
2083         el = Roo.fly(el, '_setXY');
2084         el.position();
2085         var pts = el.translatePoints(xy);
2086         if (xy[0] !== false) {
2087             el.dom.style.left = pts.left + "px";
2088         }
2089         if (xy[1] !== false) {
2090             el.dom.style.top = pts.top + "px";
2091         }
2092     },
2093
2094     setX : function(el, x) {
2095         this.setXY(el, [x, false]);
2096     },
2097
2098     setY : function(el, y) {
2099         this.setXY(el, [false, y]);
2100     }
2101 };
2102 /*
2103  * Portions of this file are based on pieces of Yahoo User Interface Library
2104  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2105  * YUI licensed under the BSD License:
2106  * http://developer.yahoo.net/yui/license.txt
2107  * <script type="text/javascript">
2108  *
2109  */
2110
2111 Roo.lib.Event = function() {
2112     var loadComplete = false;
2113     var listeners = [];
2114     var unloadListeners = [];
2115     var retryCount = 0;
2116     var onAvailStack = [];
2117     var counter = 0;
2118     var lastError = null;
2119
2120     return {
2121         POLL_RETRYS: 200,
2122         POLL_INTERVAL: 20,
2123         EL: 0,
2124         TYPE: 1,
2125         FN: 2,
2126         WFN: 3,
2127         OBJ: 3,
2128         ADJ_SCOPE: 4,
2129         _interval: null,
2130
2131         startInterval: function() {
2132             if (!this._interval) {
2133                 var self = this;
2134                 var callback = function() {
2135                     self._tryPreloadAttach();
2136                 };
2137                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2138
2139             }
2140         },
2141
2142         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2143             onAvailStack.push({ id:         p_id,
2144                 fn:         p_fn,
2145                 obj:        p_obj,
2146                 override:   p_override,
2147                 checkReady: false    });
2148
2149             retryCount = this.POLL_RETRYS;
2150             this.startInterval();
2151         },
2152
2153
2154         addListener: function(el, eventName, fn) {
2155             el = Roo.getDom(el);
2156             if (!el || !fn) {
2157                 return false;
2158             }
2159
2160             if ("unload" == eventName) {
2161                 unloadListeners[unloadListeners.length] =
2162                 [el, eventName, fn];
2163                 return true;
2164             }
2165
2166             var wrappedFn = function(e) {
2167                 return fn(Roo.lib.Event.getEvent(e));
2168             };
2169
2170             var li = [el, eventName, fn, wrappedFn];
2171
2172             var index = listeners.length;
2173             listeners[index] = li;
2174
2175             this.doAdd(el, eventName, wrappedFn, false);
2176             return true;
2177
2178         },
2179
2180
2181         removeListener: function(el, eventName, fn) {
2182             var i, len;
2183
2184             el = Roo.getDom(el);
2185
2186             if(!fn) {
2187                 return this.purgeElement(el, false, eventName);
2188             }
2189
2190
2191             if ("unload" == eventName) {
2192
2193                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2194                     var li = unloadListeners[i];
2195                     if (li &&
2196                         li[0] == el &&
2197                         li[1] == eventName &&
2198                         li[2] == fn) {
2199                         unloadListeners.splice(i, 1);
2200                         return true;
2201                     }
2202                 }
2203
2204                 return false;
2205             }
2206
2207             var cacheItem = null;
2208
2209
2210             var index = arguments[3];
2211
2212             if ("undefined" == typeof index) {
2213                 index = this._getCacheIndex(el, eventName, fn);
2214             }
2215
2216             if (index >= 0) {
2217                 cacheItem = listeners[index];
2218             }
2219
2220             if (!el || !cacheItem) {
2221                 return false;
2222             }
2223
2224             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2225
2226             delete listeners[index][this.WFN];
2227             delete listeners[index][this.FN];
2228             listeners.splice(index, 1);
2229
2230             return true;
2231
2232         },
2233
2234
2235         getTarget: function(ev, resolveTextNode) {
2236             ev = ev.browserEvent || ev;
2237             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2238             var t = ev.target || ev.srcElement;
2239             return this.resolveTextNode(t);
2240         },
2241
2242
2243         resolveTextNode: function(node) {
2244             if (Roo.isSafari && node && 3 == node.nodeType) {
2245                 return node.parentNode;
2246             } else {
2247                 return node;
2248             }
2249         },
2250
2251
2252         getPageX: function(ev) {
2253             ev = ev.browserEvent || ev;
2254             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2255             var x = ev.pageX;
2256             if (!x && 0 !== x) {
2257                 x = ev.clientX || 0;
2258
2259                 if (Roo.isIE) {
2260                     x += this.getScroll()[1];
2261                 }
2262             }
2263
2264             return x;
2265         },
2266
2267
2268         getPageY: function(ev) {
2269             ev = ev.browserEvent || ev;
2270             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2271             var y = ev.pageY;
2272             if (!y && 0 !== y) {
2273                 y = ev.clientY || 0;
2274
2275                 if (Roo.isIE) {
2276                     y += this.getScroll()[0];
2277                 }
2278             }
2279
2280
2281             return y;
2282         },
2283
2284
2285         getXY: function(ev) {
2286             ev = ev.browserEvent || ev;
2287             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2288             return [this.getPageX(ev), this.getPageY(ev)];
2289         },
2290
2291
2292         getRelatedTarget: function(ev) {
2293             ev = ev.browserEvent || ev;
2294             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2295             var t = ev.relatedTarget;
2296             if (!t) {
2297                 if (ev.type == "mouseout") {
2298                     t = ev.toElement;
2299                 } else if (ev.type == "mouseover") {
2300                     t = ev.fromElement;
2301                 }
2302             }
2303
2304             return this.resolveTextNode(t);
2305         },
2306
2307
2308         getTime: function(ev) {
2309             ev = ev.browserEvent || ev;
2310             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2311             if (!ev.time) {
2312                 var t = new Date().getTime();
2313                 try {
2314                     ev.time = t;
2315                 } catch(ex) {
2316                     this.lastError = ex;
2317                     return t;
2318                 }
2319             }
2320
2321             return ev.time;
2322         },
2323
2324
2325         stopEvent: function(ev) {
2326             this.stopPropagation(ev);
2327             this.preventDefault(ev);
2328         },
2329
2330
2331         stopPropagation: function(ev) {
2332             ev = ev.browserEvent || ev;
2333             if (ev.stopPropagation) {
2334                 ev.stopPropagation();
2335             } else {
2336                 ev.cancelBubble = true;
2337             }
2338         },
2339
2340
2341         preventDefault: function(ev) {
2342             ev = ev.browserEvent || ev;
2343             if(ev.preventDefault) {
2344                 ev.preventDefault();
2345             } else {
2346                 ev.returnValue = false;
2347             }
2348         },
2349
2350
2351         getEvent: function(e) {
2352             var ev = e || window.event;
2353             if (!ev) {
2354                 var c = this.getEvent.caller;
2355                 while (c) {
2356                     ev = c.arguments[0];
2357                     if (ev && Event == ev.constructor) {
2358                         break;
2359                     }
2360                     c = c.caller;
2361                 }
2362             }
2363             return ev;
2364         },
2365
2366
2367         getCharCode: function(ev) {
2368             ev = ev.browserEvent || ev;
2369             return ev.charCode || ev.keyCode || 0;
2370         },
2371
2372
2373         _getCacheIndex: function(el, eventName, fn) {
2374             for (var i = 0,len = listeners.length; i < len; ++i) {
2375                 var li = listeners[i];
2376                 if (li &&
2377                     li[this.FN] == fn &&
2378                     li[this.EL] == el &&
2379                     li[this.TYPE] == eventName) {
2380                     return i;
2381                 }
2382             }
2383
2384             return -1;
2385         },
2386
2387
2388         elCache: {},
2389
2390
2391         getEl: function(id) {
2392             return document.getElementById(id);
2393         },
2394
2395
2396         clearCache: function() {
2397         },
2398
2399
2400         _load: function(e) {
2401             loadComplete = true;
2402             var EU = Roo.lib.Event;
2403
2404
2405             if (Roo.isIE) {
2406                 EU.doRemove(window, "load", EU._load);
2407             }
2408         },
2409
2410
2411         _tryPreloadAttach: function() {
2412
2413             if (this.locked) {
2414                 return false;
2415             }
2416
2417             this.locked = true;
2418
2419
2420             var tryAgain = !loadComplete;
2421             if (!tryAgain) {
2422                 tryAgain = (retryCount > 0);
2423             }
2424
2425
2426             var notAvail = [];
2427             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2428                 var item = onAvailStack[i];
2429                 if (item) {
2430                     var el = this.getEl(item.id);
2431
2432                     if (el) {
2433                         if (!item.checkReady ||
2434                             loadComplete ||
2435                             el.nextSibling ||
2436                             (document && document.body)) {
2437
2438                             var scope = el;
2439                             if (item.override) {
2440                                 if (item.override === true) {
2441                                     scope = item.obj;
2442                                 } else {
2443                                     scope = item.override;
2444                                 }
2445                             }
2446                             item.fn.call(scope, item.obj);
2447                             onAvailStack[i] = null;
2448                         }
2449                     } else {
2450                         notAvail.push(item);
2451                     }
2452                 }
2453             }
2454
2455             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2456
2457             if (tryAgain) {
2458
2459                 this.startInterval();
2460             } else {
2461                 clearInterval(this._interval);
2462                 this._interval = null;
2463             }
2464
2465             this.locked = false;
2466
2467             return true;
2468
2469         },
2470
2471
2472         purgeElement: function(el, recurse, eventName) {
2473             var elListeners = this.getListeners(el, eventName);
2474             if (elListeners) {
2475                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2476                     var l = elListeners[i];
2477                     this.removeListener(el, l.type, l.fn);
2478                 }
2479             }
2480
2481             if (recurse && el && el.childNodes) {
2482                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2483                     this.purgeElement(el.childNodes[i], recurse, eventName);
2484                 }
2485             }
2486         },
2487
2488
2489         getListeners: function(el, eventName) {
2490             var results = [], searchLists;
2491             if (!eventName) {
2492                 searchLists = [listeners, unloadListeners];
2493             } else if (eventName == "unload") {
2494                 searchLists = [unloadListeners];
2495             } else {
2496                 searchLists = [listeners];
2497             }
2498
2499             for (var j = 0; j < searchLists.length; ++j) {
2500                 var searchList = searchLists[j];
2501                 if (searchList && searchList.length > 0) {
2502                     for (var i = 0,len = searchList.length; i < len; ++i) {
2503                         var l = searchList[i];
2504                         if (l && l[this.EL] === el &&
2505                             (!eventName || eventName === l[this.TYPE])) {
2506                             results.push({
2507                                 type:   l[this.TYPE],
2508                                 fn:     l[this.FN],
2509                                 obj:    l[this.OBJ],
2510                                 adjust: l[this.ADJ_SCOPE],
2511                                 index:  i
2512                             });
2513                         }
2514                     }
2515                 }
2516             }
2517
2518             return (results.length) ? results : null;
2519         },
2520
2521
2522         _unload: function(e) {
2523
2524             var EU = Roo.lib.Event, i, j, l, len, index;
2525
2526             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2527                 l = unloadListeners[i];
2528                 if (l) {
2529                     var scope = window;
2530                     if (l[EU.ADJ_SCOPE]) {
2531                         if (l[EU.ADJ_SCOPE] === true) {
2532                             scope = l[EU.OBJ];
2533                         } else {
2534                             scope = l[EU.ADJ_SCOPE];
2535                         }
2536                     }
2537                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2538                     unloadListeners[i] = null;
2539                     l = null;
2540                     scope = null;
2541                 }
2542             }
2543
2544             unloadListeners = null;
2545
2546             if (listeners && listeners.length > 0) {
2547                 j = listeners.length;
2548                 while (j) {
2549                     index = j - 1;
2550                     l = listeners[index];
2551                     if (l) {
2552                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2553                                 l[EU.FN], index);
2554                     }
2555                     j = j - 1;
2556                 }
2557                 l = null;
2558
2559                 EU.clearCache();
2560             }
2561
2562             EU.doRemove(window, "unload", EU._unload);
2563
2564         },
2565
2566
2567         getScroll: function() {
2568             var dd = document.documentElement, db = document.body;
2569             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2570                 return [dd.scrollTop, dd.scrollLeft];
2571             } else if (db) {
2572                 return [db.scrollTop, db.scrollLeft];
2573             } else {
2574                 return [0, 0];
2575             }
2576         },
2577
2578
2579         doAdd: function () {
2580             if (window.addEventListener) {
2581                 return function(el, eventName, fn, capture) {
2582                     el.addEventListener(eventName, fn, (capture));
2583                 };
2584             } else if (window.attachEvent) {
2585                 return function(el, eventName, fn, capture) {
2586                     el.attachEvent("on" + eventName, fn);
2587                 };
2588             } else {
2589                 return function() {
2590                 };
2591             }
2592         }(),
2593
2594
2595         doRemove: function() {
2596             if (window.removeEventListener) {
2597                 return function (el, eventName, fn, capture) {
2598                     el.removeEventListener(eventName, fn, (capture));
2599                 };
2600             } else if (window.detachEvent) {
2601                 return function (el, eventName, fn) {
2602                     el.detachEvent("on" + eventName, fn);
2603                 };
2604             } else {
2605                 return function() {
2606                 };
2607             }
2608         }()
2609     };
2610     
2611 }();
2612 (function() {     
2613    
2614     var E = Roo.lib.Event;
2615     E.on = E.addListener;
2616     E.un = E.removeListener;
2617
2618     if (document && document.body) {
2619         E._load();
2620     } else {
2621         E.doAdd(window, "load", E._load);
2622     }
2623     E.doAdd(window, "unload", E._unload);
2624     E._tryPreloadAttach();
2625 })();
2626
2627  
2628
2629 (function() {
2630     /**
2631      * @class Roo.lib.Ajax
2632      *
2633      * provide a simple Ajax request utility functions
2634      * 
2635      * Portions of this file are based on pieces of Yahoo User Interface Library
2636     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2637     * YUI licensed under the BSD License:
2638     * http://developer.yahoo.net/yui/license.txt
2639     * <script type="text/javascript">
2640     *
2641      *
2642      */
2643     Roo.lib.Ajax = {
2644         /**
2645          * @static 
2646          */
2647         request : function(method, uri, cb, data, options) {
2648             if(options){
2649                 var hs = options.headers;
2650                 if(hs){
2651                     for(var h in hs){
2652                         if(hs.hasOwnProperty(h)){
2653                             this.initHeader(h, hs[h], false);
2654                         }
2655                     }
2656                 }
2657                 if(options.xmlData){
2658                     this.initHeader('Content-Type', 'text/xml', false);
2659                     method = 'POST';
2660                     data = options.xmlData;
2661                 }
2662             }
2663
2664             return this.asyncRequest(method, uri, cb, data);
2665         },
2666         /**
2667          * serialize a form
2668          *
2669          * @static
2670          * @param {DomForm} form element
2671          * @return {String} urlencode form output.
2672          */
2673         serializeForm : function(form) {
2674             if(typeof form == 'string') {
2675                 form = (document.getElementById(form) || document.forms[form]);
2676             }
2677
2678             var el, name, val, disabled, data = '', hasSubmit = false;
2679             for (var i = 0; i < form.elements.length; i++) {
2680                 el = form.elements[i];
2681                 disabled = form.elements[i].disabled;
2682                 name = form.elements[i].name;
2683                 val = form.elements[i].value;
2684
2685                 if (!disabled && name){
2686                     switch (el.type)
2687                             {
2688                         case 'select-one':
2689                         case 'select-multiple':
2690                             for (var j = 0; j < el.options.length; j++) {
2691                                 if (el.options[j].selected) {
2692                                     if (Roo.isIE) {
2693                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2694                                     }
2695                                     else {
2696                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2697                                     }
2698                                 }
2699                             }
2700                             break;
2701                         case 'radio':
2702                         case 'checkbox':
2703                             if (el.checked) {
2704                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2705                             }
2706                             break;
2707                         case 'file':
2708
2709                         case undefined:
2710
2711                         case 'reset':
2712
2713                         case 'button':
2714
2715                             break;
2716                         case 'submit':
2717                             if(hasSubmit == false) {
2718                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2719                                 hasSubmit = true;
2720                             }
2721                             break;
2722                         default:
2723                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2724                             break;
2725                     }
2726                 }
2727             }
2728             data = data.substr(0, data.length - 1);
2729             return data;
2730         },
2731
2732         headers:{},
2733
2734         hasHeaders:false,
2735
2736         useDefaultHeader:true,
2737
2738         defaultPostHeader:'application/x-www-form-urlencoded',
2739
2740         useDefaultXhrHeader:true,
2741
2742         defaultXhrHeader:'XMLHttpRequest',
2743
2744         hasDefaultHeaders:true,
2745
2746         defaultHeaders:{},
2747
2748         poll:{},
2749
2750         timeout:{},
2751
2752         pollInterval:50,
2753
2754         transactionId:0,
2755
2756         setProgId:function(id)
2757         {
2758             this.activeX.unshift(id);
2759         },
2760
2761         setDefaultPostHeader:function(b)
2762         {
2763             this.useDefaultHeader = b;
2764         },
2765
2766         setDefaultXhrHeader:function(b)
2767         {
2768             this.useDefaultXhrHeader = b;
2769         },
2770
2771         setPollingInterval:function(i)
2772         {
2773             if (typeof i == 'number' && isFinite(i)) {
2774                 this.pollInterval = i;
2775             }
2776         },
2777
2778         createXhrObject:function(transactionId)
2779         {
2780             var obj,http;
2781             try
2782             {
2783
2784                 http = new XMLHttpRequest();
2785
2786                 obj = { conn:http, tId:transactionId };
2787             }
2788             catch(e)
2789             {
2790                 for (var i = 0; i < this.activeX.length; ++i) {
2791                     try
2792                     {
2793
2794                         http = new ActiveXObject(this.activeX[i]);
2795
2796                         obj = { conn:http, tId:transactionId };
2797                         break;
2798                     }
2799                     catch(e) {
2800                     }
2801                 }
2802             }
2803             finally
2804             {
2805                 return obj;
2806             }
2807         },
2808
2809         getConnectionObject:function()
2810         {
2811             var o;
2812             var tId = this.transactionId;
2813
2814             try
2815             {
2816                 o = this.createXhrObject(tId);
2817                 if (o) {
2818                     this.transactionId++;
2819                 }
2820             }
2821             catch(e) {
2822             }
2823             finally
2824             {
2825                 return o;
2826             }
2827         },
2828
2829         asyncRequest:function(method, uri, callback, postData)
2830         {
2831             var o = this.getConnectionObject();
2832
2833             if (!o) {
2834                 return null;
2835             }
2836             else {
2837                 o.conn.open(method, uri, true);
2838
2839                 if (this.useDefaultXhrHeader) {
2840                     if (!this.defaultHeaders['X-Requested-With']) {
2841                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2842                     }
2843                 }
2844
2845                 if(postData && this.useDefaultHeader){
2846                     this.initHeader('Content-Type', this.defaultPostHeader);
2847                 }
2848
2849                  if (this.hasDefaultHeaders || this.hasHeaders) {
2850                     this.setHeader(o);
2851                 }
2852
2853                 this.handleReadyState(o, callback);
2854                 o.conn.send(postData || null);
2855
2856                 return o;
2857             }
2858         },
2859
2860         handleReadyState:function(o, callback)
2861         {
2862             var oConn = this;
2863
2864             if (callback && callback.timeout) {
2865                 
2866                 this.timeout[o.tId] = window.setTimeout(function() {
2867                     oConn.abort(o, callback, true);
2868                 }, callback.timeout);
2869             }
2870
2871             this.poll[o.tId] = window.setInterval(
2872                     function() {
2873                         if (o.conn && o.conn.readyState == 4) {
2874                             window.clearInterval(oConn.poll[o.tId]);
2875                             delete oConn.poll[o.tId];
2876
2877                             if(callback && callback.timeout) {
2878                                 window.clearTimeout(oConn.timeout[o.tId]);
2879                                 delete oConn.timeout[o.tId];
2880                             }
2881
2882                             oConn.handleTransactionResponse(o, callback);
2883                         }
2884                     }
2885                     , this.pollInterval);
2886         },
2887
2888         handleTransactionResponse:function(o, callback, isAbort)
2889         {
2890
2891             if (!callback) {
2892                 this.releaseObject(o);
2893                 return;
2894             }
2895
2896             var httpStatus, responseObject;
2897
2898             try
2899             {
2900                 if (o.conn.status !== undefined && o.conn.status != 0) {
2901                     httpStatus = o.conn.status;
2902                 }
2903                 else {
2904                     httpStatus = 13030;
2905                 }
2906             }
2907             catch(e) {
2908
2909
2910                 httpStatus = 13030;
2911             }
2912
2913             if (httpStatus >= 200 && httpStatus < 300) {
2914                 responseObject = this.createResponseObject(o, callback.argument);
2915                 if (callback.success) {
2916                     if (!callback.scope) {
2917                         callback.success(responseObject);
2918                     }
2919                     else {
2920
2921
2922                         callback.success.apply(callback.scope, [responseObject]);
2923                     }
2924                 }
2925             }
2926             else {
2927                 switch (httpStatus) {
2928
2929                     case 12002:
2930                     case 12029:
2931                     case 12030:
2932                     case 12031:
2933                     case 12152:
2934                     case 13030:
2935                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2936                         if (callback.failure) {
2937                             if (!callback.scope) {
2938                                 callback.failure(responseObject);
2939                             }
2940                             else {
2941                                 callback.failure.apply(callback.scope, [responseObject]);
2942                             }
2943                         }
2944                         break;
2945                     default:
2946                         responseObject = this.createResponseObject(o, callback.argument);
2947                         if (callback.failure) {
2948                             if (!callback.scope) {
2949                                 callback.failure(responseObject);
2950                             }
2951                             else {
2952                                 callback.failure.apply(callback.scope, [responseObject]);
2953                             }
2954                         }
2955                 }
2956             }
2957
2958             this.releaseObject(o);
2959             responseObject = null;
2960         },
2961
2962         createResponseObject:function(o, callbackArg)
2963         {
2964             var obj = {};
2965             var headerObj = {};
2966
2967             try
2968             {
2969                 var headerStr = o.conn.getAllResponseHeaders();
2970                 var header = headerStr.split('\n');
2971                 for (var i = 0; i < header.length; i++) {
2972                     var delimitPos = header[i].indexOf(':');
2973                     if (delimitPos != -1) {
2974                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2975                     }
2976                 }
2977             }
2978             catch(e) {
2979             }
2980
2981             obj.tId = o.tId;
2982             obj.status = o.conn.status;
2983             obj.statusText = o.conn.statusText;
2984             obj.getResponseHeader = headerObj;
2985             obj.getAllResponseHeaders = headerStr;
2986             obj.responseText = o.conn.responseText;
2987             obj.responseXML = o.conn.responseXML;
2988
2989             if (typeof callbackArg !== undefined) {
2990                 obj.argument = callbackArg;
2991             }
2992
2993             return obj;
2994         },
2995
2996         createExceptionObject:function(tId, callbackArg, isAbort)
2997         {
2998             var COMM_CODE = 0;
2999             var COMM_ERROR = 'communication failure';
3000             var ABORT_CODE = -1;
3001             var ABORT_ERROR = 'transaction aborted';
3002
3003             var obj = {};
3004
3005             obj.tId = tId;
3006             if (isAbort) {
3007                 obj.status = ABORT_CODE;
3008                 obj.statusText = ABORT_ERROR;
3009             }
3010             else {
3011                 obj.status = COMM_CODE;
3012                 obj.statusText = COMM_ERROR;
3013             }
3014
3015             if (callbackArg) {
3016                 obj.argument = callbackArg;
3017             }
3018
3019             return obj;
3020         },
3021
3022         initHeader:function(label, value, isDefault)
3023         {
3024             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3025
3026             if (headerObj[label] === undefined) {
3027                 headerObj[label] = value;
3028             }
3029             else {
3030
3031
3032                 headerObj[label] = value + "," + headerObj[label];
3033             }
3034
3035             if (isDefault) {
3036                 this.hasDefaultHeaders = true;
3037             }
3038             else {
3039                 this.hasHeaders = true;
3040             }
3041         },
3042
3043
3044         setHeader:function(o)
3045         {
3046             if (this.hasDefaultHeaders) {
3047                 for (var prop in this.defaultHeaders) {
3048                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3049                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3050                     }
3051                 }
3052             }
3053
3054             if (this.hasHeaders) {
3055                 for (var prop in this.headers) {
3056                     if (this.headers.hasOwnProperty(prop)) {
3057                         o.conn.setRequestHeader(prop, this.headers[prop]);
3058                     }
3059                 }
3060                 this.headers = {};
3061                 this.hasHeaders = false;
3062             }
3063         },
3064
3065         resetDefaultHeaders:function() {
3066             delete this.defaultHeaders;
3067             this.defaultHeaders = {};
3068             this.hasDefaultHeaders = false;
3069         },
3070
3071         abort:function(o, callback, isTimeout)
3072         {
3073             if(this.isCallInProgress(o)) {
3074                 o.conn.abort();
3075                 window.clearInterval(this.poll[o.tId]);
3076                 delete this.poll[o.tId];
3077                 if (isTimeout) {
3078                     delete this.timeout[o.tId];
3079                 }
3080
3081                 this.handleTransactionResponse(o, callback, true);
3082
3083                 return true;
3084             }
3085             else {
3086                 return false;
3087             }
3088         },
3089
3090
3091         isCallInProgress:function(o)
3092         {
3093             if (o && o.conn) {
3094                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3095             }
3096             else {
3097
3098                 return false;
3099             }
3100         },
3101
3102
3103         releaseObject:function(o)
3104         {
3105
3106             o.conn = null;
3107
3108             o = null;
3109         },
3110
3111         activeX:[
3112         'MSXML2.XMLHTTP.3.0',
3113         'MSXML2.XMLHTTP',
3114         'Microsoft.XMLHTTP'
3115         ]
3116
3117
3118     };
3119 })();/*
3120  * Portions of this file are based on pieces of Yahoo User Interface Library
3121  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3122  * YUI licensed under the BSD License:
3123  * http://developer.yahoo.net/yui/license.txt
3124  * <script type="text/javascript">
3125  *
3126  */
3127
3128 Roo.lib.Region = function(t, r, b, l) {
3129     this.top = t;
3130     this[1] = t;
3131     this.right = r;
3132     this.bottom = b;
3133     this.left = l;
3134     this[0] = l;
3135 };
3136
3137
3138 Roo.lib.Region.prototype = {
3139     contains : function(region) {
3140         return ( region.left >= this.left &&
3141                  region.right <= this.right &&
3142                  region.top >= this.top &&
3143                  region.bottom <= this.bottom    );
3144
3145     },
3146
3147     getArea : function() {
3148         return ( (this.bottom - this.top) * (this.right - this.left) );
3149     },
3150
3151     intersect : function(region) {
3152         var t = Math.max(this.top, region.top);
3153         var r = Math.min(this.right, region.right);
3154         var b = Math.min(this.bottom, region.bottom);
3155         var l = Math.max(this.left, region.left);
3156
3157         if (b >= t && r >= l) {
3158             return new Roo.lib.Region(t, r, b, l);
3159         } else {
3160             return null;
3161         }
3162     },
3163     union : function(region) {
3164         var t = Math.min(this.top, region.top);
3165         var r = Math.max(this.right, region.right);
3166         var b = Math.max(this.bottom, region.bottom);
3167         var l = Math.min(this.left, region.left);
3168
3169         return new Roo.lib.Region(t, r, b, l);
3170     },
3171
3172     adjust : function(t, l, b, r) {
3173         this.top += t;
3174         this.left += l;
3175         this.right += r;
3176         this.bottom += b;
3177         return this;
3178     }
3179 };
3180
3181 Roo.lib.Region.getRegion = function(el) {
3182     var p = Roo.lib.Dom.getXY(el);
3183
3184     var t = p[1];
3185     var r = p[0] + el.offsetWidth;
3186     var b = p[1] + el.offsetHeight;
3187     var l = p[0];
3188
3189     return new Roo.lib.Region(t, r, b, l);
3190 };
3191 /*
3192  * Portions of this file are based on pieces of Yahoo User Interface Library
3193  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3194  * YUI licensed under the BSD License:
3195  * http://developer.yahoo.net/yui/license.txt
3196  * <script type="text/javascript">
3197  *
3198  */
3199 //@@dep Roo.lib.Region
3200
3201
3202 Roo.lib.Point = function(x, y) {
3203     if (x instanceof Array) {
3204         y = x[1];
3205         x = x[0];
3206     }
3207     this.x = this.right = this.left = this[0] = x;
3208     this.y = this.top = this.bottom = this[1] = y;
3209 };
3210
3211 Roo.lib.Point.prototype = new Roo.lib.Region();
3212 /*
3213  * Portions of this file are based on pieces of Yahoo User Interface Library
3214  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3215  * YUI licensed under the BSD License:
3216  * http://developer.yahoo.net/yui/license.txt
3217  * <script type="text/javascript">
3218  *
3219  */
3220  
3221 (function() {   
3222
3223     Roo.lib.Anim = {
3224         scroll : function(el, args, duration, easing, cb, scope) {
3225             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3226         },
3227
3228         motion : function(el, args, duration, easing, cb, scope) {
3229             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3230         },
3231
3232         color : function(el, args, duration, easing, cb, scope) {
3233             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3234         },
3235
3236         run : function(el, args, duration, easing, cb, scope, type) {
3237             type = type || Roo.lib.AnimBase;
3238             if (typeof easing == "string") {
3239                 easing = Roo.lib.Easing[easing];
3240             }
3241             var anim = new type(el, args, duration, easing);
3242             anim.animateX(function() {
3243                 Roo.callback(cb, scope);
3244             });
3245             return anim;
3246         }
3247     };
3248 })();/*
3249  * Portions of this file are based on pieces of Yahoo User Interface Library
3250  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3251  * YUI licensed under the BSD License:
3252  * http://developer.yahoo.net/yui/license.txt
3253  * <script type="text/javascript">
3254  *
3255  */
3256
3257 (function() {    
3258     var libFlyweight;
3259     
3260     function fly(el) {
3261         if (!libFlyweight) {
3262             libFlyweight = new Roo.Element.Flyweight();
3263         }
3264         libFlyweight.dom = el;
3265         return libFlyweight;
3266     }
3267
3268     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3269     
3270    
3271     
3272     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3273         if (el) {
3274             this.init(el, attributes, duration, method);
3275         }
3276     };
3277
3278     Roo.lib.AnimBase.fly = fly;
3279     
3280     
3281     
3282     Roo.lib.AnimBase.prototype = {
3283
3284         toString: function() {
3285             var el = this.getEl();
3286             var id = el.id || el.tagName;
3287             return ("Anim " + id);
3288         },
3289
3290         patterns: {
3291             noNegatives:        /width|height|opacity|padding/i,
3292             offsetAttribute:  /^((width|height)|(top|left))$/,
3293             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3294             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3295         },
3296
3297
3298         doMethod: function(attr, start, end) {
3299             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3300         },
3301
3302
3303         setAttribute: function(attr, val, unit) {
3304             if (this.patterns.noNegatives.test(attr)) {
3305                 val = (val > 0) ? val : 0;
3306             }
3307
3308             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3309         },
3310
3311
3312         getAttribute: function(attr) {
3313             var el = this.getEl();
3314             var val = fly(el).getStyle(attr);
3315
3316             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3317                 return parseFloat(val);
3318             }
3319
3320             var a = this.patterns.offsetAttribute.exec(attr) || [];
3321             var pos = !!( a[3] );
3322             var box = !!( a[2] );
3323
3324
3325             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3326                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3327             } else {
3328                 val = 0;
3329             }
3330
3331             return val;
3332         },
3333
3334
3335         getDefaultUnit: function(attr) {
3336             if (this.patterns.defaultUnit.test(attr)) {
3337                 return 'px';
3338             }
3339
3340             return '';
3341         },
3342
3343         animateX : function(callback, scope) {
3344             var f = function() {
3345                 this.onComplete.removeListener(f);
3346                 if (typeof callback == "function") {
3347                     callback.call(scope || this, this);
3348                 }
3349             };
3350             this.onComplete.addListener(f, this);
3351             this.animate();
3352         },
3353
3354
3355         setRuntimeAttribute: function(attr) {
3356             var start;
3357             var end;
3358             var attributes = this.attributes;
3359
3360             this.runtimeAttributes[attr] = {};
3361
3362             var isset = function(prop) {
3363                 return (typeof prop !== 'undefined');
3364             };
3365
3366             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3367                 return false;
3368             }
3369
3370             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3371
3372
3373             if (isset(attributes[attr]['to'])) {
3374                 end = attributes[attr]['to'];
3375             } else if (isset(attributes[attr]['by'])) {
3376                 if (start.constructor == Array) {
3377                     end = [];
3378                     for (var i = 0, len = start.length; i < len; ++i) {
3379                         end[i] = start[i] + attributes[attr]['by'][i];
3380                     }
3381                 } else {
3382                     end = start + attributes[attr]['by'];
3383                 }
3384             }
3385
3386             this.runtimeAttributes[attr].start = start;
3387             this.runtimeAttributes[attr].end = end;
3388
3389
3390             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3391         },
3392
3393
3394         init: function(el, attributes, duration, method) {
3395
3396             var isAnimated = false;
3397
3398
3399             var startTime = null;
3400
3401
3402             var actualFrames = 0;
3403
3404
3405             el = Roo.getDom(el);
3406
3407
3408             this.attributes = attributes || {};
3409
3410
3411             this.duration = duration || 1;
3412
3413
3414             this.method = method || Roo.lib.Easing.easeNone;
3415
3416
3417             this.useSeconds = true;
3418
3419
3420             this.currentFrame = 0;
3421
3422
3423             this.totalFrames = Roo.lib.AnimMgr.fps;
3424
3425
3426             this.getEl = function() {
3427                 return el;
3428             };
3429
3430
3431             this.isAnimated = function() {
3432                 return isAnimated;
3433             };
3434
3435
3436             this.getStartTime = function() {
3437                 return startTime;
3438             };
3439
3440             this.runtimeAttributes = {};
3441
3442
3443             this.animate = function() {
3444                 if (this.isAnimated()) {
3445                     return false;
3446                 }
3447
3448                 this.currentFrame = 0;
3449
3450                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3451
3452                 Roo.lib.AnimMgr.registerElement(this);
3453             };
3454
3455
3456             this.stop = function(finish) {
3457                 if (finish) {
3458                     this.currentFrame = this.totalFrames;
3459                     this._onTween.fire();
3460                 }
3461                 Roo.lib.AnimMgr.stop(this);
3462             };
3463
3464             var onStart = function() {
3465                 this.onStart.fire();
3466
3467                 this.runtimeAttributes = {};
3468                 for (var attr in this.attributes) {
3469                     this.setRuntimeAttribute(attr);
3470                 }
3471
3472                 isAnimated = true;
3473                 actualFrames = 0;
3474                 startTime = new Date();
3475             };
3476
3477
3478             var onTween = function() {
3479                 var data = {
3480                     duration: new Date() - this.getStartTime(),
3481                     currentFrame: this.currentFrame
3482                 };
3483
3484                 data.toString = function() {
3485                     return (
3486                             'duration: ' + data.duration +
3487                             ', currentFrame: ' + data.currentFrame
3488                             );
3489                 };
3490
3491                 this.onTween.fire(data);
3492
3493                 var runtimeAttributes = this.runtimeAttributes;
3494
3495                 for (var attr in runtimeAttributes) {
3496                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3497                 }
3498
3499                 actualFrames += 1;
3500             };
3501
3502             var onComplete = function() {
3503                 var actual_duration = (new Date() - startTime) / 1000 ;
3504
3505                 var data = {
3506                     duration: actual_duration,
3507                     frames: actualFrames,
3508                     fps: actualFrames / actual_duration
3509                 };
3510
3511                 data.toString = function() {
3512                     return (
3513                             'duration: ' + data.duration +
3514                             ', frames: ' + data.frames +
3515                             ', fps: ' + data.fps
3516                             );
3517                 };
3518
3519                 isAnimated = false;
3520                 actualFrames = 0;
3521                 this.onComplete.fire(data);
3522             };
3523
3524
3525             this._onStart = new Roo.util.Event(this);
3526             this.onStart = new Roo.util.Event(this);
3527             this.onTween = new Roo.util.Event(this);
3528             this._onTween = new Roo.util.Event(this);
3529             this.onComplete = new Roo.util.Event(this);
3530             this._onComplete = new Roo.util.Event(this);
3531             this._onStart.addListener(onStart);
3532             this._onTween.addListener(onTween);
3533             this._onComplete.addListener(onComplete);
3534         }
3535     };
3536 })();
3537 /*
3538  * Portions of this file are based on pieces of Yahoo User Interface Library
3539  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3540  * YUI licensed under the BSD License:
3541  * http://developer.yahoo.net/yui/license.txt
3542  * <script type="text/javascript">
3543  *
3544  */
3545
3546 Roo.lib.AnimMgr = new function() {
3547
3548     var thread = null;
3549
3550
3551     var queue = [];
3552
3553
3554     var tweenCount = 0;
3555
3556
3557     this.fps = 1000;
3558
3559
3560     this.delay = 1;
3561
3562
3563     this.registerElement = function(tween) {
3564         queue[queue.length] = tween;
3565         tweenCount += 1;
3566         tween._onStart.fire();
3567         this.start();
3568     };
3569
3570
3571     this.unRegister = function(tween, index) {
3572         tween._onComplete.fire();
3573         index = index || getIndex(tween);
3574         if (index != -1) {
3575             queue.splice(index, 1);
3576         }
3577
3578         tweenCount -= 1;
3579         if (tweenCount <= 0) {
3580             this.stop();
3581         }
3582     };
3583
3584
3585     this.start = function() {
3586         if (thread === null) {
3587             thread = setInterval(this.run, this.delay);
3588         }
3589     };
3590
3591
3592     this.stop = function(tween) {
3593         if (!tween) {
3594             clearInterval(thread);
3595
3596             for (var i = 0, len = queue.length; i < len; ++i) {
3597                 if (queue[0].isAnimated()) {
3598                     this.unRegister(queue[0], 0);
3599                 }
3600             }
3601
3602             queue = [];
3603             thread = null;
3604             tweenCount = 0;
3605         }
3606         else {
3607             this.unRegister(tween);
3608         }
3609     };
3610
3611
3612     this.run = function() {
3613         for (var i = 0, len = queue.length; i < len; ++i) {
3614             var tween = queue[i];
3615             if (!tween || !tween.isAnimated()) {
3616                 continue;
3617             }
3618
3619             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3620             {
3621                 tween.currentFrame += 1;
3622
3623                 if (tween.useSeconds) {
3624                     correctFrame(tween);
3625                 }
3626                 tween._onTween.fire();
3627             }
3628             else {
3629                 Roo.lib.AnimMgr.stop(tween, i);
3630             }
3631         }
3632     };
3633
3634     var getIndex = function(anim) {
3635         for (var i = 0, len = queue.length; i < len; ++i) {
3636             if (queue[i] == anim) {
3637                 return i;
3638             }
3639         }
3640         return -1;
3641     };
3642
3643
3644     var correctFrame = function(tween) {
3645         var frames = tween.totalFrames;
3646         var frame = tween.currentFrame;
3647         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3648         var elapsed = (new Date() - tween.getStartTime());
3649         var tweak = 0;
3650
3651         if (elapsed < tween.duration * 1000) {
3652             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3653         } else {
3654             tweak = frames - (frame + 1);
3655         }
3656         if (tweak > 0 && isFinite(tweak)) {
3657             if (tween.currentFrame + tweak >= frames) {
3658                 tweak = frames - (frame + 1);
3659             }
3660
3661             tween.currentFrame += tweak;
3662         }
3663     };
3664 };
3665
3666     /*
3667  * Portions of this file are based on pieces of Yahoo User Interface Library
3668  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669  * YUI licensed under the BSD License:
3670  * http://developer.yahoo.net/yui/license.txt
3671  * <script type="text/javascript">
3672  *
3673  */
3674 Roo.lib.Bezier = new function() {
3675
3676         this.getPosition = function(points, t) {
3677             var n = points.length;
3678             var tmp = [];
3679
3680             for (var i = 0; i < n; ++i) {
3681                 tmp[i] = [points[i][0], points[i][1]];
3682             }
3683
3684             for (var j = 1; j < n; ++j) {
3685                 for (i = 0; i < n - j; ++i) {
3686                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3687                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3688                 }
3689             }
3690
3691             return [ tmp[0][0], tmp[0][1] ];
3692
3693         };
3694     }; 
3695
3696 /**
3697  * @class Roo.lib.Color
3698  * @constructor
3699  * An abstract Color implementation. Concrete Color implementations should use
3700  * an instance of this function as their prototype, and implement the getRGB and
3701  * getHSL functions. getRGB should return an object representing the RGB
3702  * components of this Color, with the red, green, and blue components in the
3703  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3704  * return an object representing the HSL components of this Color, with the hue
3705  * component in the range [0,360), the saturation and lightness components in
3706  * the range [0,100], and the alpha component in the range [0,1].
3707  *
3708  *
3709  * Color.js
3710  *
3711  * Functions for Color handling and processing.
3712  *
3713  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3714  *
3715  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3716  * rights to this program, with the intention of it becoming part of the public
3717  * domain. Because this program is released into the public domain, it comes with
3718  * no warranty either expressed or implied, to the extent permitted by law.
3719  * 
3720  * For more free and public domain JavaScript code by the same author, visit:
3721  * http://www.safalra.com/web-design/javascript/
3722  * 
3723  */
3724 Roo.lib.Color = function() { }
3725
3726
3727 Roo.apply(Roo.lib.Color.prototype, {
3728   
3729   rgb : null,
3730   hsv : null,
3731   hsl : null,
3732   
3733   /**
3734    * getIntegerRGB
3735    * @return {Object} an object representing the RGBA components of this Color. The red,
3736    * green, and blue components are converted to integers in the range [0,255].
3737    * The alpha is a value in the range [0,1].
3738    */
3739   getIntegerRGB : function(){
3740
3741     // get the RGB components of this Color
3742     var rgb = this.getRGB();
3743
3744     // return the integer components
3745     return {
3746       'r' : Math.round(rgb.r),
3747       'g' : Math.round(rgb.g),
3748       'b' : Math.round(rgb.b),
3749       'a' : rgb.a
3750     };
3751
3752   },
3753
3754   /**
3755    * getPercentageRGB
3756    * @return {Object} an object representing the RGBA components of this Color. The red,
3757    * green, and blue components are converted to numbers in the range [0,100].
3758    * The alpha is a value in the range [0,1].
3759    */
3760   getPercentageRGB : function(){
3761
3762     // get the RGB components of this Color
3763     var rgb = this.getRGB();
3764
3765     // return the percentage components
3766     return {
3767       'r' : 100 * rgb.r / 255,
3768       'g' : 100 * rgb.g / 255,
3769       'b' : 100 * rgb.b / 255,
3770       'a' : rgb.a
3771     };
3772
3773   },
3774
3775   /**
3776    * getCSSHexadecimalRGB
3777    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3778    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3779    * are two-digit hexadecimal numbers.
3780    */
3781   getCSSHexadecimalRGB : function()
3782   {
3783
3784     // get the integer RGB components
3785     var rgb = this.getIntegerRGB();
3786
3787     // determine the hexadecimal equivalents
3788     var r16 = rgb.r.toString(16);
3789     var g16 = rgb.g.toString(16);
3790     var b16 = rgb.b.toString(16);
3791
3792     // return the CSS RGB Color value
3793     return '#'
3794         + (r16.length == 2 ? r16 : '0' + r16)
3795         + (g16.length == 2 ? g16 : '0' + g16)
3796         + (b16.length == 2 ? b16 : '0' + b16);
3797
3798   },
3799
3800   /**
3801    * getCSSIntegerRGB
3802    * @return {String} a string representing this Color as a CSS integer RGB Color
3803    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3804    * are integers in the range [0,255].
3805    */
3806   getCSSIntegerRGB : function(){
3807
3808     // get the integer RGB components
3809     var rgb = this.getIntegerRGB();
3810
3811     // return the CSS RGB Color value
3812     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3813
3814   },
3815
3816   /**
3817    * getCSSIntegerRGBA
3818    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3819    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3820    * b are integers in the range [0,255] and a is in the range [0,1].
3821    */
3822   getCSSIntegerRGBA : function(){
3823
3824     // get the integer RGB components
3825     var rgb = this.getIntegerRGB();
3826
3827     // return the CSS integer RGBA Color value
3828     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3829
3830   },
3831
3832   /**
3833    * getCSSPercentageRGB
3834    * @return {String} a string representing this Color as a CSS percentage RGB Color
3835    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3836    * b are in the range [0,100].
3837    */
3838   getCSSPercentageRGB : function(){
3839
3840     // get the percentage RGB components
3841     var rgb = this.getPercentageRGB();
3842
3843     // return the CSS RGB Color value
3844     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3845
3846   },
3847
3848   /**
3849    * getCSSPercentageRGBA
3850    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3851    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3852    * and b are in the range [0,100] and a is in the range [0,1].
3853    */
3854   getCSSPercentageRGBA : function(){
3855
3856     // get the percentage RGB components
3857     var rgb = this.getPercentageRGB();
3858
3859     // return the CSS percentage RGBA Color value
3860     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3861
3862   },
3863
3864   /**
3865    * getCSSHSL
3866    * @return {String} a string representing this Color as a CSS HSL Color value - that
3867    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3868    * s and l are in the range [0,100].
3869    */
3870   getCSSHSL : function(){
3871
3872     // get the HSL components
3873     var hsl = this.getHSL();
3874
3875     // return the CSS HSL Color value
3876     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3877
3878   },
3879
3880   /**
3881    * getCSSHSLA
3882    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3883    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3884    * s and l are in the range [0,100], and a is in the range [0,1].
3885    */
3886   getCSSHSLA : function(){
3887
3888     // get the HSL components
3889     var hsl = this.getHSL();
3890
3891     // return the CSS HSL Color value
3892     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3893
3894   },
3895
3896   /**
3897    * Sets the Color of the specified node to this Color. This functions sets
3898    * the CSS 'color' property for the node. The parameter is:
3899    * 
3900    * @param {DomElement} node - the node whose Color should be set
3901    */
3902   setNodeColor : function(node){
3903
3904     // set the Color of the node
3905     node.style.color = this.getCSSHexadecimalRGB();
3906
3907   },
3908
3909   /**
3910    * Sets the background Color of the specified node to this Color. This
3911    * functions sets the CSS 'background-color' property for the node. The
3912    * parameter is:
3913    *
3914    * @param {DomElement} node - the node whose background Color should be set
3915    */
3916   setNodeBackgroundColor : function(node){
3917
3918     // set the background Color of the node
3919     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3920
3921   },
3922   // convert between formats..
3923   toRGB: function()
3924   {
3925     var r = this.getIntegerRGB();
3926     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3927     
3928   },
3929   toHSL : function()
3930   {
3931      var hsl = this.getHSL();
3932   // return the CSS HSL Color value
3933     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3934     
3935   },
3936   
3937   toHSV : function()
3938   {
3939     var rgb = this.toRGB();
3940     var hsv = rgb.getHSV();
3941    // return the CSS HSL Color value
3942     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3943     
3944   },
3945   
3946   // modify  v = 0 ... 1 (eg. 0.5)
3947   saturate : function(v)
3948   {
3949       var rgb = this.toRGB();
3950       var hsv = rgb.getHSV();
3951       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3952       
3953   
3954   },
3955   
3956    
3957   /**
3958    * getRGB
3959    * @return {Object} the RGB and alpha components of this Color as an object with r,
3960    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3961    * the range [0,1].
3962    */
3963   getRGB: function(){
3964    
3965     // return the RGB components
3966     return {
3967       'r' : this.rgb.r,
3968       'g' : this.rgb.g,
3969       'b' : this.rgb.b,
3970       'a' : this.alpha
3971     };
3972
3973   },
3974
3975   /**
3976    * getHSV
3977    * @return {Object} the HSV and alpha components of this Color as an object with h,
3978    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3979    * [0,100], and a is in the range [0,1].
3980    */
3981   getHSV : function()
3982   {
3983     
3984     // calculate the HSV components if necessary
3985     if (this.hsv == null) {
3986       this.calculateHSV();
3987     }
3988
3989     // return the HSV components
3990     return {
3991       'h' : this.hsv.h,
3992       's' : this.hsv.s,
3993       'v' : this.hsv.v,
3994       'a' : this.alpha
3995     };
3996
3997   },
3998
3999   /**
4000    * getHSL
4001    * @return {Object} the HSL and alpha components of this Color as an object with h,
4002    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4003    * [0,100], and a is in the range [0,1].
4004    */
4005   getHSL : function(){
4006     
4007      
4008     // calculate the HSV components if necessary
4009     if (this.hsl == null) { this.calculateHSL(); }
4010
4011     // return the HSL components
4012     return {
4013       'h' : this.hsl.h,
4014       's' : this.hsl.s,
4015       'l' : this.hsl.l,
4016       'a' : this.alpha
4017     };
4018
4019   }
4020   
4021
4022 });
4023
4024
4025 /**
4026  * @class Roo.lib.RGBColor
4027  * @extends Roo.lib.Color
4028  * Creates a Color specified in the RGB Color space, with an optional alpha
4029  * component. The parameters are:
4030  * @constructor
4031  * 
4032
4033  * @param {Number} r - the red component, clipped to the range [0,255]
4034  * @param {Number} g - the green component, clipped to the range [0,255]
4035  * @param {Number} b - the blue component, clipped to the range [0,255]
4036  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4037  *     optional and defaults to 1
4038  */
4039 Roo.lib.RGBColor = function (r, g, b, a){
4040
4041   // store the alpha component after clipping it if necessary
4042   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4043
4044   // store the RGB components after clipping them if necessary
4045   this.rgb =
4046       {
4047         'r' : Math.max(0, Math.min(255, r)),
4048         'g' : Math.max(0, Math.min(255, g)),
4049         'b' : Math.max(0, Math.min(255, b))
4050       };
4051
4052   // initialise the HSV and HSL components to null
4053   
4054
4055   /* 
4056    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4057    * range [0,360). The parameters are:
4058    *
4059    * maximum - the maximum of the RGB component values
4060    * range   - the range of the RGB component values
4061    */
4062    
4063
4064 }
4065 // this does an 'exteds'
4066 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4067
4068   
4069     getHue  : function(maximum, range)
4070     {
4071       var rgb = this.rgb;
4072        
4073       // check whether the range is zero
4074       if (range == 0){
4075   
4076         // set the hue to zero (any hue is acceptable as the Color is grey)
4077         var hue = 0;
4078   
4079       }else{
4080   
4081         // determine which of the components has the highest value and set the hue
4082         switch (maximum){
4083   
4084           // red has the highest value
4085           case rgb.r:
4086             var hue = (rgb.g - rgb.b) / range * 60;
4087             if (hue < 0) { hue += 360; }
4088             break;
4089   
4090           // green has the highest value
4091           case rgb.g:
4092             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4093             break;
4094   
4095           // blue has the highest value
4096           case rgb.b:
4097             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4098             break;
4099   
4100         }
4101   
4102       }
4103   
4104       // return the hue
4105       return hue;
4106   
4107     },
4108
4109   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4110    * be returned be the getHSV function.
4111    */
4112    calculateHSV : function(){
4113     var rgb = this.rgb;
4114     // get the maximum and range of the RGB component values
4115     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4116     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4117
4118     // store the HSV components
4119     this.hsv =
4120         {
4121           'h' : this.getHue(maximum, range),
4122           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4123           'v' : maximum / 2.55
4124         };
4125
4126   },
4127
4128   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4129    * be returned be the getHSL function.
4130    */
4131    calculateHSL : function(){
4132     var rgb = this.rgb;
4133     // get the maximum and range of the RGB component values
4134     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4135     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4136
4137     // determine the lightness in the range [0,1]
4138     var l = maximum / 255 - range / 510;
4139
4140     // store the HSL components
4141     this.hsl =
4142         {
4143           'h' : this.getHue(maximum, range),
4144           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4145           'l' : 100 * l
4146         };
4147
4148   }
4149
4150 });
4151
4152 /**
4153  * @class Roo.lib.HSVColor
4154  * @extends Roo.lib.Color
4155  * Creates a Color specified in the HSV Color space, with an optional alpha
4156  * component. The parameters are:
4157  * @constructor
4158  *
4159  * @param {Number} h - the hue component, wrapped to the range [0,360)
4160  * @param {Number} s - the saturation component, clipped to the range [0,100]
4161  * @param {Number} v - the value component, clipped to the range [0,100]
4162  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4163  *     optional and defaults to 1
4164  */
4165 Roo.lib.HSVColor = function (h, s, v, a){
4166
4167   // store the alpha component after clipping it if necessary
4168   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4169
4170   // store the HSV components after clipping or wrapping them if necessary
4171   this.hsv =
4172       {
4173         'h' : (h % 360 + 360) % 360,
4174         's' : Math.max(0, Math.min(100, s)),
4175         'v' : Math.max(0, Math.min(100, v))
4176       };
4177
4178   // initialise the RGB and HSL components to null
4179   this.rgb = null;
4180   this.hsl = null;
4181 }
4182
4183 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4184   /* Calculates and stores the RGB components of this HSVColor so that they can
4185    * be returned be the getRGB function.
4186    */
4187   calculateRGB: function ()
4188   {
4189     var hsv = this.hsv;
4190     // check whether the saturation is zero
4191     if (hsv.s == 0){
4192
4193       // set the Color to the appropriate shade of grey
4194       var r = hsv.v;
4195       var g = hsv.v;
4196       var b = hsv.v;
4197
4198     }else{
4199
4200       // set some temporary values
4201       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4202       var p  = hsv.v * (1 - hsv.s / 100);
4203       var q  = hsv.v * (1 - hsv.s / 100 * f);
4204       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4205
4206       // set the RGB Color components to their temporary values
4207       switch (Math.floor(hsv.h / 60)){
4208         case 0: var r = hsv.v; var g = t; var b = p; break;
4209         case 1: var r = q; var g = hsv.v; var b = p; break;
4210         case 2: var r = p; var g = hsv.v; var b = t; break;
4211         case 3: var r = p; var g = q; var b = hsv.v; break;
4212         case 4: var r = t; var g = p; var b = hsv.v; break;
4213         case 5: var r = hsv.v; var g = p; var b = q; break;
4214       }
4215
4216     }
4217
4218     // store the RGB components
4219     this.rgb =
4220         {
4221           'r' : r * 2.55,
4222           'g' : g * 2.55,
4223           'b' : b * 2.55
4224         };
4225
4226   },
4227
4228   /* Calculates and stores the HSL components of this HSVColor so that they can
4229    * be returned be the getHSL function.
4230    */
4231   calculateHSL : function (){
4232
4233     var hsv = this.hsv;
4234     // determine the lightness in the range [0,100]
4235     var l = (2 - hsv.s / 100) * hsv.v / 2;
4236
4237     // store the HSL components
4238     this.hsl =
4239         {
4240           'h' : hsv.h,
4241           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4242           'l' : l
4243         };
4244
4245     // correct a division-by-zero error
4246     if (isNaN(hsl.s)) { hsl.s = 0; }
4247
4248   } 
4249  
4250
4251 });
4252  
4253
4254 /**
4255  * @class Roo.lib.HSLColor
4256  * @extends Roo.lib.Color
4257  *
4258  * @constructor
4259  * Creates a Color specified in the HSL Color space, with an optional alpha
4260  * component. The parameters are:
4261  *
4262  * @param {Number} h - the hue component, wrapped to the range [0,360)
4263  * @param {Number} s - the saturation component, clipped to the range [0,100]
4264  * @param {Number} l - the lightness component, clipped to the range [0,100]
4265  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4266  *     optional and defaults to 1
4267  */
4268
4269 Roo.lib.HSLColor = function(h, s, l, a){
4270
4271   // store the alpha component after clipping it if necessary
4272   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4273
4274   // store the HSL components after clipping or wrapping them if necessary
4275   this.hsl =
4276       {
4277         'h' : (h % 360 + 360) % 360,
4278         's' : Math.max(0, Math.min(100, s)),
4279         'l' : Math.max(0, Math.min(100, l))
4280       };
4281
4282   // initialise the RGB and HSV components to null
4283 }
4284
4285 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4286
4287   /* Calculates and stores the RGB components of this HSLColor so that they can
4288    * be returned be the getRGB function.
4289    */
4290   calculateRGB: function (){
4291
4292     // check whether the saturation is zero
4293     if (this.hsl.s == 0){
4294
4295       // store the RGB components representing the appropriate shade of grey
4296       this.rgb =
4297           {
4298             'r' : this.hsl.l * 2.55,
4299             'g' : this.hsl.l * 2.55,
4300             'b' : this.hsl.l * 2.55
4301           };
4302
4303     }else{
4304
4305       // set some temporary values
4306       var p = this.hsl.l < 50
4307             ? this.hsl.l * (1 + hsl.s / 100)
4308             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4309       var q = 2 * hsl.l - p;
4310
4311       // initialise the RGB components
4312       this.rgb =
4313           {
4314             'r' : (h + 120) / 60 % 6,
4315             'g' : h / 60,
4316             'b' : (h + 240) / 60 % 6
4317           };
4318
4319       // loop over the RGB components
4320       for (var key in this.rgb){
4321
4322         // ensure that the property is not inherited from the root object
4323         if (this.rgb.hasOwnProperty(key)){
4324
4325           // set the component to its value in the range [0,100]
4326           if (this.rgb[key] < 1){
4327             this.rgb[key] = q + (p - q) * this.rgb[key];
4328           }else if (this.rgb[key] < 3){
4329             this.rgb[key] = p;
4330           }else if (this.rgb[key] < 4){
4331             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4332           }else{
4333             this.rgb[key] = q;
4334           }
4335
4336           // set the component to its value in the range [0,255]
4337           this.rgb[key] *= 2.55;
4338
4339         }
4340
4341       }
4342
4343     }
4344
4345   },
4346
4347   /* Calculates and stores the HSV components of this HSLColor so that they can
4348    * be returned be the getHSL function.
4349    */
4350    calculateHSV : function(){
4351
4352     // set a temporary value
4353     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4354
4355     // store the HSV components
4356     this.hsv =
4357         {
4358           'h' : this.hsl.h,
4359           's' : 200 * t / (this.hsl.l + t),
4360           'v' : t + this.hsl.l
4361         };
4362
4363     // correct a division-by-zero error
4364     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4365
4366   }
4367  
4368
4369 });
4370 /*
4371  * Portions of this file are based on pieces of Yahoo User Interface Library
4372  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4373  * YUI licensed under the BSD License:
4374  * http://developer.yahoo.net/yui/license.txt
4375  * <script type="text/javascript">
4376  *
4377  */
4378 (function() {
4379
4380     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4381         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4382     };
4383
4384     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4385
4386     var fly = Roo.lib.AnimBase.fly;
4387     var Y = Roo.lib;
4388     var superclass = Y.ColorAnim.superclass;
4389     var proto = Y.ColorAnim.prototype;
4390
4391     proto.toString = function() {
4392         var el = this.getEl();
4393         var id = el.id || el.tagName;
4394         return ("ColorAnim " + id);
4395     };
4396
4397     proto.patterns.color = /color$/i;
4398     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4399     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4400     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4401     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4402
4403
4404     proto.parseColor = function(s) {
4405         if (s.length == 3) {
4406             return s;
4407         }
4408
4409         var c = this.patterns.hex.exec(s);
4410         if (c && c.length == 4) {
4411             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4412         }
4413
4414         c = this.patterns.rgb.exec(s);
4415         if (c && c.length == 4) {
4416             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4417         }
4418
4419         c = this.patterns.hex3.exec(s);
4420         if (c && c.length == 4) {
4421             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4422         }
4423
4424         return null;
4425     };
4426     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4427     proto.getAttribute = function(attr) {
4428         var el = this.getEl();
4429         if (this.patterns.color.test(attr)) {
4430             var val = fly(el).getStyle(attr);
4431
4432             if (this.patterns.transparent.test(val)) {
4433                 var parent = el.parentNode;
4434                 val = fly(parent).getStyle(attr);
4435
4436                 while (parent && this.patterns.transparent.test(val)) {
4437                     parent = parent.parentNode;
4438                     val = fly(parent).getStyle(attr);
4439                     if (parent.tagName.toUpperCase() == 'HTML') {
4440                         val = '#fff';
4441                     }
4442                 }
4443             }
4444         } else {
4445             val = superclass.getAttribute.call(this, attr);
4446         }
4447
4448         return val;
4449     };
4450     proto.getAttribute = function(attr) {
4451         var el = this.getEl();
4452         if (this.patterns.color.test(attr)) {
4453             var val = fly(el).getStyle(attr);
4454
4455             if (this.patterns.transparent.test(val)) {
4456                 var parent = el.parentNode;
4457                 val = fly(parent).getStyle(attr);
4458
4459                 while (parent && this.patterns.transparent.test(val)) {
4460                     parent = parent.parentNode;
4461                     val = fly(parent).getStyle(attr);
4462                     if (parent.tagName.toUpperCase() == 'HTML') {
4463                         val = '#fff';
4464                     }
4465                 }
4466             }
4467         } else {
4468             val = superclass.getAttribute.call(this, attr);
4469         }
4470
4471         return val;
4472     };
4473
4474     proto.doMethod = function(attr, start, end) {
4475         var val;
4476
4477         if (this.patterns.color.test(attr)) {
4478             val = [];
4479             for (var i = 0, len = start.length; i < len; ++i) {
4480                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4481             }
4482
4483             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4484         }
4485         else {
4486             val = superclass.doMethod.call(this, attr, start, end);
4487         }
4488
4489         return val;
4490     };
4491
4492     proto.setRuntimeAttribute = function(attr) {
4493         superclass.setRuntimeAttribute.call(this, attr);
4494
4495         if (this.patterns.color.test(attr)) {
4496             var attributes = this.attributes;
4497             var start = this.parseColor(this.runtimeAttributes[attr].start);
4498             var end = this.parseColor(this.runtimeAttributes[attr].end);
4499
4500             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4501                 end = this.parseColor(attributes[attr].by);
4502
4503                 for (var i = 0, len = start.length; i < len; ++i) {
4504                     end[i] = start[i] + end[i];
4505                 }
4506             }
4507
4508             this.runtimeAttributes[attr].start = start;
4509             this.runtimeAttributes[attr].end = end;
4510         }
4511     };
4512 })();
4513
4514 /*
4515  * Portions of this file are based on pieces of Yahoo User Interface Library
4516  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4517  * YUI licensed under the BSD License:
4518  * http://developer.yahoo.net/yui/license.txt
4519  * <script type="text/javascript">
4520  *
4521  */
4522 Roo.lib.Easing = {
4523
4524
4525     easeNone: function (t, b, c, d) {
4526         return c * t / d + b;
4527     },
4528
4529
4530     easeIn: function (t, b, c, d) {
4531         return c * (t /= d) * t + b;
4532     },
4533
4534
4535     easeOut: function (t, b, c, d) {
4536         return -c * (t /= d) * (t - 2) + b;
4537     },
4538
4539
4540     easeBoth: function (t, b, c, d) {
4541         if ((t /= d / 2) < 1) {
4542             return c / 2 * t * t + b;
4543         }
4544
4545         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4546     },
4547
4548
4549     easeInStrong: function (t, b, c, d) {
4550         return c * (t /= d) * t * t * t + b;
4551     },
4552
4553
4554     easeOutStrong: function (t, b, c, d) {
4555         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4556     },
4557
4558
4559     easeBothStrong: function (t, b, c, d) {
4560         if ((t /= d / 2) < 1) {
4561             return c / 2 * t * t * t * t + b;
4562         }
4563
4564         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4565     },
4566
4567
4568
4569     elasticIn: function (t, b, c, d, a, p) {
4570         if (t == 0) {
4571             return b;
4572         }
4573         if ((t /= d) == 1) {
4574             return b + c;
4575         }
4576         if (!p) {
4577             p = d * .3;
4578         }
4579
4580         if (!a || a < Math.abs(c)) {
4581             a = c;
4582             var s = p / 4;
4583         }
4584         else {
4585             var s = p / (2 * Math.PI) * Math.asin(c / a);
4586         }
4587
4588         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4589     },
4590
4591
4592     elasticOut: function (t, b, c, d, a, p) {
4593         if (t == 0) {
4594             return b;
4595         }
4596         if ((t /= d) == 1) {
4597             return b + c;
4598         }
4599         if (!p) {
4600             p = d * .3;
4601         }
4602
4603         if (!a || a < Math.abs(c)) {
4604             a = c;
4605             var s = p / 4;
4606         }
4607         else {
4608             var s = p / (2 * Math.PI) * Math.asin(c / a);
4609         }
4610
4611         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4612     },
4613
4614
4615     elasticBoth: function (t, b, c, d, a, p) {
4616         if (t == 0) {
4617             return b;
4618         }
4619
4620         if ((t /= d / 2) == 2) {
4621             return b + c;
4622         }
4623
4624         if (!p) {
4625             p = d * (.3 * 1.5);
4626         }
4627
4628         if (!a || a < Math.abs(c)) {
4629             a = c;
4630             var s = p / 4;
4631         }
4632         else {
4633             var s = p / (2 * Math.PI) * Math.asin(c / a);
4634         }
4635
4636         if (t < 1) {
4637             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4638                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4639         }
4640         return a * Math.pow(2, -10 * (t -= 1)) *
4641                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4642     },
4643
4644
4645
4646     backIn: function (t, b, c, d, s) {
4647         if (typeof s == 'undefined') {
4648             s = 1.70158;
4649         }
4650         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4651     },
4652
4653
4654     backOut: function (t, b, c, d, s) {
4655         if (typeof s == 'undefined') {
4656             s = 1.70158;
4657         }
4658         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4659     },
4660
4661
4662     backBoth: function (t, b, c, d, s) {
4663         if (typeof s == 'undefined') {
4664             s = 1.70158;
4665         }
4666
4667         if ((t /= d / 2 ) < 1) {
4668             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4669         }
4670         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4671     },
4672
4673
4674     bounceIn: function (t, b, c, d) {
4675         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4676     },
4677
4678
4679     bounceOut: function (t, b, c, d) {
4680         if ((t /= d) < (1 / 2.75)) {
4681             return c * (7.5625 * t * t) + b;
4682         } else if (t < (2 / 2.75)) {
4683             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4684         } else if (t < (2.5 / 2.75)) {
4685             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4686         }
4687         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4688     },
4689
4690
4691     bounceBoth: function (t, b, c, d) {
4692         if (t < d / 2) {
4693             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4694         }
4695         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4696     }
4697 };/*
4698  * Portions of this file are based on pieces of Yahoo User Interface Library
4699  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4700  * YUI licensed under the BSD License:
4701  * http://developer.yahoo.net/yui/license.txt
4702  * <script type="text/javascript">
4703  *
4704  */
4705     (function() {
4706         Roo.lib.Motion = function(el, attributes, duration, method) {
4707             if (el) {
4708                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4709             }
4710         };
4711
4712         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4713
4714
4715         var Y = Roo.lib;
4716         var superclass = Y.Motion.superclass;
4717         var proto = Y.Motion.prototype;
4718
4719         proto.toString = function() {
4720             var el = this.getEl();
4721             var id = el.id || el.tagName;
4722             return ("Motion " + id);
4723         };
4724
4725         proto.patterns.points = /^points$/i;
4726
4727         proto.setAttribute = function(attr, val, unit) {
4728             if (this.patterns.points.test(attr)) {
4729                 unit = unit || 'px';
4730                 superclass.setAttribute.call(this, 'left', val[0], unit);
4731                 superclass.setAttribute.call(this, 'top', val[1], unit);
4732             } else {
4733                 superclass.setAttribute.call(this, attr, val, unit);
4734             }
4735         };
4736
4737         proto.getAttribute = function(attr) {
4738             if (this.patterns.points.test(attr)) {
4739                 var val = [
4740                         superclass.getAttribute.call(this, 'left'),
4741                         superclass.getAttribute.call(this, 'top')
4742                         ];
4743             } else {
4744                 val = superclass.getAttribute.call(this, attr);
4745             }
4746
4747             return val;
4748         };
4749
4750         proto.doMethod = function(attr, start, end) {
4751             var val = null;
4752
4753             if (this.patterns.points.test(attr)) {
4754                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4755                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4756             } else {
4757                 val = superclass.doMethod.call(this, attr, start, end);
4758             }
4759             return val;
4760         };
4761
4762         proto.setRuntimeAttribute = function(attr) {
4763             if (this.patterns.points.test(attr)) {
4764                 var el = this.getEl();
4765                 var attributes = this.attributes;
4766                 var start;
4767                 var control = attributes['points']['control'] || [];
4768                 var end;
4769                 var i, len;
4770
4771                 if (control.length > 0 && !(control[0] instanceof Array)) {
4772                     control = [control];
4773                 } else {
4774                     var tmp = [];
4775                     for (i = 0,len = control.length; i < len; ++i) {
4776                         tmp[i] = control[i];
4777                     }
4778                     control = tmp;
4779                 }
4780
4781                 Roo.fly(el).position();
4782
4783                 if (isset(attributes['points']['from'])) {
4784                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4785                 }
4786                 else {
4787                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4788                 }
4789
4790                 start = this.getAttribute('points');
4791
4792
4793                 if (isset(attributes['points']['to'])) {
4794                     end = translateValues.call(this, attributes['points']['to'], start);
4795
4796                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4797                     for (i = 0,len = control.length; i < len; ++i) {
4798                         control[i] = translateValues.call(this, control[i], start);
4799                     }
4800
4801
4802                 } else if (isset(attributes['points']['by'])) {
4803                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4804
4805                     for (i = 0,len = control.length; i < len; ++i) {
4806                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4807                     }
4808                 }
4809
4810                 this.runtimeAttributes[attr] = [start];
4811
4812                 if (control.length > 0) {
4813                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4814                 }
4815
4816                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4817             }
4818             else {
4819                 superclass.setRuntimeAttribute.call(this, attr);
4820             }
4821         };
4822
4823         var translateValues = function(val, start) {
4824             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4825             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4826
4827             return val;
4828         };
4829
4830         var isset = function(prop) {
4831             return (typeof prop !== 'undefined');
4832         };
4833     })();
4834 /*
4835  * Portions of this file are based on pieces of Yahoo User Interface Library
4836  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4837  * YUI licensed under the BSD License:
4838  * http://developer.yahoo.net/yui/license.txt
4839  * <script type="text/javascript">
4840  *
4841  */
4842     (function() {
4843         Roo.lib.Scroll = function(el, attributes, duration, method) {
4844             if (el) {
4845                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4846             }
4847         };
4848
4849         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4850
4851
4852         var Y = Roo.lib;
4853         var superclass = Y.Scroll.superclass;
4854         var proto = Y.Scroll.prototype;
4855
4856         proto.toString = function() {
4857             var el = this.getEl();
4858             var id = el.id || el.tagName;
4859             return ("Scroll " + id);
4860         };
4861
4862         proto.doMethod = function(attr, start, end) {
4863             var val = null;
4864
4865             if (attr == 'scroll') {
4866                 val = [
4867                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4868                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4869                         ];
4870
4871             } else {
4872                 val = superclass.doMethod.call(this, attr, start, end);
4873             }
4874             return val;
4875         };
4876
4877         proto.getAttribute = function(attr) {
4878             var val = null;
4879             var el = this.getEl();
4880
4881             if (attr == 'scroll') {
4882                 val = [ el.scrollLeft, el.scrollTop ];
4883             } else {
4884                 val = superclass.getAttribute.call(this, attr);
4885             }
4886
4887             return val;
4888         };
4889
4890         proto.setAttribute = function(attr, val, unit) {
4891             var el = this.getEl();
4892
4893             if (attr == 'scroll') {
4894                 el.scrollLeft = val[0];
4895                 el.scrollTop = val[1];
4896             } else {
4897                 superclass.setAttribute.call(this, attr, val, unit);
4898             }
4899         };
4900     })();
4901 /*
4902  * Based on:
4903  * Ext JS Library 1.1.1
4904  * Copyright(c) 2006-2007, Ext JS, LLC.
4905  *
4906  * Originally Released Under LGPL - original licence link has changed is not relivant.
4907  *
4908  * Fork - LGPL
4909  * <script type="text/javascript">
4910  */
4911
4912
4913 // nasty IE9 hack - what a pile of crap that is..
4914
4915  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4916     Range.prototype.createContextualFragment = function (html) {
4917         var doc = window.document;
4918         var container = doc.createElement("div");
4919         container.innerHTML = html;
4920         var frag = doc.createDocumentFragment(), n;
4921         while ((n = container.firstChild)) {
4922             frag.appendChild(n);
4923         }
4924         return frag;
4925     };
4926 }
4927
4928 /**
4929  * @class Roo.DomHelper
4930  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4931  * 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>.
4932  * @static
4933  */
4934 Roo.DomHelper = function(){
4935     var tempTableEl = null;
4936     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4937     var tableRe = /^table|tbody|tr|td$/i;
4938     var xmlns = {};
4939     // build as innerHTML where available
4940     /** @ignore */
4941     var createHtml = function(o){
4942         if(typeof o == 'string'){
4943             return o;
4944         }
4945         var b = "";
4946         if(!o.tag){
4947             o.tag = "div";
4948         }
4949         b += "<" + o.tag;
4950         for(var attr in o){
4951             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4952             if(attr == "style"){
4953                 var s = o["style"];
4954                 if(typeof s == "function"){
4955                     s = s.call();
4956                 }
4957                 if(typeof s == "string"){
4958                     b += ' style="' + s + '"';
4959                 }else if(typeof s == "object"){
4960                     b += ' style="';
4961                     for(var key in s){
4962                         if(typeof s[key] != "function"){
4963                             b += key + ":" + s[key] + ";";
4964                         }
4965                     }
4966                     b += '"';
4967                 }
4968             }else{
4969                 if(attr == "cls"){
4970                     b += ' class="' + o["cls"] + '"';
4971                 }else if(attr == "htmlFor"){
4972                     b += ' for="' + o["htmlFor"] + '"';
4973                 }else{
4974                     b += " " + attr + '="' + o[attr] + '"';
4975                 }
4976             }
4977         }
4978         if(emptyTags.test(o.tag)){
4979             b += "/>";
4980         }else{
4981             b += ">";
4982             var cn = o.children || o.cn;
4983             if(cn){
4984                 //http://bugs.kde.org/show_bug.cgi?id=71506
4985                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4986                     for(var i = 0, len = cn.length; i < len; i++) {
4987                         b += createHtml(cn[i], b);
4988                     }
4989                 }else{
4990                     b += createHtml(cn, b);
4991                 }
4992             }
4993             if(o.html){
4994                 b += o.html;
4995             }
4996             b += "</" + o.tag + ">";
4997         }
4998         return b;
4999     };
5000
5001     // build as dom
5002     /** @ignore */
5003     var createDom = function(o, parentNode){
5004          
5005         // defininition craeted..
5006         var ns = false;
5007         if (o.ns && o.ns != 'html') {
5008                
5009             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5010                 xmlns[o.ns] = o.xmlns;
5011                 ns = o.xmlns;
5012             }
5013             if (typeof(xmlns[o.ns]) == 'undefined') {
5014                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5015             }
5016             ns = xmlns[o.ns];
5017         }
5018         
5019         
5020         if (typeof(o) == 'string') {
5021             return parentNode.appendChild(document.createTextNode(o));
5022         }
5023         o.tag = o.tag || div;
5024         if (o.ns && Roo.isIE) {
5025             ns = false;
5026             o.tag = o.ns + ':' + o.tag;
5027             
5028         }
5029         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5030         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5031         for(var attr in o){
5032             
5033             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5034                     attr == "style" || typeof o[attr] == "function") { continue; }
5035                     
5036             if(attr=="cls" && Roo.isIE){
5037                 el.className = o["cls"];
5038             }else{
5039                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5040                 else { 
5041                     el[attr] = o[attr];
5042                 }
5043             }
5044         }
5045         Roo.DomHelper.applyStyles(el, o.style);
5046         var cn = o.children || o.cn;
5047         if(cn){
5048             //http://bugs.kde.org/show_bug.cgi?id=71506
5049              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5050                 for(var i = 0, len = cn.length; i < len; i++) {
5051                     createDom(cn[i], el);
5052                 }
5053             }else{
5054                 createDom(cn, el);
5055             }
5056         }
5057         if(o.html){
5058             el.innerHTML = o.html;
5059         }
5060         if(parentNode){
5061            parentNode.appendChild(el);
5062         }
5063         return el;
5064     };
5065
5066     var ieTable = function(depth, s, h, e){
5067         tempTableEl.innerHTML = [s, h, e].join('');
5068         var i = -1, el = tempTableEl;
5069         while(++i < depth && el.firstChild){
5070             el = el.firstChild;
5071         }
5072         return el;
5073     };
5074
5075     // kill repeat to save bytes
5076     var ts = '<table>',
5077         te = '</table>',
5078         tbs = ts+'<tbody>',
5079         tbe = '</tbody>'+te,
5080         trs = tbs + '<tr>',
5081         tre = '</tr>'+tbe;
5082
5083     /**
5084      * @ignore
5085      * Nasty code for IE's broken table implementation
5086      */
5087     var insertIntoTable = function(tag, where, el, html){
5088         if(!tempTableEl){
5089             tempTableEl = document.createElement('div');
5090         }
5091         var node;
5092         var before = null;
5093         if(tag == 'td'){
5094             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5095                 return;
5096             }
5097             if(where == 'beforebegin'){
5098                 before = el;
5099                 el = el.parentNode;
5100             } else{
5101                 before = el.nextSibling;
5102                 el = el.parentNode;
5103             }
5104             node = ieTable(4, trs, html, tre);
5105         }
5106         else if(tag == 'tr'){
5107             if(where == 'beforebegin'){
5108                 before = el;
5109                 el = el.parentNode;
5110                 node = ieTable(3, tbs, html, tbe);
5111             } else if(where == 'afterend'){
5112                 before = el.nextSibling;
5113                 el = el.parentNode;
5114                 node = ieTable(3, tbs, html, tbe);
5115             } else{ // INTO a TR
5116                 if(where == 'afterbegin'){
5117                     before = el.firstChild;
5118                 }
5119                 node = ieTable(4, trs, html, tre);
5120             }
5121         } else if(tag == 'tbody'){
5122             if(where == 'beforebegin'){
5123                 before = el;
5124                 el = el.parentNode;
5125                 node = ieTable(2, ts, html, te);
5126             } else if(where == 'afterend'){
5127                 before = el.nextSibling;
5128                 el = el.parentNode;
5129                 node = ieTable(2, ts, html, te);
5130             } else{
5131                 if(where == 'afterbegin'){
5132                     before = el.firstChild;
5133                 }
5134                 node = ieTable(3, tbs, html, tbe);
5135             }
5136         } else{ // TABLE
5137             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5138                 return;
5139             }
5140             if(where == 'afterbegin'){
5141                 before = el.firstChild;
5142             }
5143             node = ieTable(2, ts, html, te);
5144         }
5145         el.insertBefore(node, before);
5146         return node;
5147     };
5148     
5149     // this is a bit like the react update code...
5150     // 
5151     
5152     var updateNode = function(from, to)
5153     {
5154         // should we handle non-standard elements?
5155         
5156         if (from.nodeType != to.nodeType) {
5157             from.parentNode.replaceChild(to, from);
5158         }
5159         
5160         if (from.nodeType == 3) {
5161             // assume it's text?!
5162             if (from.data == to.data) {
5163                 return;
5164             }
5165             from.data = to.data;
5166             return;
5167         }
5168         
5169         // assume 'to' doesnt have '1/3 nodetypes!
5170         if (from.nodeType !=1 || from.tagName != to.tagName) {
5171             from.parentNode.replaceChild(to, from);
5172             return;
5173         }
5174         // compare attributes
5175         var ar = Array.from(from.attributes);
5176         for(var i = 0; i< ar.length;i++) {
5177             if (to.hasAttribute(ar[i].name)) {
5178                 continue;
5179             }
5180             from.removeAttribute(ar[i].name);
5181         }
5182         ar = to.attributes;
5183         for(var i = 0; i< ar.length;i++) {
5184             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5185                 continue;
5186             }
5187             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5188         }
5189         // children
5190         var far = Array.from(from.childNodes);
5191         var tar = Array.from(to.childNodes);
5192         // if the lengths are different.. then it's probably a editable content change, rather than
5193         // a change of the block definition..
5194         if (from.innerHTML == to.innerHTML) {
5195             return;
5196         }
5197         if (far.length != tar.length) {
5198             from.innerHTML = to.innerHTML;
5199             return;
5200         }
5201         
5202         for(var i = 0; i < far.length; i++) {
5203             updateNode(far[i], tar[i]);
5204         }
5205         
5206         
5207     };
5208     
5209     
5210
5211     return {
5212         /** True to force the use of DOM instead of html fragments @type Boolean */
5213         useDom : false,
5214     
5215         /**
5216          * Returns the markup for the passed Element(s) config
5217          * @param {Object} o The Dom object spec (and children)
5218          * @return {String}
5219          */
5220         markup : function(o){
5221             return createHtml(o);
5222         },
5223     
5224         /**
5225          * Applies a style specification to an element
5226          * @param {String/HTMLElement} el The element to apply styles to
5227          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5228          * a function which returns such a specification.
5229          */
5230         applyStyles : function(el, styles){
5231             if(styles){
5232                el = Roo.fly(el);
5233                if(typeof styles == "string"){
5234                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5235                    var matches;
5236                    while ((matches = re.exec(styles)) != null){
5237                        el.setStyle(matches[1], matches[2]);
5238                    }
5239                }else if (typeof styles == "object"){
5240                    for (var style in styles){
5241                       el.setStyle(style, styles[style]);
5242                    }
5243                }else if (typeof styles == "function"){
5244                     Roo.DomHelper.applyStyles(el, styles.call());
5245                }
5246             }
5247         },
5248     
5249         /**
5250          * Inserts an HTML fragment into the Dom
5251          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5252          * @param {HTMLElement} el The context element
5253          * @param {String} html The HTML fragmenet
5254          * @return {HTMLElement} The new node
5255          */
5256         insertHtml : function(where, el, html){
5257             where = where.toLowerCase();
5258             if(el.insertAdjacentHTML){
5259                 if(tableRe.test(el.tagName)){
5260                     var rs;
5261                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5262                         return rs;
5263                     }
5264                 }
5265                 switch(where){
5266                     case "beforebegin":
5267                         el.insertAdjacentHTML('BeforeBegin', html);
5268                         return el.previousSibling;
5269                     case "afterbegin":
5270                         el.insertAdjacentHTML('AfterBegin', html);
5271                         return el.firstChild;
5272                     case "beforeend":
5273                         el.insertAdjacentHTML('BeforeEnd', html);
5274                         return el.lastChild;
5275                     case "afterend":
5276                         el.insertAdjacentHTML('AfterEnd', html);
5277                         return el.nextSibling;
5278                 }
5279                 throw 'Illegal insertion point -> "' + where + '"';
5280             }
5281             var range = el.ownerDocument.createRange();
5282             var frag;
5283             switch(where){
5284                  case "beforebegin":
5285                     range.setStartBefore(el);
5286                     frag = range.createContextualFragment(html);
5287                     el.parentNode.insertBefore(frag, el);
5288                     return el.previousSibling;
5289                  case "afterbegin":
5290                     if(el.firstChild){
5291                         range.setStartBefore(el.firstChild);
5292                         frag = range.createContextualFragment(html);
5293                         el.insertBefore(frag, el.firstChild);
5294                         return el.firstChild;
5295                     }else{
5296                         el.innerHTML = html;
5297                         return el.firstChild;
5298                     }
5299                 case "beforeend":
5300                     if(el.lastChild){
5301                         range.setStartAfter(el.lastChild);
5302                         frag = range.createContextualFragment(html);
5303                         el.appendChild(frag);
5304                         return el.lastChild;
5305                     }else{
5306                         el.innerHTML = html;
5307                         return el.lastChild;
5308                     }
5309                 case "afterend":
5310                     range.setStartAfter(el);
5311                     frag = range.createContextualFragment(html);
5312                     el.parentNode.insertBefore(frag, el.nextSibling);
5313                     return el.nextSibling;
5314                 }
5315                 throw 'Illegal insertion point -> "' + where + '"';
5316         },
5317     
5318         /**
5319          * Creates new Dom element(s) and inserts them before el
5320          * @param {String/HTMLElement/Element} el The context element
5321          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5322          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5323          * @return {HTMLElement/Roo.Element} The new node
5324          */
5325         insertBefore : function(el, o, returnElement){
5326             return this.doInsert(el, o, returnElement, "beforeBegin");
5327         },
5328     
5329         /**
5330          * Creates new Dom element(s) and inserts them after el
5331          * @param {String/HTMLElement/Element} el The context element
5332          * @param {Object} o The Dom object spec (and children)
5333          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5334          * @return {HTMLElement/Roo.Element} The new node
5335          */
5336         insertAfter : function(el, o, returnElement){
5337             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5338         },
5339     
5340         /**
5341          * Creates new Dom element(s) and inserts them as the first child of el
5342          * @param {String/HTMLElement/Element} el The context element
5343          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5344          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5345          * @return {HTMLElement/Roo.Element} The new node
5346          */
5347         insertFirst : function(el, o, returnElement){
5348             return this.doInsert(el, o, returnElement, "afterBegin");
5349         },
5350     
5351         // private
5352         doInsert : function(el, o, returnElement, pos, sibling){
5353             el = Roo.getDom(el);
5354             var newNode;
5355             if(this.useDom || o.ns){
5356                 newNode = createDom(o, null);
5357                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5358             }else{
5359                 var html = createHtml(o);
5360                 newNode = this.insertHtml(pos, el, html);
5361             }
5362             return returnElement ? Roo.get(newNode, true) : newNode;
5363         },
5364     
5365         /**
5366          * Creates new Dom element(s) and appends them to el
5367          * @param {String/HTMLElement/Element} el The context element
5368          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5369          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5370          * @return {HTMLElement/Roo.Element} The new node
5371          */
5372         append : function(el, o, returnElement){
5373             el = Roo.getDom(el);
5374             var newNode;
5375             if(this.useDom || o.ns){
5376                 newNode = createDom(o, null);
5377                 el.appendChild(newNode);
5378             }else{
5379                 var html = createHtml(o);
5380                 newNode = this.insertHtml("beforeEnd", el, html);
5381             }
5382             return returnElement ? Roo.get(newNode, true) : newNode;
5383         },
5384     
5385         /**
5386          * Creates new Dom element(s) and overwrites the contents of el with them
5387          * @param {String/HTMLElement/Element} el The context element
5388          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5389          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5390          * @return {HTMLElement/Roo.Element} The new node
5391          */
5392         overwrite : function(el, o, returnElement)
5393         {
5394             el = Roo.getDom(el);
5395             if (o.ns) {
5396               
5397                 while (el.childNodes.length) {
5398                     el.removeChild(el.firstChild);
5399                 }
5400                 createDom(o, el);
5401             } else {
5402                 el.innerHTML = createHtml(o);   
5403             }
5404             
5405             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5406         },
5407     
5408         /**
5409          * Creates a new Roo.DomHelper.Template from the Dom object spec
5410          * @param {Object} o The Dom object spec (and children)
5411          * @return {Roo.DomHelper.Template} The new template
5412          */
5413         createTemplate : function(o){
5414             var html = createHtml(o);
5415             return new Roo.Template(html);
5416         },
5417          /**
5418          * Updates the first element with the spec from the o (replacing if necessary)
5419          * This iterates through the children, and updates attributes / children etc..
5420          * @param {String/HTMLElement/Element} el The context element
5421          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5422          */
5423         
5424         update : function(el, o)
5425         {
5426             updateNode(Roo.getDom(el), createDom(o));
5427             
5428         }
5429         
5430         
5431     };
5432 }();
5433 /*
5434  * Based on:
5435  * Ext JS Library 1.1.1
5436  * Copyright(c) 2006-2007, Ext JS, LLC.
5437  *
5438  * Originally Released Under LGPL - original licence link has changed is not relivant.
5439  *
5440  * Fork - LGPL
5441  * <script type="text/javascript">
5442  */
5443  
5444 /**
5445 * @class Roo.Template
5446 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5447 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5448 * Usage:
5449 <pre><code>
5450 var t = new Roo.Template({
5451     html :  '&lt;div name="{id}"&gt;' + 
5452         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5453         '&lt;/div&gt;',
5454     myformat: function (value, allValues) {
5455         return 'XX' + value;
5456     }
5457 });
5458 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5459 </code></pre>
5460 * For more information see this blog post with examples:
5461 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5462      - Create Elements using DOM, HTML fragments and Templates</a>. 
5463 * @constructor
5464 * @param {Object} cfg - Configuration object.
5465 */
5466 Roo.Template = function(cfg){
5467     // BC!
5468     if(cfg instanceof Array){
5469         cfg = cfg.join("");
5470     }else if(arguments.length > 1){
5471         cfg = Array.prototype.join.call(arguments, "");
5472     }
5473     
5474     
5475     if (typeof(cfg) == 'object') {
5476         Roo.apply(this,cfg)
5477     } else {
5478         // bc
5479         this.html = cfg;
5480     }
5481     if (this.url) {
5482         this.load();
5483     }
5484     
5485 };
5486 Roo.Template.prototype = {
5487     
5488     /**
5489      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5490      */
5491     onLoad : false,
5492     
5493     
5494     /**
5495      * @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..
5496      *                    it should be fixed so that template is observable...
5497      */
5498     url : false,
5499     /**
5500      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5501      */
5502     html : '',
5503     
5504     
5505     compiled : false,
5506     loaded : false,
5507     /**
5508      * Returns an HTML fragment of this template with the specified values applied.
5509      * @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'})
5510      * @return {String} The HTML fragment
5511      */
5512     
5513    
5514     
5515     applyTemplate : function(values){
5516         //Roo.log(["applyTemplate", values]);
5517         try {
5518            
5519             if(this.compiled){
5520                 return this.compiled(values);
5521             }
5522             var useF = this.disableFormats !== true;
5523             var fm = Roo.util.Format, tpl = this;
5524             var fn = function(m, name, format, args){
5525                 if(format && useF){
5526                     if(format.substr(0, 5) == "this."){
5527                         return tpl.call(format.substr(5), values[name], values);
5528                     }else{
5529                         if(args){
5530                             // quoted values are required for strings in compiled templates, 
5531                             // but for non compiled we need to strip them
5532                             // quoted reversed for jsmin
5533                             var re = /^\s*['"](.*)["']\s*$/;
5534                             args = args.split(',');
5535                             for(var i = 0, len = args.length; i < len; i++){
5536                                 args[i] = args[i].replace(re, "$1");
5537                             }
5538                             args = [values[name]].concat(args);
5539                         }else{
5540                             args = [values[name]];
5541                         }
5542                         return fm[format].apply(fm, args);
5543                     }
5544                 }else{
5545                     return values[name] !== undefined ? values[name] : "";
5546                 }
5547             };
5548             return this.html.replace(this.re, fn);
5549         } catch (e) {
5550             Roo.log(e);
5551             throw e;
5552         }
5553          
5554     },
5555     
5556     loading : false,
5557       
5558     load : function ()
5559     {
5560          
5561         if (this.loading) {
5562             return;
5563         }
5564         var _t = this;
5565         
5566         this.loading = true;
5567         this.compiled = false;
5568         
5569         var cx = new Roo.data.Connection();
5570         cx.request({
5571             url : this.url,
5572             method : 'GET',
5573             success : function (response) {
5574                 _t.loading = false;
5575                 _t.url = false;
5576                 
5577                 _t.set(response.responseText,true);
5578                 _t.loaded = true;
5579                 if (_t.onLoad) {
5580                     _t.onLoad();
5581                 }
5582              },
5583             failure : function(response) {
5584                 Roo.log("Template failed to load from " + _t.url);
5585                 _t.loading = false;
5586             }
5587         });
5588     },
5589
5590     /**
5591      * Sets the HTML used as the template and optionally compiles it.
5592      * @param {String} html
5593      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5594      * @return {Roo.Template} this
5595      */
5596     set : function(html, compile){
5597         this.html = html;
5598         this.compiled = false;
5599         if(compile){
5600             this.compile();
5601         }
5602         return this;
5603     },
5604     
5605     /**
5606      * True to disable format functions (defaults to false)
5607      * @type Boolean
5608      */
5609     disableFormats : false,
5610     
5611     /**
5612     * The regular expression used to match template variables 
5613     * @type RegExp
5614     * @property 
5615     */
5616     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5617     
5618     /**
5619      * Compiles the template into an internal function, eliminating the RegEx overhead.
5620      * @return {Roo.Template} this
5621      */
5622     compile : function(){
5623         var fm = Roo.util.Format;
5624         var useF = this.disableFormats !== true;
5625         var sep = Roo.isGecko ? "+" : ",";
5626         var fn = function(m, name, format, args){
5627             if(format && useF){
5628                 args = args ? ',' + args : "";
5629                 if(format.substr(0, 5) != "this."){
5630                     format = "fm." + format + '(';
5631                 }else{
5632                     format = 'this.call("'+ format.substr(5) + '", ';
5633                     args = ", values";
5634                 }
5635             }else{
5636                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5637             }
5638             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5639         };
5640         var body;
5641         // branched to use + in gecko and [].join() in others
5642         if(Roo.isGecko){
5643             body = "this.compiled = function(values){ return '" +
5644                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5645                     "';};";
5646         }else{
5647             body = ["this.compiled = function(values){ return ['"];
5648             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5649             body.push("'].join('');};");
5650             body = body.join('');
5651         }
5652         /**
5653          * eval:var:values
5654          * eval:var:fm
5655          */
5656         eval(body);
5657         return this;
5658     },
5659     
5660     // private function used to call members
5661     call : function(fnName, value, allValues){
5662         return this[fnName](value, allValues);
5663     },
5664     
5665     /**
5666      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5667      * @param {String/HTMLElement/Roo.Element} el The context element
5668      * @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'})
5669      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5670      * @return {HTMLElement/Roo.Element} The new node or Element
5671      */
5672     insertFirst: function(el, values, returnElement){
5673         return this.doInsert('afterBegin', el, values, returnElement);
5674     },
5675
5676     /**
5677      * Applies the supplied values to the template and inserts the new node(s) before el.
5678      * @param {String/HTMLElement/Roo.Element} el The context element
5679      * @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'})
5680      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5681      * @return {HTMLElement/Roo.Element} The new node or Element
5682      */
5683     insertBefore: function(el, values, returnElement){
5684         return this.doInsert('beforeBegin', el, values, returnElement);
5685     },
5686
5687     /**
5688      * Applies the supplied values to the template and inserts the new node(s) after el.
5689      * @param {String/HTMLElement/Roo.Element} el The context element
5690      * @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'})
5691      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5692      * @return {HTMLElement/Roo.Element} The new node or Element
5693      */
5694     insertAfter : function(el, values, returnElement){
5695         return this.doInsert('afterEnd', el, values, returnElement);
5696     },
5697     
5698     /**
5699      * Applies the supplied values to the template and appends the new node(s) to el.
5700      * @param {String/HTMLElement/Roo.Element} el The context element
5701      * @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'})
5702      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5703      * @return {HTMLElement/Roo.Element} The new node or Element
5704      */
5705     append : function(el, values, returnElement){
5706         return this.doInsert('beforeEnd', el, values, returnElement);
5707     },
5708
5709     doInsert : function(where, el, values, returnEl){
5710         el = Roo.getDom(el);
5711         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5712         return returnEl ? Roo.get(newNode, true) : newNode;
5713     },
5714
5715     /**
5716      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5717      * @param {String/HTMLElement/Roo.Element} el The context element
5718      * @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'})
5719      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5720      * @return {HTMLElement/Roo.Element} The new node or Element
5721      */
5722     overwrite : function(el, values, returnElement){
5723         el = Roo.getDom(el);
5724         el.innerHTML = this.applyTemplate(values);
5725         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5726     }
5727 };
5728 /**
5729  * Alias for {@link #applyTemplate}
5730  * @method
5731  */
5732 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5733
5734 // backwards compat
5735 Roo.DomHelper.Template = Roo.Template;
5736
5737 /**
5738  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5739  * @param {String/HTMLElement} el A DOM element or its id
5740  * @returns {Roo.Template} The created template
5741  * @static
5742  */
5743 Roo.Template.from = function(el){
5744     el = Roo.getDom(el);
5745     return new Roo.Template(el.value || el.innerHTML);
5746 };/*
5747  * Based on:
5748  * Ext JS Library 1.1.1
5749  * Copyright(c) 2006-2007, Ext JS, LLC.
5750  *
5751  * Originally Released Under LGPL - original licence link has changed is not relivant.
5752  *
5753  * Fork - LGPL
5754  * <script type="text/javascript">
5755  */
5756  
5757
5758 /*
5759  * This is code is also distributed under MIT license for use
5760  * with jQuery and prototype JavaScript libraries.
5761  */
5762 /**
5763  * @class Roo.DomQuery
5764 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).
5765 <p>
5766 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>
5767
5768 <p>
5769 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.
5770 </p>
5771 <h4>Element Selectors:</h4>
5772 <ul class="list">
5773     <li> <b>*</b> any element</li>
5774     <li> <b>E</b> an element with the tag E</li>
5775     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5776     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5777     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5778     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5779 </ul>
5780 <h4>Attribute Selectors:</h4>
5781 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5782 <ul class="list">
5783     <li> <b>E[foo]</b> has an attribute "foo"</li>
5784     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5785     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5786     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5787     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5788     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5789     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5790 </ul>
5791 <h4>Pseudo Classes:</h4>
5792 <ul class="list">
5793     <li> <b>E:first-child</b> E is the first child of its parent</li>
5794     <li> <b>E:last-child</b> E is the last child of its parent</li>
5795     <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>
5796     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5797     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5798     <li> <b>E:only-child</b> E is the only child of its parent</li>
5799     <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>
5800     <li> <b>E:first</b> the first E in the resultset</li>
5801     <li> <b>E:last</b> the last E in the resultset</li>
5802     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5803     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5804     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5805     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5806     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5807     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5808     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5809     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5810     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5811 </ul>
5812 <h4>CSS Value Selectors:</h4>
5813 <ul class="list">
5814     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5815     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5816     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5817     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5818     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5819     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5820 </ul>
5821  * @static
5822  */
5823 Roo.DomQuery = function(){
5824     var cache = {}, simpleCache = {}, valueCache = {};
5825     var nonSpace = /\S/;
5826     var trimRe = /^\s+|\s+$/g;
5827     var tplRe = /\{(\d+)\}/g;
5828     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5829     var tagTokenRe = /^(#)?([\w-\*]+)/;
5830     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5831
5832     function child(p, index){
5833         var i = 0;
5834         var n = p.firstChild;
5835         while(n){
5836             if(n.nodeType == 1){
5837                if(++i == index){
5838                    return n;
5839                }
5840             }
5841             n = n.nextSibling;
5842         }
5843         return null;
5844     };
5845
5846     function next(n){
5847         while((n = n.nextSibling) && n.nodeType != 1);
5848         return n;
5849     };
5850
5851     function prev(n){
5852         while((n = n.previousSibling) && n.nodeType != 1);
5853         return n;
5854     };
5855
5856     function children(d){
5857         var n = d.firstChild, ni = -1;
5858             while(n){
5859                 var nx = n.nextSibling;
5860                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5861                     d.removeChild(n);
5862                 }else{
5863                     n.nodeIndex = ++ni;
5864                 }
5865                 n = nx;
5866             }
5867             return this;
5868         };
5869
5870     function byClassName(c, a, v){
5871         if(!v){
5872             return c;
5873         }
5874         var r = [], ri = -1, cn;
5875         for(var i = 0, ci; ci = c[i]; i++){
5876             
5877             
5878             if((' '+
5879                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5880                  +' ').indexOf(v) != -1){
5881                 r[++ri] = ci;
5882             }
5883         }
5884         return r;
5885     };
5886
5887     function attrValue(n, attr){
5888         if(!n.tagName && typeof n.length != "undefined"){
5889             n = n[0];
5890         }
5891         if(!n){
5892             return null;
5893         }
5894         if(attr == "for"){
5895             return n.htmlFor;
5896         }
5897         if(attr == "class" || attr == "className"){
5898             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5899         }
5900         return n.getAttribute(attr) || n[attr];
5901
5902     };
5903
5904     function getNodes(ns, mode, tagName){
5905         var result = [], ri = -1, cs;
5906         if(!ns){
5907             return result;
5908         }
5909         tagName = tagName || "*";
5910         if(typeof ns.getElementsByTagName != "undefined"){
5911             ns = [ns];
5912         }
5913         if(!mode){
5914             for(var i = 0, ni; ni = ns[i]; i++){
5915                 cs = ni.getElementsByTagName(tagName);
5916                 for(var j = 0, ci; ci = cs[j]; j++){
5917                     result[++ri] = ci;
5918                 }
5919             }
5920         }else if(mode == "/" || mode == ">"){
5921             var utag = tagName.toUpperCase();
5922             for(var i = 0, ni, cn; ni = ns[i]; i++){
5923                 cn = ni.children || ni.childNodes;
5924                 for(var j = 0, cj; cj = cn[j]; j++){
5925                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5926                         result[++ri] = cj;
5927                     }
5928                 }
5929             }
5930         }else if(mode == "+"){
5931             var utag = tagName.toUpperCase();
5932             for(var i = 0, n; n = ns[i]; i++){
5933                 while((n = n.nextSibling) && n.nodeType != 1);
5934                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5935                     result[++ri] = n;
5936                 }
5937             }
5938         }else if(mode == "~"){
5939             for(var i = 0, n; n = ns[i]; i++){
5940                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5941                 if(n){
5942                     result[++ri] = n;
5943                 }
5944             }
5945         }
5946         return result;
5947     };
5948
5949     function concat(a, b){
5950         if(b.slice){
5951             return a.concat(b);
5952         }
5953         for(var i = 0, l = b.length; i < l; i++){
5954             a[a.length] = b[i];
5955         }
5956         return a;
5957     }
5958
5959     function byTag(cs, tagName){
5960         if(cs.tagName || cs == document){
5961             cs = [cs];
5962         }
5963         if(!tagName){
5964             return cs;
5965         }
5966         var r = [], ri = -1;
5967         tagName = tagName.toLowerCase();
5968         for(var i = 0, ci; ci = cs[i]; i++){
5969             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5970                 r[++ri] = ci;
5971             }
5972         }
5973         return r;
5974     };
5975
5976     function byId(cs, attr, id){
5977         if(cs.tagName || cs == document){
5978             cs = [cs];
5979         }
5980         if(!id){
5981             return cs;
5982         }
5983         var r = [], ri = -1;
5984         for(var i = 0,ci; ci = cs[i]; i++){
5985             if(ci && ci.id == id){
5986                 r[++ri] = ci;
5987                 return r;
5988             }
5989         }
5990         return r;
5991     };
5992
5993     function byAttribute(cs, attr, value, op, custom){
5994         var r = [], ri = -1, st = custom=="{";
5995         var f = Roo.DomQuery.operators[op];
5996         for(var i = 0, ci; ci = cs[i]; i++){
5997             var a;
5998             if(st){
5999                 a = Roo.DomQuery.getStyle(ci, attr);
6000             }
6001             else if(attr == "class" || attr == "className"){
6002                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6003             }else if(attr == "for"){
6004                 a = ci.htmlFor;
6005             }else if(attr == "href"){
6006                 a = ci.getAttribute("href", 2);
6007             }else{
6008                 a = ci.getAttribute(attr);
6009             }
6010             if((f && f(a, value)) || (!f && a)){
6011                 r[++ri] = ci;
6012             }
6013         }
6014         return r;
6015     };
6016
6017     function byPseudo(cs, name, value){
6018         return Roo.DomQuery.pseudos[name](cs, value);
6019     };
6020
6021     // This is for IE MSXML which does not support expandos.
6022     // IE runs the same speed using setAttribute, however FF slows way down
6023     // and Safari completely fails so they need to continue to use expandos.
6024     var isIE = window.ActiveXObject ? true : false;
6025
6026     // this eval is stop the compressor from
6027     // renaming the variable to something shorter
6028     
6029     /** eval:var:batch */
6030     var batch = 30803; 
6031
6032     var key = 30803;
6033
6034     function nodupIEXml(cs){
6035         var d = ++key;
6036         cs[0].setAttribute("_nodup", d);
6037         var r = [cs[0]];
6038         for(var i = 1, len = cs.length; i < len; i++){
6039             var c = cs[i];
6040             if(!c.getAttribute("_nodup") != d){
6041                 c.setAttribute("_nodup", d);
6042                 r[r.length] = c;
6043             }
6044         }
6045         for(var i = 0, len = cs.length; i < len; i++){
6046             cs[i].removeAttribute("_nodup");
6047         }
6048         return r;
6049     }
6050
6051     function nodup(cs){
6052         if(!cs){
6053             return [];
6054         }
6055         var len = cs.length, c, i, r = cs, cj, ri = -1;
6056         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6057             return cs;
6058         }
6059         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6060             return nodupIEXml(cs);
6061         }
6062         var d = ++key;
6063         cs[0]._nodup = d;
6064         for(i = 1; c = cs[i]; i++){
6065             if(c._nodup != d){
6066                 c._nodup = d;
6067             }else{
6068                 r = [];
6069                 for(var j = 0; j < i; j++){
6070                     r[++ri] = cs[j];
6071                 }
6072                 for(j = i+1; cj = cs[j]; j++){
6073                     if(cj._nodup != d){
6074                         cj._nodup = d;
6075                         r[++ri] = cj;
6076                     }
6077                 }
6078                 return r;
6079             }
6080         }
6081         return r;
6082     }
6083
6084     function quickDiffIEXml(c1, c2){
6085         var d = ++key;
6086         for(var i = 0, len = c1.length; i < len; i++){
6087             c1[i].setAttribute("_qdiff", d);
6088         }
6089         var r = [];
6090         for(var i = 0, len = c2.length; i < len; i++){
6091             if(c2[i].getAttribute("_qdiff") != d){
6092                 r[r.length] = c2[i];
6093             }
6094         }
6095         for(var i = 0, len = c1.length; i < len; i++){
6096            c1[i].removeAttribute("_qdiff");
6097         }
6098         return r;
6099     }
6100
6101     function quickDiff(c1, c2){
6102         var len1 = c1.length;
6103         if(!len1){
6104             return c2;
6105         }
6106         if(isIE && c1[0].selectSingleNode){
6107             return quickDiffIEXml(c1, c2);
6108         }
6109         var d = ++key;
6110         for(var i = 0; i < len1; i++){
6111             c1[i]._qdiff = d;
6112         }
6113         var r = [];
6114         for(var i = 0, len = c2.length; i < len; i++){
6115             if(c2[i]._qdiff != d){
6116                 r[r.length] = c2[i];
6117             }
6118         }
6119         return r;
6120     }
6121
6122     function quickId(ns, mode, root, id){
6123         if(ns == root){
6124            var d = root.ownerDocument || root;
6125            return d.getElementById(id);
6126         }
6127         ns = getNodes(ns, mode, "*");
6128         return byId(ns, null, id);
6129     }
6130
6131     return {
6132         getStyle : function(el, name){
6133             return Roo.fly(el).getStyle(name);
6134         },
6135         /**
6136          * Compiles a selector/xpath query into a reusable function. The returned function
6137          * takes one parameter "root" (optional), which is the context node from where the query should start.
6138          * @param {String} selector The selector/xpath query
6139          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6140          * @return {Function}
6141          */
6142         compile : function(path, type){
6143             type = type || "select";
6144             
6145             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6146             var q = path, mode, lq;
6147             var tk = Roo.DomQuery.matchers;
6148             var tklen = tk.length;
6149             var mm;
6150
6151             // accept leading mode switch
6152             var lmode = q.match(modeRe);
6153             if(lmode && lmode[1]){
6154                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6155                 q = q.replace(lmode[1], "");
6156             }
6157             // strip leading slashes
6158             while(path.substr(0, 1)=="/"){
6159                 path = path.substr(1);
6160             }
6161
6162             while(q && lq != q){
6163                 lq = q;
6164                 var tm = q.match(tagTokenRe);
6165                 if(type == "select"){
6166                     if(tm){
6167                         if(tm[1] == "#"){
6168                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6169                         }else{
6170                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6171                         }
6172                         q = q.replace(tm[0], "");
6173                     }else if(q.substr(0, 1) != '@'){
6174                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6175                     }
6176                 }else{
6177                     if(tm){
6178                         if(tm[1] == "#"){
6179                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6180                         }else{
6181                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6182                         }
6183                         q = q.replace(tm[0], "");
6184                     }
6185                 }
6186                 while(!(mm = q.match(modeRe))){
6187                     var matched = false;
6188                     for(var j = 0; j < tklen; j++){
6189                         var t = tk[j];
6190                         var m = q.match(t.re);
6191                         if(m){
6192                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6193                                                     return m[i];
6194                                                 });
6195                             q = q.replace(m[0], "");
6196                             matched = true;
6197                             break;
6198                         }
6199                     }
6200                     // prevent infinite loop on bad selector
6201                     if(!matched){
6202                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6203                     }
6204                 }
6205                 if(mm[1]){
6206                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6207                     q = q.replace(mm[1], "");
6208                 }
6209             }
6210             fn[fn.length] = "return nodup(n);\n}";
6211             
6212              /** 
6213               * list of variables that need from compression as they are used by eval.
6214              *  eval:var:batch 
6215              *  eval:var:nodup
6216              *  eval:var:byTag
6217              *  eval:var:ById
6218              *  eval:var:getNodes
6219              *  eval:var:quickId
6220              *  eval:var:mode
6221              *  eval:var:root
6222              *  eval:var:n
6223              *  eval:var:byClassName
6224              *  eval:var:byPseudo
6225              *  eval:var:byAttribute
6226              *  eval:var:attrValue
6227              * 
6228              **/ 
6229             eval(fn.join(""));
6230             return f;
6231         },
6232
6233         /**
6234          * Selects a group of elements.
6235          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6236          * @param {Node} root (optional) The start of the query (defaults to document).
6237          * @return {Array}
6238          */
6239         select : function(path, root, type){
6240             if(!root || root == document){
6241                 root = document;
6242             }
6243             if(typeof root == "string"){
6244                 root = document.getElementById(root);
6245             }
6246             var paths = path.split(",");
6247             var results = [];
6248             for(var i = 0, len = paths.length; i < len; i++){
6249                 var p = paths[i].replace(trimRe, "");
6250                 if(!cache[p]){
6251                     cache[p] = Roo.DomQuery.compile(p);
6252                     if(!cache[p]){
6253                         throw p + " is not a valid selector";
6254                     }
6255                 }
6256                 var result = cache[p](root);
6257                 if(result && result != document){
6258                     results = results.concat(result);
6259                 }
6260             }
6261             if(paths.length > 1){
6262                 return nodup(results);
6263             }
6264             return results;
6265         },
6266
6267         /**
6268          * Selects a single element.
6269          * @param {String} selector The selector/xpath query
6270          * @param {Node} root (optional) The start of the query (defaults to document).
6271          * @return {Element}
6272          */
6273         selectNode : function(path, root){
6274             return Roo.DomQuery.select(path, root)[0];
6275         },
6276
6277         /**
6278          * Selects the value of a node, optionally replacing null with the defaultValue.
6279          * @param {String} selector The selector/xpath query
6280          * @param {Node} root (optional) The start of the query (defaults to document).
6281          * @param {String} defaultValue
6282          */
6283         selectValue : function(path, root, defaultValue){
6284             path = path.replace(trimRe, "");
6285             if(!valueCache[path]){
6286                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6287             }
6288             var n = valueCache[path](root);
6289             n = n[0] ? n[0] : n;
6290             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6291             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6292         },
6293
6294         /**
6295          * Selects the value of a node, parsing integers and floats.
6296          * @param {String} selector The selector/xpath query
6297          * @param {Node} root (optional) The start of the query (defaults to document).
6298          * @param {Number} defaultValue
6299          * @return {Number}
6300          */
6301         selectNumber : function(path, root, defaultValue){
6302             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6303             return parseFloat(v);
6304         },
6305
6306         /**
6307          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6308          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6309          * @param {String} selector The simple selector to test
6310          * @return {Boolean}
6311          */
6312         is : function(el, ss){
6313             if(typeof el == "string"){
6314                 el = document.getElementById(el);
6315             }
6316             var isArray = (el instanceof Array);
6317             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6318             return isArray ? (result.length == el.length) : (result.length > 0);
6319         },
6320
6321         /**
6322          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6323          * @param {Array} el An array of elements to filter
6324          * @param {String} selector The simple selector to test
6325          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6326          * the selector instead of the ones that match
6327          * @return {Array}
6328          */
6329         filter : function(els, ss, nonMatches){
6330             ss = ss.replace(trimRe, "");
6331             if(!simpleCache[ss]){
6332                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6333             }
6334             var result = simpleCache[ss](els);
6335             return nonMatches ? quickDiff(result, els) : result;
6336         },
6337
6338         /**
6339          * Collection of matching regular expressions and code snippets.
6340          */
6341         matchers : [{
6342                 re: /^\.([\w-]+)/,
6343                 select: 'n = byClassName(n, null, " {1} ");'
6344             }, {
6345                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6346                 select: 'n = byPseudo(n, "{1}", "{2}");'
6347             },{
6348                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6349                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6350             }, {
6351                 re: /^#([\w-]+)/,
6352                 select: 'n = byId(n, null, "{1}");'
6353             },{
6354                 re: /^@([\w-]+)/,
6355                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6356             }
6357         ],
6358
6359         /**
6360          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6361          * 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;.
6362          */
6363         operators : {
6364             "=" : function(a, v){
6365                 return a == v;
6366             },
6367             "!=" : function(a, v){
6368                 return a != v;
6369             },
6370             "^=" : function(a, v){
6371                 return a && a.substr(0, v.length) == v;
6372             },
6373             "$=" : function(a, v){
6374                 return a && a.substr(a.length-v.length) == v;
6375             },
6376             "*=" : function(a, v){
6377                 return a && a.indexOf(v) !== -1;
6378             },
6379             "%=" : function(a, v){
6380                 return (a % v) == 0;
6381             },
6382             "|=" : function(a, v){
6383                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6384             },
6385             "~=" : function(a, v){
6386                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6387             }
6388         },
6389
6390         /**
6391          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6392          * and the argument (if any) supplied in the selector.
6393          */
6394         pseudos : {
6395             "first-child" : function(c){
6396                 var r = [], ri = -1, n;
6397                 for(var i = 0, ci; ci = n = c[i]; i++){
6398                     while((n = n.previousSibling) && n.nodeType != 1);
6399                     if(!n){
6400                         r[++ri] = ci;
6401                     }
6402                 }
6403                 return r;
6404             },
6405
6406             "last-child" : function(c){
6407                 var r = [], ri = -1, n;
6408                 for(var i = 0, ci; ci = n = c[i]; i++){
6409                     while((n = n.nextSibling) && n.nodeType != 1);
6410                     if(!n){
6411                         r[++ri] = ci;
6412                     }
6413                 }
6414                 return r;
6415             },
6416
6417             "nth-child" : function(c, a) {
6418                 var r = [], ri = -1;
6419                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6420                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6421                 for(var i = 0, n; n = c[i]; i++){
6422                     var pn = n.parentNode;
6423                     if (batch != pn._batch) {
6424                         var j = 0;
6425                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6426                             if(cn.nodeType == 1){
6427                                cn.nodeIndex = ++j;
6428                             }
6429                         }
6430                         pn._batch = batch;
6431                     }
6432                     if (f == 1) {
6433                         if (l == 0 || n.nodeIndex == l){
6434                             r[++ri] = n;
6435                         }
6436                     } else if ((n.nodeIndex + l) % f == 0){
6437                         r[++ri] = n;
6438                     }
6439                 }
6440
6441                 return r;
6442             },
6443
6444             "only-child" : function(c){
6445                 var r = [], ri = -1;;
6446                 for(var i = 0, ci; ci = c[i]; i++){
6447                     if(!prev(ci) && !next(ci)){
6448                         r[++ri] = ci;
6449                     }
6450                 }
6451                 return r;
6452             },
6453
6454             "empty" : function(c){
6455                 var r = [], ri = -1;
6456                 for(var i = 0, ci; ci = c[i]; i++){
6457                     var cns = ci.childNodes, j = 0, cn, empty = true;
6458                     while(cn = cns[j]){
6459                         ++j;
6460                         if(cn.nodeType == 1 || cn.nodeType == 3){
6461                             empty = false;
6462                             break;
6463                         }
6464                     }
6465                     if(empty){
6466                         r[++ri] = ci;
6467                     }
6468                 }
6469                 return r;
6470             },
6471
6472             "contains" : function(c, v){
6473                 var r = [], ri = -1;
6474                 for(var i = 0, ci; ci = c[i]; i++){
6475                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6476                         r[++ri] = ci;
6477                     }
6478                 }
6479                 return r;
6480             },
6481
6482             "nodeValue" : function(c, v){
6483                 var r = [], ri = -1;
6484                 for(var i = 0, ci; ci = c[i]; i++){
6485                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6486                         r[++ri] = ci;
6487                     }
6488                 }
6489                 return r;
6490             },
6491
6492             "checked" : function(c){
6493                 var r = [], ri = -1;
6494                 for(var i = 0, ci; ci = c[i]; i++){
6495                     if(ci.checked == true){
6496                         r[++ri] = ci;
6497                     }
6498                 }
6499                 return r;
6500             },
6501
6502             "not" : function(c, ss){
6503                 return Roo.DomQuery.filter(c, ss, true);
6504             },
6505
6506             "odd" : function(c){
6507                 return this["nth-child"](c, "odd");
6508             },
6509
6510             "even" : function(c){
6511                 return this["nth-child"](c, "even");
6512             },
6513
6514             "nth" : function(c, a){
6515                 return c[a-1] || [];
6516             },
6517
6518             "first" : function(c){
6519                 return c[0] || [];
6520             },
6521
6522             "last" : function(c){
6523                 return c[c.length-1] || [];
6524             },
6525
6526             "has" : function(c, ss){
6527                 var s = Roo.DomQuery.select;
6528                 var r = [], ri = -1;
6529                 for(var i = 0, ci; ci = c[i]; i++){
6530                     if(s(ss, ci).length > 0){
6531                         r[++ri] = ci;
6532                     }
6533                 }
6534                 return r;
6535             },
6536
6537             "next" : function(c, ss){
6538                 var is = Roo.DomQuery.is;
6539                 var r = [], ri = -1;
6540                 for(var i = 0, ci; ci = c[i]; i++){
6541                     var n = next(ci);
6542                     if(n && is(n, ss)){
6543                         r[++ri] = ci;
6544                     }
6545                 }
6546                 return r;
6547             },
6548
6549             "prev" : function(c, ss){
6550                 var is = Roo.DomQuery.is;
6551                 var r = [], ri = -1;
6552                 for(var i = 0, ci; ci = c[i]; i++){
6553                     var n = prev(ci);
6554                     if(n && is(n, ss)){
6555                         r[++ri] = ci;
6556                     }
6557                 }
6558                 return r;
6559             }
6560         }
6561     };
6562 }();
6563
6564 /**
6565  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6566  * @param {String} path The selector/xpath query
6567  * @param {Node} root (optional) The start of the query (defaults to document).
6568  * @return {Array}
6569  * @member Roo
6570  * @method query
6571  */
6572 Roo.query = Roo.DomQuery.select;
6573 /*
6574  * Based on:
6575  * Ext JS Library 1.1.1
6576  * Copyright(c) 2006-2007, Ext JS, LLC.
6577  *
6578  * Originally Released Under LGPL - original licence link has changed is not relivant.
6579  *
6580  * Fork - LGPL
6581  * <script type="text/javascript">
6582  */
6583
6584 /**
6585  * @class Roo.util.Observable
6586  * Base class that provides a common interface for publishing events. Subclasses are expected to
6587  * to have a property "events" with all the events defined.<br>
6588  * For example:
6589  * <pre><code>
6590  Employee = function(name){
6591     this.name = name;
6592     this.addEvents({
6593         "fired" : true,
6594         "quit" : true
6595     });
6596  }
6597  Roo.extend(Employee, Roo.util.Observable);
6598 </code></pre>
6599  * @param {Object} config properties to use (incuding events / listeners)
6600  */
6601
6602 Roo.util.Observable = function(cfg){
6603     
6604     cfg = cfg|| {};
6605     this.addEvents(cfg.events || {});
6606     if (cfg.events) {
6607         delete cfg.events; // make sure
6608     }
6609      
6610     Roo.apply(this, cfg);
6611     
6612     if(this.listeners){
6613         this.on(this.listeners);
6614         delete this.listeners;
6615     }
6616 };
6617 Roo.util.Observable.prototype = {
6618     /** 
6619  * @cfg {Object} listeners  list of events and functions to call for this object, 
6620  * For example :
6621  * <pre><code>
6622     listeners :  { 
6623        'click' : function(e) {
6624            ..... 
6625         } ,
6626         .... 
6627     } 
6628   </code></pre>
6629  */
6630     
6631     
6632     /**
6633      * Fires the specified event with the passed parameters (minus the event name).
6634      * @param {String} eventName
6635      * @param {Object...} args Variable number of parameters are passed to handlers
6636      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6637      */
6638     fireEvent : function(){
6639         var ce = this.events[arguments[0].toLowerCase()];
6640         if(typeof ce == "object"){
6641             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6642         }else{
6643             return true;
6644         }
6645     },
6646
6647     // private
6648     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6649
6650     /**
6651      * Appends an event handler to this component
6652      * @param {String}   eventName The type of event to listen for
6653      * @param {Function} handler The method the event invokes
6654      * @param {Object}   scope (optional) The scope in which to execute the handler
6655      * function. The handler function's "this" context.
6656      * @param {Object}   options (optional) An object containing handler configuration
6657      * properties. This may contain any of the following properties:<ul>
6658      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6659      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6660      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6661      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6662      * by the specified number of milliseconds. If the event fires again within that time, the original
6663      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6664      * </ul><br>
6665      * <p>
6666      * <b>Combining Options</b><br>
6667      * Using the options argument, it is possible to combine different types of listeners:<br>
6668      * <br>
6669      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6670                 <pre><code>
6671                 el.on('click', this.onClick, this, {
6672                         single: true,
6673                 delay: 100,
6674                 forumId: 4
6675                 });
6676                 </code></pre>
6677      * <p>
6678      * <b>Attaching multiple handlers in 1 call</b><br>
6679      * The method also allows for a single argument to be passed which is a config object containing properties
6680      * which specify multiple handlers.
6681      * <pre><code>
6682                 el.on({
6683                         'click': {
6684                         fn: this.onClick,
6685                         scope: this,
6686                         delay: 100
6687                 }, 
6688                 'mouseover': {
6689                         fn: this.onMouseOver,
6690                         scope: this
6691                 },
6692                 'mouseout': {
6693                         fn: this.onMouseOut,
6694                         scope: this
6695                 }
6696                 });
6697                 </code></pre>
6698      * <p>
6699      * Or a shorthand syntax which passes the same scope object to all handlers:
6700         <pre><code>
6701                 el.on({
6702                         'click': this.onClick,
6703                 'mouseover': this.onMouseOver,
6704                 'mouseout': this.onMouseOut,
6705                 scope: this
6706                 });
6707                 </code></pre>
6708      */
6709     addListener : function(eventName, fn, scope, o){
6710         if(typeof eventName == "object"){
6711             o = eventName;
6712             for(var e in o){
6713                 if(this.filterOptRe.test(e)){
6714                     continue;
6715                 }
6716                 if(typeof o[e] == "function"){
6717                     // shared options
6718                     this.addListener(e, o[e], o.scope,  o);
6719                 }else{
6720                     // individual options
6721                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6722                 }
6723             }
6724             return;
6725         }
6726         o = (!o || typeof o == "boolean") ? {} : o;
6727         eventName = eventName.toLowerCase();
6728         var ce = this.events[eventName] || true;
6729         if(typeof ce == "boolean"){
6730             ce = new Roo.util.Event(this, eventName);
6731             this.events[eventName] = ce;
6732         }
6733         ce.addListener(fn, scope, o);
6734     },
6735
6736     /**
6737      * Removes a listener
6738      * @param {String}   eventName     The type of event to listen for
6739      * @param {Function} handler        The handler to remove
6740      * @param {Object}   scope  (optional) The scope (this object) for the handler
6741      */
6742     removeListener : function(eventName, fn, scope){
6743         var ce = this.events[eventName.toLowerCase()];
6744         if(typeof ce == "object"){
6745             ce.removeListener(fn, scope);
6746         }
6747     },
6748
6749     /**
6750      * Removes all listeners for this object
6751      */
6752     purgeListeners : function(){
6753         for(var evt in this.events){
6754             if(typeof this.events[evt] == "object"){
6755                  this.events[evt].clearListeners();
6756             }
6757         }
6758     },
6759
6760     relayEvents : function(o, events){
6761         var createHandler = function(ename){
6762             return function(){
6763                  
6764                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6765             };
6766         };
6767         for(var i = 0, len = events.length; i < len; i++){
6768             var ename = events[i];
6769             if(!this.events[ename]){
6770                 this.events[ename] = true;
6771             };
6772             o.on(ename, createHandler(ename), this);
6773         }
6774     },
6775
6776     /**
6777      * Used to define events on this Observable
6778      * @param {Object} object The object with the events defined
6779      */
6780     addEvents : function(o){
6781         if(!this.events){
6782             this.events = {};
6783         }
6784         Roo.applyIf(this.events, o);
6785     },
6786
6787     /**
6788      * Checks to see if this object has any listeners for a specified event
6789      * @param {String} eventName The name of the event to check for
6790      * @return {Boolean} True if the event is being listened for, else false
6791      */
6792     hasListener : function(eventName){
6793         var e = this.events[eventName];
6794         return typeof e == "object" && e.listeners.length > 0;
6795     }
6796 };
6797 /**
6798  * Appends an event handler to this element (shorthand for addListener)
6799  * @param {String}   eventName     The type of event to listen for
6800  * @param {Function} handler        The method the event invokes
6801  * @param {Object}   scope (optional) The scope in which to execute the handler
6802  * function. The handler function's "this" context.
6803  * @param {Object}   options  (optional)
6804  * @method
6805  */
6806 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6807 /**
6808  * Removes a listener (shorthand for removeListener)
6809  * @param {String}   eventName     The type of event to listen for
6810  * @param {Function} handler        The handler to remove
6811  * @param {Object}   scope  (optional) The scope (this object) for the handler
6812  * @method
6813  */
6814 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6815
6816 /**
6817  * Starts capture on the specified Observable. All events will be passed
6818  * to the supplied function with the event name + standard signature of the event
6819  * <b>before</b> the event is fired. If the supplied function returns false,
6820  * the event will not fire.
6821  * @param {Observable} o The Observable to capture
6822  * @param {Function} fn The function to call
6823  * @param {Object} scope (optional) The scope (this object) for the fn
6824  * @static
6825  */
6826 Roo.util.Observable.capture = function(o, fn, scope){
6827     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6828 };
6829
6830 /**
6831  * Removes <b>all</b> added captures from the Observable.
6832  * @param {Observable} o The Observable to release
6833  * @static
6834  */
6835 Roo.util.Observable.releaseCapture = function(o){
6836     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6837 };
6838
6839 (function(){
6840
6841     var createBuffered = function(h, o, scope){
6842         var task = new Roo.util.DelayedTask();
6843         return function(){
6844             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6845         };
6846     };
6847
6848     var createSingle = function(h, e, fn, scope){
6849         return function(){
6850             e.removeListener(fn, scope);
6851             return h.apply(scope, arguments);
6852         };
6853     };
6854
6855     var createDelayed = function(h, o, scope){
6856         return function(){
6857             var args = Array.prototype.slice.call(arguments, 0);
6858             setTimeout(function(){
6859                 h.apply(scope, args);
6860             }, o.delay || 10);
6861         };
6862     };
6863
6864     Roo.util.Event = function(obj, name){
6865         this.name = name;
6866         this.obj = obj;
6867         this.listeners = [];
6868     };
6869
6870     Roo.util.Event.prototype = {
6871         addListener : function(fn, scope, options){
6872             var o = options || {};
6873             scope = scope || this.obj;
6874             if(!this.isListening(fn, scope)){
6875                 var l = {fn: fn, scope: scope, options: o};
6876                 var h = fn;
6877                 if(o.delay){
6878                     h = createDelayed(h, o, scope);
6879                 }
6880                 if(o.single){
6881                     h = createSingle(h, this, fn, scope);
6882                 }
6883                 if(o.buffer){
6884                     h = createBuffered(h, o, scope);
6885                 }
6886                 l.fireFn = h;
6887                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6888                     this.listeners.push(l);
6889                 }else{
6890                     this.listeners = this.listeners.slice(0);
6891                     this.listeners.push(l);
6892                 }
6893             }
6894         },
6895
6896         findListener : function(fn, scope){
6897             scope = scope || this.obj;
6898             var ls = this.listeners;
6899             for(var i = 0, len = ls.length; i < len; i++){
6900                 var l = ls[i];
6901                 if(l.fn == fn && l.scope == scope){
6902                     return i;
6903                 }
6904             }
6905             return -1;
6906         },
6907
6908         isListening : function(fn, scope){
6909             return this.findListener(fn, scope) != -1;
6910         },
6911
6912         removeListener : function(fn, scope){
6913             var index;
6914             if((index = this.findListener(fn, scope)) != -1){
6915                 if(!this.firing){
6916                     this.listeners.splice(index, 1);
6917                 }else{
6918                     this.listeners = this.listeners.slice(0);
6919                     this.listeners.splice(index, 1);
6920                 }
6921                 return true;
6922             }
6923             return false;
6924         },
6925
6926         clearListeners : function(){
6927             this.listeners = [];
6928         },
6929
6930         fire : function(){
6931             var ls = this.listeners, scope, len = ls.length;
6932             if(len > 0){
6933                 this.firing = true;
6934                 var args = Array.prototype.slice.call(arguments, 0);                
6935                 for(var i = 0; i < len; i++){
6936                     var l = ls[i];
6937                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6938                         this.firing = false;
6939                         return false;
6940                     }
6941                 }
6942                 this.firing = false;
6943             }
6944             return true;
6945         }
6946     };
6947 })();/*
6948  * RooJS Library 
6949  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6950  *
6951  * Licence LGPL 
6952  *
6953  */
6954  
6955 /**
6956  * @class Roo.Document
6957  * @extends Roo.util.Observable
6958  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6959  * 
6960  * @param {Object} config the methods and properties of the 'base' class for the application.
6961  * 
6962  *  Generic Page handler - implement this to start your app..
6963  * 
6964  * eg.
6965  *  MyProject = new Roo.Document({
6966         events : {
6967             'load' : true // your events..
6968         },
6969         listeners : {
6970             'ready' : function() {
6971                 // fired on Roo.onReady()
6972             }
6973         }
6974  * 
6975  */
6976 Roo.Document = function(cfg) {
6977      
6978     this.addEvents({ 
6979         'ready' : true
6980     });
6981     Roo.util.Observable.call(this,cfg);
6982     
6983     var _this = this;
6984     
6985     Roo.onReady(function() {
6986         _this.fireEvent('ready');
6987     },null,false);
6988     
6989     
6990 }
6991
6992 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6993  * Based on:
6994  * Ext JS Library 1.1.1
6995  * Copyright(c) 2006-2007, Ext JS, LLC.
6996  *
6997  * Originally Released Under LGPL - original licence link has changed is not relivant.
6998  *
6999  * Fork - LGPL
7000  * <script type="text/javascript">
7001  */
7002
7003 /**
7004  * @class Roo.EventManager
7005  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7006  * several useful events directly.
7007  * See {@link Roo.EventObject} for more details on normalized event objects.
7008  * @static
7009  */
7010 Roo.EventManager = function(){
7011     var docReadyEvent, docReadyProcId, docReadyState = false;
7012     var resizeEvent, resizeTask, textEvent, textSize;
7013     var E = Roo.lib.Event;
7014     var D = Roo.lib.Dom;
7015
7016     
7017     
7018
7019     var fireDocReady = function(){
7020         if(!docReadyState){
7021             docReadyState = true;
7022             Roo.isReady = true;
7023             if(docReadyProcId){
7024                 clearInterval(docReadyProcId);
7025             }
7026             if(Roo.isGecko || Roo.isOpera) {
7027                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7028             }
7029             if(Roo.isIE){
7030                 var defer = document.getElementById("ie-deferred-loader");
7031                 if(defer){
7032                     defer.onreadystatechange = null;
7033                     defer.parentNode.removeChild(defer);
7034                 }
7035             }
7036             if(docReadyEvent){
7037                 docReadyEvent.fire();
7038                 docReadyEvent.clearListeners();
7039             }
7040         }
7041     };
7042     
7043     var initDocReady = function(){
7044         docReadyEvent = new Roo.util.Event();
7045         if(Roo.isGecko || Roo.isOpera) {
7046             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7047         }else if(Roo.isIE){
7048             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7049             var defer = document.getElementById("ie-deferred-loader");
7050             defer.onreadystatechange = function(){
7051                 if(this.readyState == "complete"){
7052                     fireDocReady();
7053                 }
7054             };
7055         }else if(Roo.isSafari){ 
7056             docReadyProcId = setInterval(function(){
7057                 var rs = document.readyState;
7058                 if(rs == "complete") {
7059                     fireDocReady();     
7060                  }
7061             }, 10);
7062         }
7063         // no matter what, make sure it fires on load
7064         E.on(window, "load", fireDocReady);
7065     };
7066
7067     var createBuffered = function(h, o){
7068         var task = new Roo.util.DelayedTask(h);
7069         return function(e){
7070             // create new event object impl so new events don't wipe out properties
7071             e = new Roo.EventObjectImpl(e);
7072             task.delay(o.buffer, h, null, [e]);
7073         };
7074     };
7075
7076     var createSingle = function(h, el, ename, fn){
7077         return function(e){
7078             Roo.EventManager.removeListener(el, ename, fn);
7079             h(e);
7080         };
7081     };
7082
7083     var createDelayed = function(h, o){
7084         return function(e){
7085             // create new event object impl so new events don't wipe out properties
7086             e = new Roo.EventObjectImpl(e);
7087             setTimeout(function(){
7088                 h(e);
7089             }, o.delay || 10);
7090         };
7091     };
7092     var transitionEndVal = false;
7093     
7094     var transitionEnd = function()
7095     {
7096         if (transitionEndVal) {
7097             return transitionEndVal;
7098         }
7099         var el = document.createElement('div');
7100
7101         var transEndEventNames = {
7102             WebkitTransition : 'webkitTransitionEnd',
7103             MozTransition    : 'transitionend',
7104             OTransition      : 'oTransitionEnd otransitionend',
7105             transition       : 'transitionend'
7106         };
7107     
7108         for (var name in transEndEventNames) {
7109             if (el.style[name] !== undefined) {
7110                 transitionEndVal = transEndEventNames[name];
7111                 return  transitionEndVal ;
7112             }
7113         }
7114     }
7115     
7116   
7117
7118     var listen = function(element, ename, opt, fn, scope)
7119     {
7120         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7121         fn = fn || o.fn; scope = scope || o.scope;
7122         var el = Roo.getDom(element);
7123         
7124         
7125         if(!el){
7126             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7127         }
7128         
7129         if (ename == 'transitionend') {
7130             ename = transitionEnd();
7131         }
7132         var h = function(e){
7133             e = Roo.EventObject.setEvent(e);
7134             var t;
7135             if(o.delegate){
7136                 t = e.getTarget(o.delegate, el);
7137                 if(!t){
7138                     return;
7139                 }
7140             }else{
7141                 t = e.target;
7142             }
7143             if(o.stopEvent === true){
7144                 e.stopEvent();
7145             }
7146             if(o.preventDefault === true){
7147                e.preventDefault();
7148             }
7149             if(o.stopPropagation === true){
7150                 e.stopPropagation();
7151             }
7152
7153             if(o.normalized === false){
7154                 e = e.browserEvent;
7155             }
7156
7157             fn.call(scope || el, e, t, o);
7158         };
7159         if(o.delay){
7160             h = createDelayed(h, o);
7161         }
7162         if(o.single){
7163             h = createSingle(h, el, ename, fn);
7164         }
7165         if(o.buffer){
7166             h = createBuffered(h, o);
7167         }
7168         
7169         fn._handlers = fn._handlers || [];
7170         
7171         
7172         fn._handlers.push([Roo.id(el), ename, h]);
7173         
7174         
7175          
7176         E.on(el, ename, h); // this adds the actuall listener to the object..
7177         
7178         
7179         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7180             el.addEventListener("DOMMouseScroll", h, false);
7181             E.on(window, 'unload', function(){
7182                 el.removeEventListener("DOMMouseScroll", h, false);
7183             });
7184         }
7185         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7186             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7187         }
7188         return h;
7189     };
7190
7191     var stopListening = function(el, ename, fn){
7192         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7193         if(hds){
7194             for(var i = 0, len = hds.length; i < len; i++){
7195                 var h = hds[i];
7196                 if(h[0] == id && h[1] == ename){
7197                     hd = h[2];
7198                     hds.splice(i, 1);
7199                     break;
7200                 }
7201             }
7202         }
7203         E.un(el, ename, hd);
7204         el = Roo.getDom(el);
7205         if(ename == "mousewheel" && el.addEventListener){
7206             el.removeEventListener("DOMMouseScroll", hd, false);
7207         }
7208         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7209             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7210         }
7211     };
7212
7213     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7214     
7215     var pub = {
7216         
7217         
7218         /** 
7219          * Fix for doc tools
7220          * @scope Roo.EventManager
7221          */
7222         
7223         
7224         /** 
7225          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7226          * object with a Roo.EventObject
7227          * @param {Function} fn        The method the event invokes
7228          * @param {Object}   scope    An object that becomes the scope of the handler
7229          * @param {boolean}  override If true, the obj passed in becomes
7230          *                             the execution scope of the listener
7231          * @return {Function} The wrapped function
7232          * @deprecated
7233          */
7234         wrap : function(fn, scope, override){
7235             return function(e){
7236                 Roo.EventObject.setEvent(e);
7237                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7238             };
7239         },
7240         
7241         /**
7242      * Appends an event handler to an element (shorthand for addListener)
7243      * @param {String/HTMLElement}   element        The html element or id to assign the
7244      * @param {String}   eventName The type of event to listen for
7245      * @param {Function} handler The method the event invokes
7246      * @param {Object}   scope (optional) The scope in which to execute the handler
7247      * function. The handler function's "this" context.
7248      * @param {Object}   options (optional) An object containing handler configuration
7249      * properties. This may contain any of the following properties:<ul>
7250      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7251      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7252      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7253      * <li>preventDefault {Boolean} True to prevent the default action</li>
7254      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7255      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7256      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7257      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7258      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7259      * by the specified number of milliseconds. If the event fires again within that time, the original
7260      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7261      * </ul><br>
7262      * <p>
7263      * <b>Combining Options</b><br>
7264      * Using the options argument, it is possible to combine different types of listeners:<br>
7265      * <br>
7266      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7267      * Code:<pre><code>
7268 el.on('click', this.onClick, this, {
7269     single: true,
7270     delay: 100,
7271     stopEvent : true,
7272     forumId: 4
7273 });</code></pre>
7274      * <p>
7275      * <b>Attaching multiple handlers in 1 call</b><br>
7276       * The method also allows for a single argument to be passed which is a config object containing properties
7277      * which specify multiple handlers.
7278      * <p>
7279      * Code:<pre><code>
7280 el.on({
7281     'click' : {
7282         fn: this.onClick
7283         scope: this,
7284         delay: 100
7285     },
7286     'mouseover' : {
7287         fn: this.onMouseOver
7288         scope: this
7289     },
7290     'mouseout' : {
7291         fn: this.onMouseOut
7292         scope: this
7293     }
7294 });</code></pre>
7295      * <p>
7296      * Or a shorthand syntax:<br>
7297      * Code:<pre><code>
7298 el.on({
7299     'click' : this.onClick,
7300     'mouseover' : this.onMouseOver,
7301     'mouseout' : this.onMouseOut
7302     scope: this
7303 });</code></pre>
7304      */
7305         addListener : function(element, eventName, fn, scope, options){
7306             if(typeof eventName == "object"){
7307                 var o = eventName;
7308                 for(var e in o){
7309                     if(propRe.test(e)){
7310                         continue;
7311                     }
7312                     if(typeof o[e] == "function"){
7313                         // shared options
7314                         listen(element, e, o, o[e], o.scope);
7315                     }else{
7316                         // individual options
7317                         listen(element, e, o[e]);
7318                     }
7319                 }
7320                 return;
7321             }
7322             return listen(element, eventName, options, fn, scope);
7323         },
7324         
7325         /**
7326          * Removes an event handler
7327          *
7328          * @param {String/HTMLElement}   element        The id or html element to remove the 
7329          *                             event from
7330          * @param {String}   eventName     The type of event
7331          * @param {Function} fn
7332          * @return {Boolean} True if a listener was actually removed
7333          */
7334         removeListener : function(element, eventName, fn){
7335             return stopListening(element, eventName, fn);
7336         },
7337         
7338         /**
7339          * Fires when the document is ready (before onload and before images are loaded). Can be 
7340          * accessed shorthanded Roo.onReady().
7341          * @param {Function} fn        The method the event invokes
7342          * @param {Object}   scope    An  object that becomes the scope of the handler
7343          * @param {boolean}  options
7344          */
7345         onDocumentReady : function(fn, scope, options){
7346             if(docReadyState){ // if it already fired
7347                 docReadyEvent.addListener(fn, scope, options);
7348                 docReadyEvent.fire();
7349                 docReadyEvent.clearListeners();
7350                 return;
7351             }
7352             if(!docReadyEvent){
7353                 initDocReady();
7354             }
7355             docReadyEvent.addListener(fn, scope, options);
7356         },
7357         
7358         /**
7359          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7360          * @param {Function} fn        The method the event invokes
7361          * @param {Object}   scope    An object that becomes the scope of the handler
7362          * @param {boolean}  options
7363          */
7364         onWindowResize : function(fn, scope, options)
7365         {
7366             if(!resizeEvent){
7367                 resizeEvent = new Roo.util.Event();
7368                 resizeTask = new Roo.util.DelayedTask(function(){
7369                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7370                 });
7371                 E.on(window, "resize", function()
7372                 {
7373                     if (Roo.isIE) {
7374                         resizeTask.delay(50);
7375                     } else {
7376                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7377                     }
7378                 });
7379             }
7380             resizeEvent.addListener(fn, scope, options);
7381         },
7382
7383         /**
7384          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7385          * @param {Function} fn        The method the event invokes
7386          * @param {Object}   scope    An object that becomes the scope of the handler
7387          * @param {boolean}  options
7388          */
7389         onTextResize : function(fn, scope, options){
7390             if(!textEvent){
7391                 textEvent = new Roo.util.Event();
7392                 var textEl = new Roo.Element(document.createElement('div'));
7393                 textEl.dom.className = 'x-text-resize';
7394                 textEl.dom.innerHTML = 'X';
7395                 textEl.appendTo(document.body);
7396                 textSize = textEl.dom.offsetHeight;
7397                 setInterval(function(){
7398                     if(textEl.dom.offsetHeight != textSize){
7399                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7400                     }
7401                 }, this.textResizeInterval);
7402             }
7403             textEvent.addListener(fn, scope, options);
7404         },
7405
7406         /**
7407          * Removes the passed window resize listener.
7408          * @param {Function} fn        The method the event invokes
7409          * @param {Object}   scope    The scope of handler
7410          */
7411         removeResizeListener : function(fn, scope){
7412             if(resizeEvent){
7413                 resizeEvent.removeListener(fn, scope);
7414             }
7415         },
7416
7417         // private
7418         fireResize : function(){
7419             if(resizeEvent){
7420                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7421             }   
7422         },
7423         /**
7424          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7425          */
7426         ieDeferSrc : false,
7427         /**
7428          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7429          */
7430         textResizeInterval : 50
7431     };
7432     
7433     /**
7434      * Fix for doc tools
7435      * @scopeAlias pub=Roo.EventManager
7436      */
7437     
7438      /**
7439      * Appends an event handler to an element (shorthand for addListener)
7440      * @param {String/HTMLElement}   element        The html element or id to assign the
7441      * @param {String}   eventName The type of event to listen for
7442      * @param {Function} handler The method the event invokes
7443      * @param {Object}   scope (optional) The scope in which to execute the handler
7444      * function. The handler function's "this" context.
7445      * @param {Object}   options (optional) An object containing handler configuration
7446      * properties. This may contain any of the following properties:<ul>
7447      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7448      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7449      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7450      * <li>preventDefault {Boolean} True to prevent the default action</li>
7451      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7452      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7453      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7454      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7455      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7456      * by the specified number of milliseconds. If the event fires again within that time, the original
7457      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7458      * </ul><br>
7459      * <p>
7460      * <b>Combining Options</b><br>
7461      * Using the options argument, it is possible to combine different types of listeners:<br>
7462      * <br>
7463      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7464      * Code:<pre><code>
7465 el.on('click', this.onClick, this, {
7466     single: true,
7467     delay: 100,
7468     stopEvent : true,
7469     forumId: 4
7470 });</code></pre>
7471      * <p>
7472      * <b>Attaching multiple handlers in 1 call</b><br>
7473       * The method also allows for a single argument to be passed which is a config object containing properties
7474      * which specify multiple handlers.
7475      * <p>
7476      * Code:<pre><code>
7477 el.on({
7478     'click' : {
7479         fn: this.onClick
7480         scope: this,
7481         delay: 100
7482     },
7483     'mouseover' : {
7484         fn: this.onMouseOver
7485         scope: this
7486     },
7487     'mouseout' : {
7488         fn: this.onMouseOut
7489         scope: this
7490     }
7491 });</code></pre>
7492      * <p>
7493      * Or a shorthand syntax:<br>
7494      * Code:<pre><code>
7495 el.on({
7496     'click' : this.onClick,
7497     'mouseover' : this.onMouseOver,
7498     'mouseout' : this.onMouseOut
7499     scope: this
7500 });</code></pre>
7501      */
7502     pub.on = pub.addListener;
7503     pub.un = pub.removeListener;
7504
7505     pub.stoppedMouseDownEvent = new Roo.util.Event();
7506     return pub;
7507 }();
7508 /**
7509   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7510   * @param {Function} fn        The method the event invokes
7511   * @param {Object}   scope    An  object that becomes the scope of the handler
7512   * @param {boolean}  override If true, the obj passed in becomes
7513   *                             the execution scope of the listener
7514   * @member Roo
7515   * @method onReady
7516  */
7517 Roo.onReady = Roo.EventManager.onDocumentReady;
7518
7519 Roo.onReady(function(){
7520     var bd = Roo.get(document.body);
7521     if(!bd){ return; }
7522
7523     var cls = [
7524             Roo.isIE ? "roo-ie"
7525             : Roo.isIE11 ? "roo-ie11"
7526             : Roo.isEdge ? "roo-edge"
7527             : Roo.isGecko ? "roo-gecko"
7528             : Roo.isOpera ? "roo-opera"
7529             : Roo.isSafari ? "roo-safari" : ""];
7530
7531     if(Roo.isMac){
7532         cls.push("roo-mac");
7533     }
7534     if(Roo.isLinux){
7535         cls.push("roo-linux");
7536     }
7537     if(Roo.isIOS){
7538         cls.push("roo-ios");
7539     }
7540     if(Roo.isTouch){
7541         cls.push("roo-touch");
7542     }
7543     if(Roo.isBorderBox){
7544         cls.push('roo-border-box');
7545     }
7546     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7547         var p = bd.dom.parentNode;
7548         if(p){
7549             p.className += ' roo-strict';
7550         }
7551     }
7552     bd.addClass(cls.join(' '));
7553 });
7554
7555 /**
7556  * @class Roo.EventObject
7557  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7558  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7559  * Example:
7560  * <pre><code>
7561  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7562     e.preventDefault();
7563     var target = e.getTarget();
7564     ...
7565  }
7566  var myDiv = Roo.get("myDiv");
7567  myDiv.on("click", handleClick);
7568  //or
7569  Roo.EventManager.on("myDiv", 'click', handleClick);
7570  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7571  </code></pre>
7572  * @static
7573  */
7574 Roo.EventObject = function(){
7575     
7576     var E = Roo.lib.Event;
7577     
7578     // safari keypress events for special keys return bad keycodes
7579     var safariKeys = {
7580         63234 : 37, // left
7581         63235 : 39, // right
7582         63232 : 38, // up
7583         63233 : 40, // down
7584         63276 : 33, // page up
7585         63277 : 34, // page down
7586         63272 : 46, // delete
7587         63273 : 36, // home
7588         63275 : 35  // end
7589     };
7590
7591     // normalize button clicks
7592     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7593                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7594
7595     Roo.EventObjectImpl = function(e){
7596         if(e){
7597             this.setEvent(e.browserEvent || e);
7598         }
7599     };
7600     Roo.EventObjectImpl.prototype = {
7601         /**
7602          * Used to fix doc tools.
7603          * @scope Roo.EventObject.prototype
7604          */
7605             
7606
7607         
7608         
7609         /** The normal browser event */
7610         browserEvent : null,
7611         /** The button pressed in a mouse event */
7612         button : -1,
7613         /** True if the shift key was down during the event */
7614         shiftKey : false,
7615         /** True if the control key was down during the event */
7616         ctrlKey : false,
7617         /** True if the alt key was down during the event */
7618         altKey : false,
7619
7620         /** Key constant 
7621         * @type Number */
7622         BACKSPACE : 8,
7623         /** Key constant 
7624         * @type Number */
7625         TAB : 9,
7626         /** Key constant 
7627         * @type Number */
7628         RETURN : 13,
7629         /** Key constant 
7630         * @type Number */
7631         ENTER : 13,
7632         /** Key constant 
7633         * @type Number */
7634         SHIFT : 16,
7635         /** Key constant 
7636         * @type Number */
7637         CONTROL : 17,
7638         /** Key constant 
7639         * @type Number */
7640         ESC : 27,
7641         /** Key constant 
7642         * @type Number */
7643         SPACE : 32,
7644         /** Key constant 
7645         * @type Number */
7646         PAGEUP : 33,
7647         /** Key constant 
7648         * @type Number */
7649         PAGEDOWN : 34,
7650         /** Key constant 
7651         * @type Number */
7652         END : 35,
7653         /** Key constant 
7654         * @type Number */
7655         HOME : 36,
7656         /** Key constant 
7657         * @type Number */
7658         LEFT : 37,
7659         /** Key constant 
7660         * @type Number */
7661         UP : 38,
7662         /** Key constant 
7663         * @type Number */
7664         RIGHT : 39,
7665         /** Key constant 
7666         * @type Number */
7667         DOWN : 40,
7668         /** Key constant 
7669         * @type Number */
7670         DELETE : 46,
7671         /** Key constant 
7672         * @type Number */
7673         F5 : 116,
7674
7675            /** @private */
7676         setEvent : function(e){
7677             if(e == this || (e && e.browserEvent)){ // already wrapped
7678                 return e;
7679             }
7680             this.browserEvent = e;
7681             if(e){
7682                 // normalize buttons
7683                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7684                 if(e.type == 'click' && this.button == -1){
7685                     this.button = 0;
7686                 }
7687                 this.type = e.type;
7688                 this.shiftKey = e.shiftKey;
7689                 // mac metaKey behaves like ctrlKey
7690                 this.ctrlKey = e.ctrlKey || e.metaKey;
7691                 this.altKey = e.altKey;
7692                 // in getKey these will be normalized for the mac
7693                 this.keyCode = e.keyCode;
7694                 // keyup warnings on firefox.
7695                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7696                 // cache the target for the delayed and or buffered events
7697                 this.target = E.getTarget(e);
7698                 // same for XY
7699                 this.xy = E.getXY(e);
7700             }else{
7701                 this.button = -1;
7702                 this.shiftKey = false;
7703                 this.ctrlKey = false;
7704                 this.altKey = false;
7705                 this.keyCode = 0;
7706                 this.charCode =0;
7707                 this.target = null;
7708                 this.xy = [0, 0];
7709             }
7710             return this;
7711         },
7712
7713         /**
7714          * Stop the event (preventDefault and stopPropagation)
7715          */
7716         stopEvent : function(){
7717             if(this.browserEvent){
7718                 if(this.browserEvent.type == 'mousedown'){
7719                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7720                 }
7721                 E.stopEvent(this.browserEvent);
7722             }
7723         },
7724
7725         /**
7726          * Prevents the browsers default handling of the event.
7727          */
7728         preventDefault : function(){
7729             if(this.browserEvent){
7730                 E.preventDefault(this.browserEvent);
7731             }
7732         },
7733
7734         /** @private */
7735         isNavKeyPress : function(){
7736             var k = this.keyCode;
7737             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7738             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7739         },
7740
7741         isSpecialKey : function(){
7742             var k = this.keyCode;
7743             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7744             (k == 16) || (k == 17) ||
7745             (k >= 18 && k <= 20) ||
7746             (k >= 33 && k <= 35) ||
7747             (k >= 36 && k <= 39) ||
7748             (k >= 44 && k <= 45);
7749         },
7750         /**
7751          * Cancels bubbling of the event.
7752          */
7753         stopPropagation : function(){
7754             if(this.browserEvent){
7755                 if(this.type == 'mousedown'){
7756                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7757                 }
7758                 E.stopPropagation(this.browserEvent);
7759             }
7760         },
7761
7762         /**
7763          * Gets the key code for the event.
7764          * @return {Number}
7765          */
7766         getCharCode : function(){
7767             return this.charCode || this.keyCode;
7768         },
7769
7770         /**
7771          * Returns a normalized keyCode for the event.
7772          * @return {Number} The key code
7773          */
7774         getKey : function(){
7775             var k = this.keyCode || this.charCode;
7776             return Roo.isSafari ? (safariKeys[k] || k) : k;
7777         },
7778
7779         /**
7780          * Gets the x coordinate of the event.
7781          * @return {Number}
7782          */
7783         getPageX : function(){
7784             return this.xy[0];
7785         },
7786
7787         /**
7788          * Gets the y coordinate of the event.
7789          * @return {Number}
7790          */
7791         getPageY : function(){
7792             return this.xy[1];
7793         },
7794
7795         /**
7796          * Gets the time of the event.
7797          * @return {Number}
7798          */
7799         getTime : function(){
7800             if(this.browserEvent){
7801                 return E.getTime(this.browserEvent);
7802             }
7803             return null;
7804         },
7805
7806         /**
7807          * Gets the page coordinates of the event.
7808          * @return {Array} The xy values like [x, y]
7809          */
7810         getXY : function(){
7811             return this.xy;
7812         },
7813
7814         /**
7815          * Gets the target for the event.
7816          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7817          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7818                 search as a number or element (defaults to 10 || document.body)
7819          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7820          * @return {HTMLelement}
7821          */
7822         getTarget : function(selector, maxDepth, returnEl){
7823             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7824         },
7825         /**
7826          * Gets the related target.
7827          * @return {HTMLElement}
7828          */
7829         getRelatedTarget : function(){
7830             if(this.browserEvent){
7831                 return E.getRelatedTarget(this.browserEvent);
7832             }
7833             return null;
7834         },
7835
7836         /**
7837          * Normalizes mouse wheel delta across browsers
7838          * @return {Number} The delta
7839          */
7840         getWheelDelta : function(){
7841             var e = this.browserEvent;
7842             var delta = 0;
7843             if(e.wheelDelta){ /* IE/Opera. */
7844                 delta = e.wheelDelta/120;
7845             }else if(e.detail){ /* Mozilla case. */
7846                 delta = -e.detail/3;
7847             }
7848             return delta;
7849         },
7850
7851         /**
7852          * Returns true if the control, meta, shift or alt key was pressed during this event.
7853          * @return {Boolean}
7854          */
7855         hasModifier : function(){
7856             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7857         },
7858
7859         /**
7860          * Returns true if the target of this event equals el or is a child of el
7861          * @param {String/HTMLElement/Element} el
7862          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7863          * @return {Boolean}
7864          */
7865         within : function(el, related){
7866             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7867             return t && Roo.fly(el).contains(t);
7868         },
7869
7870         getPoint : function(){
7871             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7872         }
7873     };
7874
7875     return new Roo.EventObjectImpl();
7876 }();
7877             
7878     /*
7879  * Based on:
7880  * Ext JS Library 1.1.1
7881  * Copyright(c) 2006-2007, Ext JS, LLC.
7882  *
7883  * Originally Released Under LGPL - original licence link has changed is not relivant.
7884  *
7885  * Fork - LGPL
7886  * <script type="text/javascript">
7887  */
7888
7889  
7890 // was in Composite Element!??!?!
7891  
7892 (function(){
7893     var D = Roo.lib.Dom;
7894     var E = Roo.lib.Event;
7895     var A = Roo.lib.Anim;
7896
7897     // local style camelizing for speed
7898     var propCache = {};
7899     var camelRe = /(-[a-z])/gi;
7900     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7901     var view = document.defaultView;
7902
7903 /**
7904  * @class Roo.Element
7905  * Represents an Element in the DOM.<br><br>
7906  * Usage:<br>
7907 <pre><code>
7908 var el = Roo.get("my-div");
7909
7910 // or with getEl
7911 var el = getEl("my-div");
7912
7913 // or with a DOM element
7914 var el = Roo.get(myDivElement);
7915 </code></pre>
7916  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7917  * each call instead of constructing a new one.<br><br>
7918  * <b>Animations</b><br />
7919  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7920  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7921 <pre>
7922 Option    Default   Description
7923 --------- --------  ---------------------------------------------
7924 duration  .35       The duration of the animation in seconds
7925 easing    easeOut   The YUI easing method
7926 callback  none      A function to execute when the anim completes
7927 scope     this      The scope (this) of the callback function
7928 </pre>
7929 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7930 * manipulate the animation. Here's an example:
7931 <pre><code>
7932 var el = Roo.get("my-div");
7933
7934 // no animation
7935 el.setWidth(100);
7936
7937 // default animation
7938 el.setWidth(100, true);
7939
7940 // animation with some options set
7941 el.setWidth(100, {
7942     duration: 1,
7943     callback: this.foo,
7944     scope: this
7945 });
7946
7947 // using the "anim" property to get the Anim object
7948 var opt = {
7949     duration: 1,
7950     callback: this.foo,
7951     scope: this
7952 };
7953 el.setWidth(100, opt);
7954 ...
7955 if(opt.anim.isAnimated()){
7956     opt.anim.stop();
7957 }
7958 </code></pre>
7959 * <b> Composite (Collections of) Elements</b><br />
7960  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7961  * @constructor Create a new Element directly.
7962  * @param {String/HTMLElement} element
7963  * @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).
7964  */
7965     Roo.Element = function(element, forceNew)
7966     {
7967         var dom = typeof element == "string" ?
7968                 document.getElementById(element) : element;
7969         
7970         this.listeners = {};
7971         
7972         if(!dom){ // invalid id/element
7973             return null;
7974         }
7975         var id = dom.id;
7976         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7977             return Roo.Element.cache[id];
7978         }
7979
7980         /**
7981          * The DOM element
7982          * @type HTMLElement
7983          */
7984         this.dom = dom;
7985
7986         /**
7987          * The DOM element ID
7988          * @type String
7989          */
7990         this.id = id || Roo.id(dom);
7991         
7992         return this; // assumed for cctor?
7993     };
7994
7995     var El = Roo.Element;
7996
7997     El.prototype = {
7998         /**
7999          * The element's default display mode  (defaults to "") 
8000          * @type String
8001          */
8002         originalDisplay : "",
8003
8004         
8005         // note this is overridden in BS version..
8006         visibilityMode : 1, 
8007         /**
8008          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8009          * @type String
8010          */
8011         defaultUnit : "px",
8012         
8013         /**
8014          * Sets the element's visibility mode. When setVisible() is called it
8015          * will use this to determine whether to set the visibility or the display property.
8016          * @param visMode Element.VISIBILITY or Element.DISPLAY
8017          * @return {Roo.Element} this
8018          */
8019         setVisibilityMode : function(visMode){
8020             this.visibilityMode = visMode;
8021             return this;
8022         },
8023         /**
8024          * Convenience method for setVisibilityMode(Element.DISPLAY)
8025          * @param {String} display (optional) What to set display to when visible
8026          * @return {Roo.Element} this
8027          */
8028         enableDisplayMode : function(display){
8029             this.setVisibilityMode(El.DISPLAY);
8030             if(typeof display != "undefined") { this.originalDisplay = display; }
8031             return this;
8032         },
8033
8034         /**
8035          * 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)
8036          * @param {String} selector The simple selector to test
8037          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8038                 search as a number or element (defaults to 10 || document.body)
8039          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8040          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8041          */
8042         findParent : function(simpleSelector, maxDepth, returnEl){
8043             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8044             maxDepth = maxDepth || 50;
8045             if(typeof maxDepth != "number"){
8046                 stopEl = Roo.getDom(maxDepth);
8047                 maxDepth = 10;
8048             }
8049             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8050                 if(dq.is(p, simpleSelector)){
8051                     return returnEl ? Roo.get(p) : p;
8052                 }
8053                 depth++;
8054                 p = p.parentNode;
8055             }
8056             return null;
8057         },
8058
8059
8060         /**
8061          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8062          * @param {String} selector The simple selector to test
8063          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8064                 search as a number or element (defaults to 10 || document.body)
8065          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8066          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8067          */
8068         findParentNode : function(simpleSelector, maxDepth, returnEl){
8069             var p = Roo.fly(this.dom.parentNode, '_internal');
8070             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8071         },
8072         
8073         /**
8074          * Looks at  the scrollable parent element
8075          */
8076         findScrollableParent : function()
8077         {
8078             var overflowRegex = /(auto|scroll)/;
8079             
8080             if(this.getStyle('position') === 'fixed'){
8081                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8082             }
8083             
8084             var excludeStaticParent = this.getStyle('position') === "absolute";
8085             
8086             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8087                 
8088                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8089                     continue;
8090                 }
8091                 
8092                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8093                     return parent;
8094                 }
8095                 
8096                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8097                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8098                 }
8099             }
8100             
8101             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8102         },
8103
8104         /**
8105          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8106          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8107          * @param {String} selector The simple selector to test
8108          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8109                 search as a number or element (defaults to 10 || document.body)
8110          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8111          */
8112         up : function(simpleSelector, maxDepth){
8113             return this.findParentNode(simpleSelector, maxDepth, true);
8114         },
8115
8116
8117
8118         /**
8119          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8120          * @param {String} selector The simple selector to test
8121          * @return {Boolean} True if this element matches the selector, else false
8122          */
8123         is : function(simpleSelector){
8124             return Roo.DomQuery.is(this.dom, simpleSelector);
8125         },
8126
8127         /**
8128          * Perform animation on this element.
8129          * @param {Object} args The YUI animation control args
8130          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8131          * @param {Function} onComplete (optional) Function to call when animation completes
8132          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8133          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8134          * @return {Roo.Element} this
8135          */
8136         animate : function(args, duration, onComplete, easing, animType){
8137             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8138             return this;
8139         },
8140
8141         /*
8142          * @private Internal animation call
8143          */
8144         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8145             animType = animType || 'run';
8146             opt = opt || {};
8147             var anim = Roo.lib.Anim[animType](
8148                 this.dom, args,
8149                 (opt.duration || defaultDur) || .35,
8150                 (opt.easing || defaultEase) || 'easeOut',
8151                 function(){
8152                     Roo.callback(cb, this);
8153                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8154                 },
8155                 this
8156             );
8157             opt.anim = anim;
8158             return anim;
8159         },
8160
8161         // private legacy anim prep
8162         preanim : function(a, i){
8163             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8164         },
8165
8166         /**
8167          * Removes worthless text nodes
8168          * @param {Boolean} forceReclean (optional) By default the element
8169          * keeps track if it has been cleaned already so
8170          * you can call this over and over. However, if you update the element and
8171          * need to force a reclean, you can pass true.
8172          */
8173         clean : function(forceReclean){
8174             if(this.isCleaned && forceReclean !== true){
8175                 return this;
8176             }
8177             var ns = /\S/;
8178             var d = this.dom, n = d.firstChild, ni = -1;
8179             while(n){
8180                 var nx = n.nextSibling;
8181                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8182                     d.removeChild(n);
8183                 }else{
8184                     n.nodeIndex = ++ni;
8185                 }
8186                 n = nx;
8187             }
8188             this.isCleaned = true;
8189             return this;
8190         },
8191
8192         // private
8193         calcOffsetsTo : function(el){
8194             el = Roo.get(el);
8195             var d = el.dom;
8196             var restorePos = false;
8197             if(el.getStyle('position') == 'static'){
8198                 el.position('relative');
8199                 restorePos = true;
8200             }
8201             var x = 0, y =0;
8202             var op = this.dom;
8203             while(op && op != d && op.tagName != 'HTML'){
8204                 x+= op.offsetLeft;
8205                 y+= op.offsetTop;
8206                 op = op.offsetParent;
8207             }
8208             if(restorePos){
8209                 el.position('static');
8210             }
8211             return [x, y];
8212         },
8213
8214         /**
8215          * Scrolls this element into view within the passed container.
8216          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8217          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8218          * @return {Roo.Element} this
8219          */
8220         scrollIntoView : function(container, hscroll){
8221             var c = Roo.getDom(container) || document.body;
8222             var el = this.dom;
8223
8224             var o = this.calcOffsetsTo(c),
8225                 l = o[0],
8226                 t = o[1],
8227                 b = t+el.offsetHeight,
8228                 r = l+el.offsetWidth;
8229
8230             var ch = c.clientHeight;
8231             var ct = parseInt(c.scrollTop, 10);
8232             var cl = parseInt(c.scrollLeft, 10);
8233             var cb = ct + ch;
8234             var cr = cl + c.clientWidth;
8235
8236             if(t < ct){
8237                 c.scrollTop = t;
8238             }else if(b > cb){
8239                 c.scrollTop = b-ch;
8240             }
8241
8242             if(hscroll !== false){
8243                 if(l < cl){
8244                     c.scrollLeft = l;
8245                 }else if(r > cr){
8246                     c.scrollLeft = r-c.clientWidth;
8247                 }
8248             }
8249             return this;
8250         },
8251
8252         // private
8253         scrollChildIntoView : function(child, hscroll){
8254             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8255         },
8256
8257         /**
8258          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8259          * the new height may not be available immediately.
8260          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8261          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8262          * @param {Function} onComplete (optional) Function to call when animation completes
8263          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8264          * @return {Roo.Element} this
8265          */
8266         autoHeight : function(animate, duration, onComplete, easing){
8267             var oldHeight = this.getHeight();
8268             this.clip();
8269             this.setHeight(1); // force clipping
8270             setTimeout(function(){
8271                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8272                 if(!animate){
8273                     this.setHeight(height);
8274                     this.unclip();
8275                     if(typeof onComplete == "function"){
8276                         onComplete();
8277                     }
8278                 }else{
8279                     this.setHeight(oldHeight); // restore original height
8280                     this.setHeight(height, animate, duration, function(){
8281                         this.unclip();
8282                         if(typeof onComplete == "function") { onComplete(); }
8283                     }.createDelegate(this), easing);
8284                 }
8285             }.createDelegate(this), 0);
8286             return this;
8287         },
8288
8289         /**
8290          * Returns true if this element is an ancestor of the passed element
8291          * @param {HTMLElement/String} el The element to check
8292          * @return {Boolean} True if this element is an ancestor of el, else false
8293          */
8294         contains : function(el){
8295             if(!el){return false;}
8296             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8297         },
8298
8299         /**
8300          * Checks whether the element is currently visible using both visibility and display properties.
8301          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8302          * @return {Boolean} True if the element is currently visible, else false
8303          */
8304         isVisible : function(deep) {
8305             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8306             if(deep !== true || !vis){
8307                 return vis;
8308             }
8309             var p = this.dom.parentNode;
8310             while(p && p.tagName.toLowerCase() != "body"){
8311                 if(!Roo.fly(p, '_isVisible').isVisible()){
8312                     return false;
8313                 }
8314                 p = p.parentNode;
8315             }
8316             return true;
8317         },
8318
8319         /**
8320          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8321          * @param {String} selector The CSS selector
8322          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8323          * @return {CompositeElement/CompositeElementLite} The composite element
8324          */
8325         select : function(selector, unique){
8326             return El.select(selector, unique, this.dom);
8327         },
8328
8329         /**
8330          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8331          * @param {String} selector The CSS selector
8332          * @return {Array} An array of the matched nodes
8333          */
8334         query : function(selector, unique){
8335             return Roo.DomQuery.select(selector, this.dom);
8336         },
8337
8338         /**
8339          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8340          * @param {String} selector The CSS selector
8341          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8342          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8343          */
8344         child : function(selector, returnDom){
8345             var n = Roo.DomQuery.selectNode(selector, this.dom);
8346             return returnDom ? n : Roo.get(n);
8347         },
8348
8349         /**
8350          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8351          * @param {String} selector The CSS selector
8352          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8353          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8354          */
8355         down : function(selector, returnDom){
8356             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8357             return returnDom ? n : Roo.get(n);
8358         },
8359
8360         /**
8361          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8362          * @param {String} group The group the DD object is member of
8363          * @param {Object} config The DD config object
8364          * @param {Object} overrides An object containing methods to override/implement on the DD object
8365          * @return {Roo.dd.DD} The DD object
8366          */
8367         initDD : function(group, config, overrides){
8368             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8369             return Roo.apply(dd, overrides);
8370         },
8371
8372         /**
8373          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8374          * @param {String} group The group the DDProxy object is member of
8375          * @param {Object} config The DDProxy config object
8376          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8377          * @return {Roo.dd.DDProxy} The DDProxy object
8378          */
8379         initDDProxy : function(group, config, overrides){
8380             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8381             return Roo.apply(dd, overrides);
8382         },
8383
8384         /**
8385          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8386          * @param {String} group The group the DDTarget object is member of
8387          * @param {Object} config The DDTarget config object
8388          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8389          * @return {Roo.dd.DDTarget} The DDTarget object
8390          */
8391         initDDTarget : function(group, config, overrides){
8392             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8393             return Roo.apply(dd, overrides);
8394         },
8395
8396         /**
8397          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8398          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8399          * @param {Boolean} visible Whether the element is visible
8400          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8401          * @return {Roo.Element} this
8402          */
8403          setVisible : function(visible, animate){
8404             if(!animate || !A){
8405                 if(this.visibilityMode == El.DISPLAY){
8406                     this.setDisplayed(visible);
8407                 }else{
8408                     this.fixDisplay();
8409                     this.dom.style.visibility = visible ? "visible" : "hidden";
8410                 }
8411             }else{
8412                 // closure for composites
8413                 var dom = this.dom;
8414                 var visMode = this.visibilityMode;
8415                 if(visible){
8416                     this.setOpacity(.01);
8417                     this.setVisible(true);
8418                 }
8419                 this.anim({opacity: { to: (visible?1:0) }},
8420                       this.preanim(arguments, 1),
8421                       null, .35, 'easeIn', function(){
8422                          if(!visible){
8423                              if(visMode == El.DISPLAY){
8424                                  dom.style.display = "none";
8425                              }else{
8426                                  dom.style.visibility = "hidden";
8427                              }
8428                              Roo.get(dom).setOpacity(1);
8429                          }
8430                      });
8431             }
8432             return this;
8433         },
8434
8435         /**
8436          * Returns true if display is not "none"
8437          * @return {Boolean}
8438          */
8439         isDisplayed : function() {
8440             return this.getStyle("display") != "none";
8441         },
8442
8443         /**
8444          * Toggles the element's visibility or display, depending on visibility mode.
8445          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8446          * @return {Roo.Element} this
8447          */
8448         toggle : function(animate){
8449             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8450             return this;
8451         },
8452
8453         /**
8454          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8455          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8456          * @return {Roo.Element} this
8457          */
8458         setDisplayed : function(value) {
8459             if(typeof value == "boolean"){
8460                value = value ? this.originalDisplay : "none";
8461             }
8462             this.setStyle("display", value);
8463             return this;
8464         },
8465
8466         /**
8467          * Tries to focus the element. Any exceptions are caught and ignored.
8468          * @return {Roo.Element} this
8469          */
8470         focus : function() {
8471             try{
8472                 this.dom.focus();
8473             }catch(e){}
8474             return this;
8475         },
8476
8477         /**
8478          * Tries to blur the element. Any exceptions are caught and ignored.
8479          * @return {Roo.Element} this
8480          */
8481         blur : function() {
8482             try{
8483                 this.dom.blur();
8484             }catch(e){}
8485             return this;
8486         },
8487
8488         /**
8489          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8490          * @param {String/Array} className The CSS class to add, or an array of classes
8491          * @return {Roo.Element} this
8492          */
8493         addClass : function(className){
8494             if(className instanceof Array){
8495                 for(var i = 0, len = className.length; i < len; i++) {
8496                     this.addClass(className[i]);
8497                 }
8498             }else{
8499                 if(className && !this.hasClass(className)){
8500                     if (this.dom instanceof SVGElement) {
8501                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8502                     } else {
8503                         this.dom.className = this.dom.className + " " + className;
8504                     }
8505                 }
8506             }
8507             return this;
8508         },
8509
8510         /**
8511          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8512          * @param {String/Array} className The CSS class to add, or an array of classes
8513          * @return {Roo.Element} this
8514          */
8515         radioClass : function(className){
8516             var siblings = this.dom.parentNode.childNodes;
8517             for(var i = 0; i < siblings.length; i++) {
8518                 var s = siblings[i];
8519                 if(s.nodeType == 1){
8520                     Roo.get(s).removeClass(className);
8521                 }
8522             }
8523             this.addClass(className);
8524             return this;
8525         },
8526
8527         /**
8528          * Removes one or more CSS classes from the element.
8529          * @param {String/Array} className The CSS class to remove, or an array of classes
8530          * @return {Roo.Element} this
8531          */
8532         removeClass : function(className){
8533             
8534             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8535             if(!className || !cn){
8536                 return this;
8537             }
8538             if(className instanceof Array){
8539                 for(var i = 0, len = className.length; i < len; i++) {
8540                     this.removeClass(className[i]);
8541                 }
8542             }else{
8543                 if(this.hasClass(className)){
8544                     var re = this.classReCache[className];
8545                     if (!re) {
8546                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8547                        this.classReCache[className] = re;
8548                     }
8549                     if (this.dom instanceof SVGElement) {
8550                         this.dom.className.baseVal = cn.replace(re, " ");
8551                     } else {
8552                         this.dom.className = cn.replace(re, " ");
8553                     }
8554                 }
8555             }
8556             return this;
8557         },
8558
8559         // private
8560         classReCache: {},
8561
8562         /**
8563          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8564          * @param {String} className The CSS class to toggle
8565          * @return {Roo.Element} this
8566          */
8567         toggleClass : function(className){
8568             if(this.hasClass(className)){
8569                 this.removeClass(className);
8570             }else{
8571                 this.addClass(className);
8572             }
8573             return this;
8574         },
8575
8576         /**
8577          * Checks if the specified CSS class exists on this element's DOM node.
8578          * @param {String} className The CSS class to check for
8579          * @return {Boolean} True if the class exists, else false
8580          */
8581         hasClass : function(className){
8582             if (this.dom instanceof SVGElement) {
8583                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8584             } 
8585             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8586         },
8587
8588         /**
8589          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8590          * @param {String} oldClassName The CSS class to replace
8591          * @param {String} newClassName The replacement CSS class
8592          * @return {Roo.Element} this
8593          */
8594         replaceClass : function(oldClassName, newClassName){
8595             this.removeClass(oldClassName);
8596             this.addClass(newClassName);
8597             return this;
8598         },
8599
8600         /**
8601          * Returns an object with properties matching the styles requested.
8602          * For example, el.getStyles('color', 'font-size', 'width') might return
8603          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8604          * @param {String} style1 A style name
8605          * @param {String} style2 A style name
8606          * @param {String} etc.
8607          * @return {Object} The style object
8608          */
8609         getStyles : function(){
8610             var a = arguments, len = a.length, r = {};
8611             for(var i = 0; i < len; i++){
8612                 r[a[i]] = this.getStyle(a[i]);
8613             }
8614             return r;
8615         },
8616
8617         /**
8618          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8619          * @param {String} property The style property whose value is returned.
8620          * @return {String} The current value of the style property for this element.
8621          */
8622         getStyle : function(){
8623             return view && view.getComputedStyle ?
8624                 function(prop){
8625                     var el = this.dom, v, cs, camel;
8626                     if(prop == 'float'){
8627                         prop = "cssFloat";
8628                     }
8629                     if(el.style && (v = el.style[prop])){
8630                         return v;
8631                     }
8632                     if(cs = view.getComputedStyle(el, "")){
8633                         if(!(camel = propCache[prop])){
8634                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8635                         }
8636                         return cs[camel];
8637                     }
8638                     return null;
8639                 } :
8640                 function(prop){
8641                     var el = this.dom, v, cs, camel;
8642                     if(prop == 'opacity'){
8643                         if(typeof el.style.filter == 'string'){
8644                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8645                             if(m){
8646                                 var fv = parseFloat(m[1]);
8647                                 if(!isNaN(fv)){
8648                                     return fv ? fv / 100 : 0;
8649                                 }
8650                             }
8651                         }
8652                         return 1;
8653                     }else if(prop == 'float'){
8654                         prop = "styleFloat";
8655                     }
8656                     if(!(camel = propCache[prop])){
8657                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8658                     }
8659                     if(v = el.style[camel]){
8660                         return v;
8661                     }
8662                     if(cs = el.currentStyle){
8663                         return cs[camel];
8664                     }
8665                     return null;
8666                 };
8667         }(),
8668
8669         /**
8670          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8671          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8672          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8673          * @return {Roo.Element} this
8674          */
8675         setStyle : function(prop, value){
8676             if(typeof prop == "string"){
8677                 
8678                 if (prop == 'float') {
8679                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8680                     return this;
8681                 }
8682                 
8683                 var camel;
8684                 if(!(camel = propCache[prop])){
8685                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8686                 }
8687                 
8688                 if(camel == 'opacity') {
8689                     this.setOpacity(value);
8690                 }else{
8691                     this.dom.style[camel] = value;
8692                 }
8693             }else{
8694                 for(var style in prop){
8695                     if(typeof prop[style] != "function"){
8696                        this.setStyle(style, prop[style]);
8697                     }
8698                 }
8699             }
8700             return this;
8701         },
8702
8703         /**
8704          * More flexible version of {@link #setStyle} for setting style properties.
8705          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8706          * a function which returns such a specification.
8707          * @return {Roo.Element} this
8708          */
8709         applyStyles : function(style){
8710             Roo.DomHelper.applyStyles(this.dom, style);
8711             return this;
8712         },
8713
8714         /**
8715           * 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).
8716           * @return {Number} The X position of the element
8717           */
8718         getX : function(){
8719             return D.getX(this.dom);
8720         },
8721
8722         /**
8723           * 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).
8724           * @return {Number} The Y position of the element
8725           */
8726         getY : function(){
8727             return D.getY(this.dom);
8728         },
8729
8730         /**
8731           * 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).
8732           * @return {Array} The XY position of the element
8733           */
8734         getXY : function(){
8735             return D.getXY(this.dom);
8736         },
8737
8738         /**
8739          * 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).
8740          * @param {Number} The X position of the element
8741          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8742          * @return {Roo.Element} this
8743          */
8744         setX : function(x, animate){
8745             if(!animate || !A){
8746                 D.setX(this.dom, x);
8747             }else{
8748                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8749             }
8750             return this;
8751         },
8752
8753         /**
8754          * 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).
8755          * @param {Number} The Y position of the element
8756          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8757          * @return {Roo.Element} this
8758          */
8759         setY : function(y, animate){
8760             if(!animate || !A){
8761                 D.setY(this.dom, y);
8762             }else{
8763                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8764             }
8765             return this;
8766         },
8767
8768         /**
8769          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8770          * @param {String} left The left CSS property value
8771          * @return {Roo.Element} this
8772          */
8773         setLeft : function(left){
8774             this.setStyle("left", this.addUnits(left));
8775             return this;
8776         },
8777
8778         /**
8779          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8780          * @param {String} top The top CSS property value
8781          * @return {Roo.Element} this
8782          */
8783         setTop : function(top){
8784             this.setStyle("top", this.addUnits(top));
8785             return this;
8786         },
8787
8788         /**
8789          * Sets the element's CSS right style.
8790          * @param {String} right The right CSS property value
8791          * @return {Roo.Element} this
8792          */
8793         setRight : function(right){
8794             this.setStyle("right", this.addUnits(right));
8795             return this;
8796         },
8797
8798         /**
8799          * Sets the element's CSS bottom style.
8800          * @param {String} bottom The bottom CSS property value
8801          * @return {Roo.Element} this
8802          */
8803         setBottom : function(bottom){
8804             this.setStyle("bottom", this.addUnits(bottom));
8805             return this;
8806         },
8807
8808         /**
8809          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8810          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8811          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8812          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8813          * @return {Roo.Element} this
8814          */
8815         setXY : function(pos, animate){
8816             if(!animate || !A){
8817                 D.setXY(this.dom, pos);
8818             }else{
8819                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8820             }
8821             return this;
8822         },
8823
8824         /**
8825          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8826          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8827          * @param {Number} x X value for new position (coordinates are page-based)
8828          * @param {Number} y Y value for new position (coordinates are page-based)
8829          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8830          * @return {Roo.Element} this
8831          */
8832         setLocation : function(x, y, animate){
8833             this.setXY([x, y], this.preanim(arguments, 2));
8834             return this;
8835         },
8836
8837         /**
8838          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8839          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8840          * @param {Number} x X value for new position (coordinates are page-based)
8841          * @param {Number} y Y value for new position (coordinates are page-based)
8842          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8843          * @return {Roo.Element} this
8844          */
8845         moveTo : function(x, y, animate){
8846             this.setXY([x, y], this.preanim(arguments, 2));
8847             return this;
8848         },
8849
8850         /**
8851          * Returns the region of the given element.
8852          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8853          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8854          */
8855         getRegion : function(){
8856             return D.getRegion(this.dom);
8857         },
8858
8859         /**
8860          * Returns the offset height of the element
8861          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8862          * @return {Number} The element's height
8863          */
8864         getHeight : function(contentHeight){
8865             var h = this.dom.offsetHeight || 0;
8866             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8867         },
8868
8869         /**
8870          * Returns the offset width of the element
8871          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8872          * @return {Number} The element's width
8873          */
8874         getWidth : function(contentWidth){
8875             var w = this.dom.offsetWidth || 0;
8876             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8877         },
8878
8879         /**
8880          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8881          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8882          * if a height has not been set using CSS.
8883          * @return {Number}
8884          */
8885         getComputedHeight : function(){
8886             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8887             if(!h){
8888                 h = parseInt(this.getStyle('height'), 10) || 0;
8889                 if(!this.isBorderBox()){
8890                     h += this.getFrameWidth('tb');
8891                 }
8892             }
8893             return h;
8894         },
8895
8896         /**
8897          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8898          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8899          * if a width has not been set using CSS.
8900          * @return {Number}
8901          */
8902         getComputedWidth : function(){
8903             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8904             if(!w){
8905                 w = parseInt(this.getStyle('width'), 10) || 0;
8906                 if(!this.isBorderBox()){
8907                     w += this.getFrameWidth('lr');
8908                 }
8909             }
8910             return w;
8911         },
8912
8913         /**
8914          * Returns the size of the element.
8915          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8916          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8917          */
8918         getSize : function(contentSize){
8919             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8920         },
8921
8922         /**
8923          * Returns the width and height of the viewport.
8924          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8925          */
8926         getViewSize : function(){
8927             var d = this.dom, doc = document, aw = 0, ah = 0;
8928             if(d == doc || d == doc.body){
8929                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8930             }else{
8931                 return {
8932                     width : d.clientWidth,
8933                     height: d.clientHeight
8934                 };
8935             }
8936         },
8937
8938         /**
8939          * Returns the value of the "value" attribute
8940          * @param {Boolean} asNumber true to parse the value as a number
8941          * @return {String/Number}
8942          */
8943         getValue : function(asNumber){
8944             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8945         },
8946
8947         // private
8948         adjustWidth : function(width){
8949             if(typeof width == "number"){
8950                 if(this.autoBoxAdjust && !this.isBorderBox()){
8951                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8952                 }
8953                 if(width < 0){
8954                     width = 0;
8955                 }
8956             }
8957             return width;
8958         },
8959
8960         // private
8961         adjustHeight : function(height){
8962             if(typeof height == "number"){
8963                if(this.autoBoxAdjust && !this.isBorderBox()){
8964                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8965                }
8966                if(height < 0){
8967                    height = 0;
8968                }
8969             }
8970             return height;
8971         },
8972
8973         /**
8974          * Set the width of the element
8975          * @param {Number} width The new width
8976          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8977          * @return {Roo.Element} this
8978          */
8979         setWidth : function(width, animate){
8980             width = this.adjustWidth(width);
8981             if(!animate || !A){
8982                 this.dom.style.width = this.addUnits(width);
8983             }else{
8984                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8985             }
8986             return this;
8987         },
8988
8989         /**
8990          * Set the height of the element
8991          * @param {Number} height The new height
8992          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8993          * @return {Roo.Element} this
8994          */
8995          setHeight : function(height, animate){
8996             height = this.adjustHeight(height);
8997             if(!animate || !A){
8998                 this.dom.style.height = this.addUnits(height);
8999             }else{
9000                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9001             }
9002             return this;
9003         },
9004
9005         /**
9006          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9007          * @param {Number} width The new width
9008          * @param {Number} height The new height
9009          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9010          * @return {Roo.Element} this
9011          */
9012          setSize : function(width, height, animate){
9013             if(typeof width == "object"){ // in case of object from getSize()
9014                 height = width.height; width = width.width;
9015             }
9016             width = this.adjustWidth(width); height = this.adjustHeight(height);
9017             if(!animate || !A){
9018                 this.dom.style.width = this.addUnits(width);
9019                 this.dom.style.height = this.addUnits(height);
9020             }else{
9021                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9022             }
9023             return this;
9024         },
9025
9026         /**
9027          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9028          * @param {Number} x X value for new position (coordinates are page-based)
9029          * @param {Number} y Y value for new position (coordinates are page-based)
9030          * @param {Number} width The new width
9031          * @param {Number} height The new height
9032          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9033          * @return {Roo.Element} this
9034          */
9035         setBounds : function(x, y, width, height, animate){
9036             if(!animate || !A){
9037                 this.setSize(width, height);
9038                 this.setLocation(x, y);
9039             }else{
9040                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9041                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9042                               this.preanim(arguments, 4), 'motion');
9043             }
9044             return this;
9045         },
9046
9047         /**
9048          * 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.
9049          * @param {Roo.lib.Region} region The region to fill
9050          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9051          * @return {Roo.Element} this
9052          */
9053         setRegion : function(region, animate){
9054             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9055             return this;
9056         },
9057
9058         /**
9059          * Appends an event handler
9060          *
9061          * @param {String}   eventName     The type of event to append
9062          * @param {Function} fn        The method the event invokes
9063          * @param {Object} scope       (optional) The scope (this object) of the fn
9064          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9065          */
9066         addListener : function(eventName, fn, scope, options)
9067         {
9068             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9069                 this.addListener('touchstart', this.onTapHandler, this);
9070             }
9071             
9072             // we need to handle a special case where dom element is a svg element.
9073             // in this case we do not actua
9074             if (!this.dom) {
9075                 return;
9076             }
9077             
9078             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9079                 if (typeof(this.listeners[eventName]) == 'undefined') {
9080                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9081                 }
9082                 this.listeners[eventName].addListener(fn, scope, options);
9083                 return;
9084             }
9085             
9086                 
9087             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9088             
9089             
9090         },
9091         tapedTwice : false,
9092         onTapHandler : function(event)
9093         {
9094             if(!this.tapedTwice) {
9095                 this.tapedTwice = true;
9096                 var s = this;
9097                 setTimeout( function() {
9098                     s.tapedTwice = false;
9099                 }, 300 );
9100                 return;
9101             }
9102             event.preventDefault();
9103             var revent = new MouseEvent('dblclick',  {
9104                 view: window,
9105                 bubbles: true,
9106                 cancelable: true
9107             });
9108              
9109             this.dom.dispatchEvent(revent);
9110             //action on double tap goes below
9111              
9112         }, 
9113  
9114         /**
9115          * Removes an event handler from this element
9116          * @param {String} eventName the type of event to remove
9117          * @param {Function} fn the method the event invokes
9118          * @param {Function} scope (needed for svg fake listeners)
9119          * @return {Roo.Element} this
9120          */
9121         removeListener : function(eventName, fn, scope){
9122             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9123             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9124                 return this;
9125             }
9126             this.listeners[eventName].removeListener(fn, scope);
9127             return this;
9128         },
9129
9130         /**
9131          * Removes all previous added listeners from this element
9132          * @return {Roo.Element} this
9133          */
9134         removeAllListeners : function(){
9135             E.purgeElement(this.dom);
9136             this.listeners = {};
9137             return this;
9138         },
9139
9140         relayEvent : function(eventName, observable){
9141             this.on(eventName, function(e){
9142                 observable.fireEvent(eventName, e);
9143             });
9144         },
9145
9146         
9147         /**
9148          * Set the opacity of the element
9149          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9150          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9151          * @return {Roo.Element} this
9152          */
9153          setOpacity : function(opacity, animate){
9154             if(!animate || !A){
9155                 var s = this.dom.style;
9156                 if(Roo.isIE){
9157                     s.zoom = 1;
9158                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9159                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9160                 }else{
9161                     s.opacity = opacity;
9162                 }
9163             }else{
9164                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9165             }
9166             return this;
9167         },
9168
9169         /**
9170          * Gets the left X coordinate
9171          * @param {Boolean} local True to get the local css position instead of page coordinate
9172          * @return {Number}
9173          */
9174         getLeft : function(local){
9175             if(!local){
9176                 return this.getX();
9177             }else{
9178                 return parseInt(this.getStyle("left"), 10) || 0;
9179             }
9180         },
9181
9182         /**
9183          * Gets the right X coordinate of the element (element X position + element width)
9184          * @param {Boolean} local True to get the local css position instead of page coordinate
9185          * @return {Number}
9186          */
9187         getRight : function(local){
9188             if(!local){
9189                 return this.getX() + this.getWidth();
9190             }else{
9191                 return (this.getLeft(true) + this.getWidth()) || 0;
9192             }
9193         },
9194
9195         /**
9196          * Gets the top Y coordinate
9197          * @param {Boolean} local True to get the local css position instead of page coordinate
9198          * @return {Number}
9199          */
9200         getTop : function(local) {
9201             if(!local){
9202                 return this.getY();
9203             }else{
9204                 return parseInt(this.getStyle("top"), 10) || 0;
9205             }
9206         },
9207
9208         /**
9209          * Gets the bottom Y coordinate of the element (element Y position + element height)
9210          * @param {Boolean} local True to get the local css position instead of page coordinate
9211          * @return {Number}
9212          */
9213         getBottom : function(local){
9214             if(!local){
9215                 return this.getY() + this.getHeight();
9216             }else{
9217                 return (this.getTop(true) + this.getHeight()) || 0;
9218             }
9219         },
9220
9221         /**
9222         * Initializes positioning on this element. If a desired position is not passed, it will make the
9223         * the element positioned relative IF it is not already positioned.
9224         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9225         * @param {Number} zIndex (optional) The zIndex to apply
9226         * @param {Number} x (optional) Set the page X position
9227         * @param {Number} y (optional) Set the page Y position
9228         */
9229         position : function(pos, zIndex, x, y){
9230             if(!pos){
9231                if(this.getStyle('position') == 'static'){
9232                    this.setStyle('position', 'relative');
9233                }
9234             }else{
9235                 this.setStyle("position", pos);
9236             }
9237             if(zIndex){
9238                 this.setStyle("z-index", zIndex);
9239             }
9240             if(x !== undefined && y !== undefined){
9241                 this.setXY([x, y]);
9242             }else if(x !== undefined){
9243                 this.setX(x);
9244             }else if(y !== undefined){
9245                 this.setY(y);
9246             }
9247         },
9248
9249         /**
9250         * Clear positioning back to the default when the document was loaded
9251         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9252         * @return {Roo.Element} this
9253          */
9254         clearPositioning : function(value){
9255             value = value ||'';
9256             this.setStyle({
9257                 "left": value,
9258                 "right": value,
9259                 "top": value,
9260                 "bottom": value,
9261                 "z-index": "",
9262                 "position" : "static"
9263             });
9264             return this;
9265         },
9266
9267         /**
9268         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9269         * snapshot before performing an update and then restoring the element.
9270         * @return {Object}
9271         */
9272         getPositioning : function(){
9273             var l = this.getStyle("left");
9274             var t = this.getStyle("top");
9275             return {
9276                 "position" : this.getStyle("position"),
9277                 "left" : l,
9278                 "right" : l ? "" : this.getStyle("right"),
9279                 "top" : t,
9280                 "bottom" : t ? "" : this.getStyle("bottom"),
9281                 "z-index" : this.getStyle("z-index")
9282             };
9283         },
9284
9285         /**
9286          * Gets the width of the border(s) for the specified side(s)
9287          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9288          * passing lr would get the border (l)eft width + the border (r)ight width.
9289          * @return {Number} The width of the sides passed added together
9290          */
9291         getBorderWidth : function(side){
9292             return this.addStyles(side, El.borders);
9293         },
9294
9295         /**
9296          * Gets the width of the padding(s) for the specified side(s)
9297          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9298          * passing lr would get the padding (l)eft + the padding (r)ight.
9299          * @return {Number} The padding of the sides passed added together
9300          */
9301         getPadding : function(side){
9302             return this.addStyles(side, El.paddings);
9303         },
9304
9305         /**
9306         * Set positioning with an object returned by getPositioning().
9307         * @param {Object} posCfg
9308         * @return {Roo.Element} this
9309          */
9310         setPositioning : function(pc){
9311             this.applyStyles(pc);
9312             if(pc.right == "auto"){
9313                 this.dom.style.right = "";
9314             }
9315             if(pc.bottom == "auto"){
9316                 this.dom.style.bottom = "";
9317             }
9318             return this;
9319         },
9320
9321         // private
9322         fixDisplay : function(){
9323             if(this.getStyle("display") == "none"){
9324                 this.setStyle("visibility", "hidden");
9325                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9326                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9327                     this.setStyle("display", "block");
9328                 }
9329             }
9330         },
9331
9332         /**
9333          * Quick set left and top adding default units
9334          * @param {String} left The left CSS property value
9335          * @param {String} top The top CSS property value
9336          * @return {Roo.Element} this
9337          */
9338          setLeftTop : function(left, top){
9339             this.dom.style.left = this.addUnits(left);
9340             this.dom.style.top = this.addUnits(top);
9341             return this;
9342         },
9343
9344         /**
9345          * Move this element relative to its current position.
9346          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9347          * @param {Number} distance How far to move the element in pixels
9348          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9349          * @return {Roo.Element} this
9350          */
9351          move : function(direction, distance, animate){
9352             var xy = this.getXY();
9353             direction = direction.toLowerCase();
9354             switch(direction){
9355                 case "l":
9356                 case "left":
9357                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9358                     break;
9359                case "r":
9360                case "right":
9361                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9362                     break;
9363                case "t":
9364                case "top":
9365                case "up":
9366                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9367                     break;
9368                case "b":
9369                case "bottom":
9370                case "down":
9371                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9372                     break;
9373             }
9374             return this;
9375         },
9376
9377         /**
9378          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9379          * @return {Roo.Element} this
9380          */
9381         clip : function(){
9382             if(!this.isClipped){
9383                this.isClipped = true;
9384                this.originalClip = {
9385                    "o": this.getStyle("overflow"),
9386                    "x": this.getStyle("overflow-x"),
9387                    "y": this.getStyle("overflow-y")
9388                };
9389                this.setStyle("overflow", "hidden");
9390                this.setStyle("overflow-x", "hidden");
9391                this.setStyle("overflow-y", "hidden");
9392             }
9393             return this;
9394         },
9395
9396         /**
9397          *  Return clipping (overflow) to original clipping before clip() was called
9398          * @return {Roo.Element} this
9399          */
9400         unclip : function(){
9401             if(this.isClipped){
9402                 this.isClipped = false;
9403                 var o = this.originalClip;
9404                 if(o.o){this.setStyle("overflow", o.o);}
9405                 if(o.x){this.setStyle("overflow-x", o.x);}
9406                 if(o.y){this.setStyle("overflow-y", o.y);}
9407             }
9408             return this;
9409         },
9410
9411
9412         /**
9413          * Gets the x,y coordinates specified by the anchor position on the element.
9414          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9415          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9416          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9417          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9418          * @return {Array} [x, y] An array containing the element's x and y coordinates
9419          */
9420         getAnchorXY : function(anchor, local, s){
9421             //Passing a different size is useful for pre-calculating anchors,
9422             //especially for anchored animations that change the el size.
9423
9424             var w, h, vp = false;
9425             if(!s){
9426                 var d = this.dom;
9427                 if(d == document.body || d == document){
9428                     vp = true;
9429                     w = D.getViewWidth(); h = D.getViewHeight();
9430                 }else{
9431                     w = this.getWidth(); h = this.getHeight();
9432                 }
9433             }else{
9434                 w = s.width;  h = s.height;
9435             }
9436             var x = 0, y = 0, r = Math.round;
9437             switch((anchor || "tl").toLowerCase()){
9438                 case "c":
9439                     x = r(w*.5);
9440                     y = r(h*.5);
9441                 break;
9442                 case "t":
9443                     x = r(w*.5);
9444                     y = 0;
9445                 break;
9446                 case "l":
9447                     x = 0;
9448                     y = r(h*.5);
9449                 break;
9450                 case "r":
9451                     x = w;
9452                     y = r(h*.5);
9453                 break;
9454                 case "b":
9455                     x = r(w*.5);
9456                     y = h;
9457                 break;
9458                 case "tl":
9459                     x = 0;
9460                     y = 0;
9461                 break;
9462                 case "bl":
9463                     x = 0;
9464                     y = h;
9465                 break;
9466                 case "br":
9467                     x = w;
9468                     y = h;
9469                 break;
9470                 case "tr":
9471                     x = w;
9472                     y = 0;
9473                 break;
9474             }
9475             if(local === true){
9476                 return [x, y];
9477             }
9478             if(vp){
9479                 var sc = this.getScroll();
9480                 return [x + sc.left, y + sc.top];
9481             }
9482             //Add the element's offset xy
9483             var o = this.getXY();
9484             return [x+o[0], y+o[1]];
9485         },
9486
9487         /**
9488          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9489          * supported position values.
9490          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9491          * @param {String} position The position to align to.
9492          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9493          * @return {Array} [x, y]
9494          */
9495         getAlignToXY : function(el, p, o)
9496         {
9497             el = Roo.get(el);
9498             var d = this.dom;
9499             if(!el.dom){
9500                 throw "Element.alignTo with an element that doesn't exist";
9501             }
9502             var c = false; //constrain to viewport
9503             var p1 = "", p2 = "";
9504             o = o || [0,0];
9505
9506             if(!p){
9507                 p = "tl-bl";
9508             }else if(p == "?"){
9509                 p = "tl-bl?";
9510             }else if(p.indexOf("-") == -1){
9511                 p = "tl-" + p;
9512             }
9513             p = p.toLowerCase();
9514             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9515             if(!m){
9516                throw "Element.alignTo with an invalid alignment " + p;
9517             }
9518             p1 = m[1]; p2 = m[2]; c = !!m[3];
9519
9520             //Subtract the aligned el's internal xy from the target's offset xy
9521             //plus custom offset to get the aligned el's new offset xy
9522             var a1 = this.getAnchorXY(p1, true);
9523             var a2 = el.getAnchorXY(p2, false);
9524             var x = a2[0] - a1[0] + o[0];
9525             var y = a2[1] - a1[1] + o[1];
9526             if(c){
9527                 //constrain the aligned el to viewport if necessary
9528                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9529                 // 5px of margin for ie
9530                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9531
9532                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9533                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9534                 //otherwise swap the aligned el to the opposite border of the target.
9535                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9536                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9537                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9538                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9539
9540                var doc = document;
9541                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9542                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9543
9544                if((x+w) > dw + scrollX){
9545                     x = swapX ? r.left-w : dw+scrollX-w;
9546                 }
9547                if(x < scrollX){
9548                    x = swapX ? r.right : scrollX;
9549                }
9550                if((y+h) > dh + scrollY){
9551                     y = swapY ? r.top-h : dh+scrollY-h;
9552                 }
9553                if (y < scrollY){
9554                    y = swapY ? r.bottom : scrollY;
9555                }
9556             }
9557             return [x,y];
9558         },
9559
9560         // private
9561         getConstrainToXY : function(){
9562             var os = {top:0, left:0, bottom:0, right: 0};
9563
9564             return function(el, local, offsets, proposedXY){
9565                 el = Roo.get(el);
9566                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9567
9568                 var vw, vh, vx = 0, vy = 0;
9569                 if(el.dom == document.body || el.dom == document){
9570                     vw = Roo.lib.Dom.getViewWidth();
9571                     vh = Roo.lib.Dom.getViewHeight();
9572                 }else{
9573                     vw = el.dom.clientWidth;
9574                     vh = el.dom.clientHeight;
9575                     if(!local){
9576                         var vxy = el.getXY();
9577                         vx = vxy[0];
9578                         vy = vxy[1];
9579                     }
9580                 }
9581
9582                 var s = el.getScroll();
9583
9584                 vx += offsets.left + s.left;
9585                 vy += offsets.top + s.top;
9586
9587                 vw -= offsets.right;
9588                 vh -= offsets.bottom;
9589
9590                 var vr = vx+vw;
9591                 var vb = vy+vh;
9592
9593                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9594                 var x = xy[0], y = xy[1];
9595                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9596
9597                 // only move it if it needs it
9598                 var moved = false;
9599
9600                 // first validate right/bottom
9601                 if((x + w) > vr){
9602                     x = vr - w;
9603                     moved = true;
9604                 }
9605                 if((y + h) > vb){
9606                     y = vb - h;
9607                     moved = true;
9608                 }
9609                 // then make sure top/left isn't negative
9610                 if(x < vx){
9611                     x = vx;
9612                     moved = true;
9613                 }
9614                 if(y < vy){
9615                     y = vy;
9616                     moved = true;
9617                 }
9618                 return moved ? [x, y] : false;
9619             };
9620         }(),
9621
9622         // private
9623         adjustForConstraints : function(xy, parent, offsets){
9624             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9625         },
9626
9627         /**
9628          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9629          * document it aligns it to the viewport.
9630          * The position parameter is optional, and can be specified in any one of the following formats:
9631          * <ul>
9632          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9633          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9634          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9635          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9636          *   <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
9637          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9638          * </ul>
9639          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9640          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9641          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9642          * that specified in order to enforce the viewport constraints.
9643          * Following are all of the supported anchor positions:
9644     <pre>
9645     Value  Description
9646     -----  -----------------------------
9647     tl     The top left corner (default)
9648     t      The center of the top edge
9649     tr     The top right corner
9650     l      The center of the left edge
9651     c      In the center of the element
9652     r      The center of the right edge
9653     bl     The bottom left corner
9654     b      The center of the bottom edge
9655     br     The bottom right corner
9656     </pre>
9657     Example Usage:
9658     <pre><code>
9659     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9660     el.alignTo("other-el");
9661
9662     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9663     el.alignTo("other-el", "tr?");
9664
9665     // align the bottom right corner of el with the center left edge of other-el
9666     el.alignTo("other-el", "br-l?");
9667
9668     // align the center of el with the bottom left corner of other-el and
9669     // adjust the x position by -6 pixels (and the y position by 0)
9670     el.alignTo("other-el", "c-bl", [-6, 0]);
9671     </code></pre>
9672          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9673          * @param {String} position The position to align to.
9674          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9675          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9676          * @return {Roo.Element} this
9677          */
9678         alignTo : function(element, position, offsets, animate){
9679             var xy = this.getAlignToXY(element, position, offsets);
9680             this.setXY(xy, this.preanim(arguments, 3));
9681             return this;
9682         },
9683
9684         /**
9685          * Anchors an element to another element and realigns it when the window is resized.
9686          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9687          * @param {String} position The position to align to.
9688          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9689          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9690          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9691          * is a number, it is used as the buffer delay (defaults to 50ms).
9692          * @param {Function} callback The function to call after the animation finishes
9693          * @return {Roo.Element} this
9694          */
9695         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9696             var action = function(){
9697                 this.alignTo(el, alignment, offsets, animate);
9698                 Roo.callback(callback, this);
9699             };
9700             Roo.EventManager.onWindowResize(action, this);
9701             var tm = typeof monitorScroll;
9702             if(tm != 'undefined'){
9703                 Roo.EventManager.on(window, 'scroll', action, this,
9704                     {buffer: tm == 'number' ? monitorScroll : 50});
9705             }
9706             action.call(this); // align immediately
9707             return this;
9708         },
9709         /**
9710          * Clears any opacity settings from this element. Required in some cases for IE.
9711          * @return {Roo.Element} this
9712          */
9713         clearOpacity : function(){
9714             if (window.ActiveXObject) {
9715                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9716                     this.dom.style.filter = "";
9717                 }
9718             } else {
9719                 this.dom.style.opacity = "";
9720                 this.dom.style["-moz-opacity"] = "";
9721                 this.dom.style["-khtml-opacity"] = "";
9722             }
9723             return this;
9724         },
9725
9726         /**
9727          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9728          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9729          * @return {Roo.Element} this
9730          */
9731         hide : function(animate){
9732             this.setVisible(false, this.preanim(arguments, 0));
9733             return this;
9734         },
9735
9736         /**
9737         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9738         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9739          * @return {Roo.Element} this
9740          */
9741         show : function(animate){
9742             this.setVisible(true, this.preanim(arguments, 0));
9743             return this;
9744         },
9745
9746         /**
9747          * @private Test if size has a unit, otherwise appends the default
9748          */
9749         addUnits : function(size){
9750             return Roo.Element.addUnits(size, this.defaultUnit);
9751         },
9752
9753         /**
9754          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9755          * @return {Roo.Element} this
9756          */
9757         beginMeasure : function(){
9758             var el = this.dom;
9759             if(el.offsetWidth || el.offsetHeight){
9760                 return this; // offsets work already
9761             }
9762             var changed = [];
9763             var p = this.dom, b = document.body; // start with this element
9764             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9765                 var pe = Roo.get(p);
9766                 if(pe.getStyle('display') == 'none'){
9767                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9768                     p.style.visibility = "hidden";
9769                     p.style.display = "block";
9770                 }
9771                 p = p.parentNode;
9772             }
9773             this._measureChanged = changed;
9774             return this;
9775
9776         },
9777
9778         /**
9779          * Restores displays to before beginMeasure was called
9780          * @return {Roo.Element} this
9781          */
9782         endMeasure : function(){
9783             var changed = this._measureChanged;
9784             if(changed){
9785                 for(var i = 0, len = changed.length; i < len; i++) {
9786                     var r = changed[i];
9787                     r.el.style.visibility = r.visibility;
9788                     r.el.style.display = "none";
9789                 }
9790                 this._measureChanged = null;
9791             }
9792             return this;
9793         },
9794
9795         /**
9796         * Update the innerHTML of this element, optionally searching for and processing scripts
9797         * @param {String} html The new HTML
9798         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9799         * @param {Function} callback For async script loading you can be noticed when the update completes
9800         * @return {Roo.Element} this
9801          */
9802         update : function(html, loadScripts, callback){
9803             if(typeof html == "undefined"){
9804                 html = "";
9805             }
9806             if(loadScripts !== true){
9807                 this.dom.innerHTML = html;
9808                 if(typeof callback == "function"){
9809                     callback();
9810                 }
9811                 return this;
9812             }
9813             var id = Roo.id();
9814             var dom = this.dom;
9815
9816             html += '<span id="' + id + '"></span>';
9817
9818             E.onAvailable(id, function(){
9819                 var hd = document.getElementsByTagName("head")[0];
9820                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9821                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9822                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9823
9824                 var match;
9825                 while(match = re.exec(html)){
9826                     var attrs = match[1];
9827                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9828                     if(srcMatch && srcMatch[2]){
9829                        var s = document.createElement("script");
9830                        s.src = srcMatch[2];
9831                        var typeMatch = attrs.match(typeRe);
9832                        if(typeMatch && typeMatch[2]){
9833                            s.type = typeMatch[2];
9834                        }
9835                        hd.appendChild(s);
9836                     }else if(match[2] && match[2].length > 0){
9837                         if(window.execScript) {
9838                            window.execScript(match[2]);
9839                         } else {
9840                             /**
9841                              * eval:var:id
9842                              * eval:var:dom
9843                              * eval:var:html
9844                              * 
9845                              */
9846                            window.eval(match[2]);
9847                         }
9848                     }
9849                 }
9850                 var el = document.getElementById(id);
9851                 if(el){el.parentNode.removeChild(el);}
9852                 if(typeof callback == "function"){
9853                     callback();
9854                 }
9855             });
9856             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9857             return this;
9858         },
9859
9860         /**
9861          * Direct access to the UpdateManager update() method (takes the same parameters).
9862          * @param {String/Function} url The url for this request or a function to call to get the url
9863          * @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}
9864          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9865          * @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.
9866          * @return {Roo.Element} this
9867          */
9868         load : function(){
9869             var um = this.getUpdateManager();
9870             um.update.apply(um, arguments);
9871             return this;
9872         },
9873
9874         /**
9875         * Gets this element's UpdateManager
9876         * @return {Roo.UpdateManager} The UpdateManager
9877         */
9878         getUpdateManager : function(){
9879             if(!this.updateManager){
9880                 this.updateManager = new Roo.UpdateManager(this);
9881             }
9882             return this.updateManager;
9883         },
9884
9885         /**
9886          * Disables text selection for this element (normalized across browsers)
9887          * @return {Roo.Element} this
9888          */
9889         unselectable : function(){
9890             this.dom.unselectable = "on";
9891             this.swallowEvent("selectstart", true);
9892             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9893             this.addClass("x-unselectable");
9894             return this;
9895         },
9896
9897         /**
9898         * Calculates the x, y to center this element on the screen
9899         * @return {Array} The x, y values [x, y]
9900         */
9901         getCenterXY : function(){
9902             return this.getAlignToXY(document, 'c-c');
9903         },
9904
9905         /**
9906         * Centers the Element in either the viewport, or another Element.
9907         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9908         */
9909         center : function(centerIn){
9910             this.alignTo(centerIn || document, 'c-c');
9911             return this;
9912         },
9913
9914         /**
9915          * Tests various css rules/browsers to determine if this element uses a border box
9916          * @return {Boolean}
9917          */
9918         isBorderBox : function(){
9919             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9920         },
9921
9922         /**
9923          * Return a box {x, y, width, height} that can be used to set another elements
9924          * size/location to match this element.
9925          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9926          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9927          * @return {Object} box An object in the format {x, y, width, height}
9928          */
9929         getBox : function(contentBox, local){
9930             var xy;
9931             if(!local){
9932                 xy = this.getXY();
9933             }else{
9934                 var left = parseInt(this.getStyle("left"), 10) || 0;
9935                 var top = parseInt(this.getStyle("top"), 10) || 0;
9936                 xy = [left, top];
9937             }
9938             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9939             if(!contentBox){
9940                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9941             }else{
9942                 var l = this.getBorderWidth("l")+this.getPadding("l");
9943                 var r = this.getBorderWidth("r")+this.getPadding("r");
9944                 var t = this.getBorderWidth("t")+this.getPadding("t");
9945                 var b = this.getBorderWidth("b")+this.getPadding("b");
9946                 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)};
9947             }
9948             bx.right = bx.x + bx.width;
9949             bx.bottom = bx.y + bx.height;
9950             return bx;
9951         },
9952
9953         /**
9954          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9955          for more information about the sides.
9956          * @param {String} sides
9957          * @return {Number}
9958          */
9959         getFrameWidth : function(sides, onlyContentBox){
9960             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9961         },
9962
9963         /**
9964          * 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.
9965          * @param {Object} box The box to fill {x, y, width, height}
9966          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9967          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9968          * @return {Roo.Element} this
9969          */
9970         setBox : function(box, adjust, animate){
9971             var w = box.width, h = box.height;
9972             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9973                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9974                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9975             }
9976             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9977             return this;
9978         },
9979
9980         /**
9981          * Forces the browser to repaint this element
9982          * @return {Roo.Element} this
9983          */
9984          repaint : function(){
9985             var dom = this.dom;
9986             this.addClass("x-repaint");
9987             setTimeout(function(){
9988                 Roo.get(dom).removeClass("x-repaint");
9989             }, 1);
9990             return this;
9991         },
9992
9993         /**
9994          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9995          * then it returns the calculated width of the sides (see getPadding)
9996          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9997          * @return {Object/Number}
9998          */
9999         getMargins : function(side){
10000             if(!side){
10001                 return {
10002                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10003                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10004                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10005                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10006                 };
10007             }else{
10008                 return this.addStyles(side, El.margins);
10009              }
10010         },
10011
10012         // private
10013         addStyles : function(sides, styles){
10014             var val = 0, v, w;
10015             for(var i = 0, len = sides.length; i < len; i++){
10016                 v = this.getStyle(styles[sides.charAt(i)]);
10017                 if(v){
10018                      w = parseInt(v, 10);
10019                      if(w){ val += w; }
10020                 }
10021             }
10022             return val;
10023         },
10024
10025         /**
10026          * Creates a proxy element of this element
10027          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10028          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10029          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10030          * @return {Roo.Element} The new proxy element
10031          */
10032         createProxy : function(config, renderTo, matchBox){
10033             if(renderTo){
10034                 renderTo = Roo.getDom(renderTo);
10035             }else{
10036                 renderTo = document.body;
10037             }
10038             config = typeof config == "object" ?
10039                 config : {tag : "div", cls: config};
10040             var proxy = Roo.DomHelper.append(renderTo, config, true);
10041             if(matchBox){
10042                proxy.setBox(this.getBox());
10043             }
10044             return proxy;
10045         },
10046
10047         /**
10048          * Puts a mask over this element to disable user interaction. Requires core.css.
10049          * This method can only be applied to elements which accept child nodes.
10050          * @param {String} msg (optional) A message to display in the mask
10051          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10052          * @return {Element} The mask  element
10053          */
10054         mask : function(msg, msgCls)
10055         {
10056             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10057                 this.setStyle("position", "relative");
10058             }
10059             if(!this._mask){
10060                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10061             }
10062             
10063             this.addClass("x-masked");
10064             this._mask.setDisplayed(true);
10065             
10066             // we wander
10067             var z = 0;
10068             var dom = this.dom;
10069             while (dom && dom.style) {
10070                 if (!isNaN(parseInt(dom.style.zIndex))) {
10071                     z = Math.max(z, parseInt(dom.style.zIndex));
10072                 }
10073                 dom = dom.parentNode;
10074             }
10075             // if we are masking the body - then it hides everything..
10076             if (this.dom == document.body) {
10077                 z = 1000000;
10078                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10079                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10080             }
10081            
10082             if(typeof msg == 'string'){
10083                 if(!this._maskMsg){
10084                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10085                         cls: "roo-el-mask-msg", 
10086                         cn: [
10087                             {
10088                                 tag: 'i',
10089                                 cls: 'fa fa-spinner fa-spin'
10090                             },
10091                             {
10092                                 tag: 'div'
10093                             }   
10094                         ]
10095                     }, true);
10096                 }
10097                 var mm = this._maskMsg;
10098                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10099                 if (mm.dom.lastChild) { // weird IE issue?
10100                     mm.dom.lastChild.innerHTML = msg;
10101                 }
10102                 mm.setDisplayed(true);
10103                 mm.center(this);
10104                 mm.setStyle('z-index', z + 102);
10105             }
10106             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10107                 this._mask.setHeight(this.getHeight());
10108             }
10109             this._mask.setStyle('z-index', z + 100);
10110             
10111             return this._mask;
10112         },
10113
10114         /**
10115          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10116          * it is cached for reuse.
10117          */
10118         unmask : function(removeEl){
10119             if(this._mask){
10120                 if(removeEl === true){
10121                     this._mask.remove();
10122                     delete this._mask;
10123                     if(this._maskMsg){
10124                         this._maskMsg.remove();
10125                         delete this._maskMsg;
10126                     }
10127                 }else{
10128                     this._mask.setDisplayed(false);
10129                     if(this._maskMsg){
10130                         this._maskMsg.setDisplayed(false);
10131                     }
10132                 }
10133             }
10134             this.removeClass("x-masked");
10135         },
10136
10137         /**
10138          * Returns true if this element is masked
10139          * @return {Boolean}
10140          */
10141         isMasked : function(){
10142             return this._mask && this._mask.isVisible();
10143         },
10144
10145         /**
10146          * Creates an iframe shim for this element to keep selects and other windowed objects from
10147          * showing through.
10148          * @return {Roo.Element} The new shim element
10149          */
10150         createShim : function(){
10151             var el = document.createElement('iframe');
10152             el.frameBorder = 'no';
10153             el.className = 'roo-shim';
10154             if(Roo.isIE && Roo.isSecure){
10155                 el.src = Roo.SSL_SECURE_URL;
10156             }
10157             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10158             shim.autoBoxAdjust = false;
10159             return shim;
10160         },
10161
10162         /**
10163          * Removes this element from the DOM and deletes it from the cache
10164          */
10165         remove : function(){
10166             if(this.dom.parentNode){
10167                 this.dom.parentNode.removeChild(this.dom);
10168             }
10169             delete El.cache[this.dom.id];
10170         },
10171
10172         /**
10173          * Sets up event handlers to add and remove a css class when the mouse is over this element
10174          * @param {String} className
10175          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10176          * mouseout events for children elements
10177          * @return {Roo.Element} this
10178          */
10179         addClassOnOver : function(className, preventFlicker){
10180             this.on("mouseover", function(){
10181                 Roo.fly(this, '_internal').addClass(className);
10182             }, this.dom);
10183             var removeFn = function(e){
10184                 if(preventFlicker !== true || !e.within(this, true)){
10185                     Roo.fly(this, '_internal').removeClass(className);
10186                 }
10187             };
10188             this.on("mouseout", removeFn, this.dom);
10189             return this;
10190         },
10191
10192         /**
10193          * Sets up event handlers to add and remove a css class when this element has the focus
10194          * @param {String} className
10195          * @return {Roo.Element} this
10196          */
10197         addClassOnFocus : function(className){
10198             this.on("focus", function(){
10199                 Roo.fly(this, '_internal').addClass(className);
10200             }, this.dom);
10201             this.on("blur", function(){
10202                 Roo.fly(this, '_internal').removeClass(className);
10203             }, this.dom);
10204             return this;
10205         },
10206         /**
10207          * 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)
10208          * @param {String} className
10209          * @return {Roo.Element} this
10210          */
10211         addClassOnClick : function(className){
10212             var dom = this.dom;
10213             this.on("mousedown", function(){
10214                 Roo.fly(dom, '_internal').addClass(className);
10215                 var d = Roo.get(document);
10216                 var fn = function(){
10217                     Roo.fly(dom, '_internal').removeClass(className);
10218                     d.removeListener("mouseup", fn);
10219                 };
10220                 d.on("mouseup", fn);
10221             });
10222             return this;
10223         },
10224
10225         /**
10226          * Stops the specified event from bubbling and optionally prevents the default action
10227          * @param {String} eventName
10228          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10229          * @return {Roo.Element} this
10230          */
10231         swallowEvent : function(eventName, preventDefault){
10232             var fn = function(e){
10233                 e.stopPropagation();
10234                 if(preventDefault){
10235                     e.preventDefault();
10236                 }
10237             };
10238             if(eventName instanceof Array){
10239                 for(var i = 0, len = eventName.length; i < len; i++){
10240                      this.on(eventName[i], fn);
10241                 }
10242                 return this;
10243             }
10244             this.on(eventName, fn);
10245             return this;
10246         },
10247
10248         /**
10249          * @private
10250          */
10251         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10252
10253         /**
10254          * Sizes this element to its parent element's dimensions performing
10255          * neccessary box adjustments.
10256          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10257          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10258          * @return {Roo.Element} this
10259          */
10260         fitToParent : function(monitorResize, targetParent) {
10261           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10262           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10263           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10264             return this;
10265           }
10266           var p = Roo.get(targetParent || this.dom.parentNode);
10267           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10268           if (monitorResize === true) {
10269             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10270             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10271           }
10272           return this;
10273         },
10274
10275         /**
10276          * Gets the next sibling, skipping text nodes
10277          * @return {HTMLElement} The next sibling or null
10278          */
10279         getNextSibling : function(){
10280             var n = this.dom.nextSibling;
10281             while(n && n.nodeType != 1){
10282                 n = n.nextSibling;
10283             }
10284             return n;
10285         },
10286
10287         /**
10288          * Gets the previous sibling, skipping text nodes
10289          * @return {HTMLElement} The previous sibling or null
10290          */
10291         getPrevSibling : function(){
10292             var n = this.dom.previousSibling;
10293             while(n && n.nodeType != 1){
10294                 n = n.previousSibling;
10295             }
10296             return n;
10297         },
10298
10299
10300         /**
10301          * Appends the passed element(s) to this element
10302          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10303          * @return {Roo.Element} this
10304          */
10305         appendChild: function(el){
10306             el = Roo.get(el);
10307             el.appendTo(this);
10308             return this;
10309         },
10310
10311         /**
10312          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10313          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10314          * automatically generated with the specified attributes.
10315          * @param {HTMLElement} insertBefore (optional) a child element of this element
10316          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10317          * @return {Roo.Element} The new child element
10318          */
10319         createChild: function(config, insertBefore, returnDom){
10320             config = config || {tag:'div'};
10321             if(insertBefore){
10322                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10323             }
10324             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10325         },
10326
10327         /**
10328          * Appends this element to the passed element
10329          * @param {String/HTMLElement/Element} el The new parent element
10330          * @return {Roo.Element} this
10331          */
10332         appendTo: function(el){
10333             el = Roo.getDom(el);
10334             el.appendChild(this.dom);
10335             return this;
10336         },
10337
10338         /**
10339          * Inserts this element before the passed element in the DOM
10340          * @param {String/HTMLElement/Element} el The element to insert before
10341          * @return {Roo.Element} this
10342          */
10343         insertBefore: function(el){
10344             el = Roo.getDom(el);
10345             el.parentNode.insertBefore(this.dom, el);
10346             return this;
10347         },
10348
10349         /**
10350          * Inserts this element after the passed element in the DOM
10351          * @param {String/HTMLElement/Element} el The element to insert after
10352          * @return {Roo.Element} this
10353          */
10354         insertAfter: function(el){
10355             el = Roo.getDom(el);
10356             el.parentNode.insertBefore(this.dom, el.nextSibling);
10357             return this;
10358         },
10359
10360         /**
10361          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10362          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10363          * @return {Roo.Element} The new child
10364          */
10365         insertFirst: function(el, returnDom){
10366             el = el || {};
10367             if(typeof el == 'object' && !el.nodeType){ // dh config
10368                 return this.createChild(el, this.dom.firstChild, returnDom);
10369             }else{
10370                 el = Roo.getDom(el);
10371                 this.dom.insertBefore(el, this.dom.firstChild);
10372                 return !returnDom ? Roo.get(el) : el;
10373             }
10374         },
10375
10376         /**
10377          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10378          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10379          * @param {String} where (optional) 'before' or 'after' defaults to before
10380          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10381          * @return {Roo.Element} the inserted Element
10382          */
10383         insertSibling: function(el, where, returnDom){
10384             where = where ? where.toLowerCase() : 'before';
10385             el = el || {};
10386             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10387
10388             if(typeof el == 'object' && !el.nodeType){ // dh config
10389                 if(where == 'after' && !this.dom.nextSibling){
10390                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10391                 }else{
10392                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10393                 }
10394
10395             }else{
10396                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10397                             where == 'before' ? this.dom : this.dom.nextSibling);
10398                 if(!returnDom){
10399                     rt = Roo.get(rt);
10400                 }
10401             }
10402             return rt;
10403         },
10404
10405         /**
10406          * Creates and wraps this element with another element
10407          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10408          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10409          * @return {HTMLElement/Element} The newly created wrapper element
10410          */
10411         wrap: function(config, returnDom){
10412             if(!config){
10413                 config = {tag: "div"};
10414             }
10415             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10416             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10417             return newEl;
10418         },
10419
10420         /**
10421          * Replaces the passed element with this element
10422          * @param {String/HTMLElement/Element} el The element to replace
10423          * @return {Roo.Element} this
10424          */
10425         replace: function(el){
10426             el = Roo.get(el);
10427             this.insertBefore(el);
10428             el.remove();
10429             return this;
10430         },
10431
10432         /**
10433          * Inserts an html fragment into this element
10434          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10435          * @param {String} html The HTML fragment
10436          * @param {Boolean} returnEl True to return an Roo.Element
10437          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10438          */
10439         insertHtml : function(where, html, returnEl){
10440             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10441             return returnEl ? Roo.get(el) : el;
10442         },
10443
10444         /**
10445          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10446          * @param {Object} o The object with the attributes
10447          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10448          * @return {Roo.Element} this
10449          */
10450         set : function(o, useSet){
10451             var el = this.dom;
10452             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10453             for(var attr in o){
10454                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10455                 if(attr=="cls"){
10456                     el.className = o["cls"];
10457                 }else{
10458                     if(useSet) {
10459                         el.setAttribute(attr, o[attr]);
10460                     } else {
10461                         el[attr] = o[attr];
10462                     }
10463                 }
10464             }
10465             if(o.style){
10466                 Roo.DomHelper.applyStyles(el, o.style);
10467             }
10468             return this;
10469         },
10470
10471         /**
10472          * Convenience method for constructing a KeyMap
10473          * @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:
10474          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10475          * @param {Function} fn The function to call
10476          * @param {Object} scope (optional) The scope of the function
10477          * @return {Roo.KeyMap} The KeyMap created
10478          */
10479         addKeyListener : function(key, fn, scope){
10480             var config;
10481             if(typeof key != "object" || key instanceof Array){
10482                 config = {
10483                     key: key,
10484                     fn: fn,
10485                     scope: scope
10486                 };
10487             }else{
10488                 config = {
10489                     key : key.key,
10490                     shift : key.shift,
10491                     ctrl : key.ctrl,
10492                     alt : key.alt,
10493                     fn: fn,
10494                     scope: scope
10495                 };
10496             }
10497             return new Roo.KeyMap(this, config);
10498         },
10499
10500         /**
10501          * Creates a KeyMap for this element
10502          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10503          * @return {Roo.KeyMap} The KeyMap created
10504          */
10505         addKeyMap : function(config){
10506             return new Roo.KeyMap(this, config);
10507         },
10508
10509         /**
10510          * Returns true if this element is scrollable.
10511          * @return {Boolean}
10512          */
10513          isScrollable : function(){
10514             var dom = this.dom;
10515             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10516         },
10517
10518         /**
10519          * 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().
10520          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10521          * @param {Number} value The new scroll value
10522          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10523          * @return {Element} this
10524          */
10525
10526         scrollTo : function(side, value, animate){
10527             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10528             if(!animate || !A){
10529                 this.dom[prop] = value;
10530             }else{
10531                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10532                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10533             }
10534             return this;
10535         },
10536
10537         /**
10538          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10539          * within this element's scrollable range.
10540          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10541          * @param {Number} distance How far to scroll the element in pixels
10542          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10543          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10544          * was scrolled as far as it could go.
10545          */
10546          scroll : function(direction, distance, animate){
10547              if(!this.isScrollable()){
10548                  return;
10549              }
10550              var el = this.dom;
10551              var l = el.scrollLeft, t = el.scrollTop;
10552              var w = el.scrollWidth, h = el.scrollHeight;
10553              var cw = el.clientWidth, ch = el.clientHeight;
10554              direction = direction.toLowerCase();
10555              var scrolled = false;
10556              var a = this.preanim(arguments, 2);
10557              switch(direction){
10558                  case "l":
10559                  case "left":
10560                      if(w - l > cw){
10561                          var v = Math.min(l + distance, w-cw);
10562                          this.scrollTo("left", v, a);
10563                          scrolled = true;
10564                      }
10565                      break;
10566                 case "r":
10567                 case "right":
10568                      if(l > 0){
10569                          var v = Math.max(l - distance, 0);
10570                          this.scrollTo("left", v, a);
10571                          scrolled = true;
10572                      }
10573                      break;
10574                 case "t":
10575                 case "top":
10576                 case "up":
10577                      if(t > 0){
10578                          var v = Math.max(t - distance, 0);
10579                          this.scrollTo("top", v, a);
10580                          scrolled = true;
10581                      }
10582                      break;
10583                 case "b":
10584                 case "bottom":
10585                 case "down":
10586                      if(h - t > ch){
10587                          var v = Math.min(t + distance, h-ch);
10588                          this.scrollTo("top", v, a);
10589                          scrolled = true;
10590                      }
10591                      break;
10592              }
10593              return scrolled;
10594         },
10595
10596         /**
10597          * Translates the passed page coordinates into left/top css values for this element
10598          * @param {Number/Array} x The page x or an array containing [x, y]
10599          * @param {Number} y The page y
10600          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10601          */
10602         translatePoints : function(x, y){
10603             if(typeof x == 'object' || x instanceof Array){
10604                 y = x[1]; x = x[0];
10605             }
10606             var p = this.getStyle('position');
10607             var o = this.getXY();
10608
10609             var l = parseInt(this.getStyle('left'), 10);
10610             var t = parseInt(this.getStyle('top'), 10);
10611
10612             if(isNaN(l)){
10613                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10614             }
10615             if(isNaN(t)){
10616                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10617             }
10618
10619             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10620         },
10621
10622         /**
10623          * Returns the current scroll position of the element.
10624          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10625          */
10626         getScroll : function(){
10627             var d = this.dom, doc = document;
10628             if(d == doc || d == doc.body){
10629                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10630                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10631                 return {left: l, top: t};
10632             }else{
10633                 return {left: d.scrollLeft, top: d.scrollTop};
10634             }
10635         },
10636
10637         /**
10638          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10639          * are convert to standard 6 digit hex color.
10640          * @param {String} attr The css attribute
10641          * @param {String} defaultValue The default value to use when a valid color isn't found
10642          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10643          * YUI color anims.
10644          */
10645         getColor : function(attr, defaultValue, prefix){
10646             var v = this.getStyle(attr);
10647             if(!v || v == "transparent" || v == "inherit") {
10648                 return defaultValue;
10649             }
10650             var color = typeof prefix == "undefined" ? "#" : prefix;
10651             if(v.substr(0, 4) == "rgb("){
10652                 var rvs = v.slice(4, v.length -1).split(",");
10653                 for(var i = 0; i < 3; i++){
10654                     var h = parseInt(rvs[i]).toString(16);
10655                     if(h < 16){
10656                         h = "0" + h;
10657                     }
10658                     color += h;
10659                 }
10660             } else {
10661                 if(v.substr(0, 1) == "#"){
10662                     if(v.length == 4) {
10663                         for(var i = 1; i < 4; i++){
10664                             var c = v.charAt(i);
10665                             color +=  c + c;
10666                         }
10667                     }else if(v.length == 7){
10668                         color += v.substr(1);
10669                     }
10670                 }
10671             }
10672             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10673         },
10674
10675         /**
10676          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10677          * gradient background, rounded corners and a 4-way shadow.
10678          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10679          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10680          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10681          * @return {Roo.Element} this
10682          */
10683         boxWrap : function(cls){
10684             cls = cls || 'x-box';
10685             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10686             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10687             return el;
10688         },
10689
10690         /**
10691          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10692          * @param {String} namespace The namespace in which to look for the attribute
10693          * @param {String} name The attribute name
10694          * @return {String} The attribute value
10695          */
10696         getAttributeNS : Roo.isIE ? function(ns, name){
10697             var d = this.dom;
10698             var type = typeof d[ns+":"+name];
10699             if(type != 'undefined' && type != 'unknown'){
10700                 return d[ns+":"+name];
10701             }
10702             return d[name];
10703         } : function(ns, name){
10704             var d = this.dom;
10705             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10706         },
10707         
10708         
10709         /**
10710          * Sets or Returns the value the dom attribute value
10711          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10712          * @param {String} value (optional) The value to set the attribute to
10713          * @return {String} The attribute value
10714          */
10715         attr : function(name){
10716             if (arguments.length > 1) {
10717                 this.dom.setAttribute(name, arguments[1]);
10718                 return arguments[1];
10719             }
10720             if (typeof(name) == 'object') {
10721                 for(var i in name) {
10722                     this.attr(i, name[i]);
10723                 }
10724                 return name;
10725             }
10726             
10727             
10728             if (!this.dom.hasAttribute(name)) {
10729                 return undefined;
10730             }
10731             return this.dom.getAttribute(name);
10732         }
10733         
10734         
10735         
10736     };
10737
10738     var ep = El.prototype;
10739
10740     /**
10741      * Appends an event handler (Shorthand for addListener)
10742      * @param {String}   eventName     The type of event to append
10743      * @param {Function} fn        The method the event invokes
10744      * @param {Object} scope       (optional) The scope (this object) of the fn
10745      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10746      * @method
10747      */
10748     ep.on = ep.addListener;
10749         // backwards compat
10750     ep.mon = ep.addListener;
10751
10752     /**
10753      * Removes an event handler from this element (shorthand for removeListener)
10754      * @param {String} eventName the type of event to remove
10755      * @param {Function} fn the method the event invokes
10756      * @return {Roo.Element} this
10757      * @method
10758      */
10759     ep.un = ep.removeListener;
10760
10761     /**
10762      * true to automatically adjust width and height settings for box-model issues (default to true)
10763      */
10764     ep.autoBoxAdjust = true;
10765
10766     // private
10767     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10768
10769     // private
10770     El.addUnits = function(v, defaultUnit){
10771         if(v === "" || v == "auto"){
10772             return v;
10773         }
10774         if(v === undefined){
10775             return '';
10776         }
10777         if(typeof v == "number" || !El.unitPattern.test(v)){
10778             return v + (defaultUnit || 'px');
10779         }
10780         return v;
10781     };
10782
10783     // special markup used throughout Roo when box wrapping elements
10784     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>';
10785     /**
10786      * Visibility mode constant - Use visibility to hide element
10787      * @static
10788      * @type Number
10789      */
10790     El.VISIBILITY = 1;
10791     /**
10792      * Visibility mode constant - Use display to hide element
10793      * @static
10794      * @type Number
10795      */
10796     El.DISPLAY = 2;
10797
10798     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10799     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10800     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10801
10802
10803
10804     /**
10805      * @private
10806      */
10807     El.cache = {};
10808
10809     var docEl;
10810
10811     /**
10812      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10813      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10814      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10815      * @return {Element} The Element object
10816      * @static
10817      */
10818     El.get = function(el){
10819         var ex, elm, id;
10820         if(!el){ return null; }
10821         if(typeof el == "string"){ // element id
10822             if(!(elm = document.getElementById(el))){
10823                 return null;
10824             }
10825             if(ex = El.cache[el]){
10826                 ex.dom = elm;
10827             }else{
10828                 ex = El.cache[el] = new El(elm);
10829             }
10830             return ex;
10831         }else if(el.tagName){ // dom element
10832             if(!(id = el.id)){
10833                 id = Roo.id(el);
10834             }
10835             if(ex = El.cache[id]){
10836                 ex.dom = el;
10837             }else{
10838                 ex = El.cache[id] = new El(el);
10839             }
10840             return ex;
10841         }else if(el instanceof El){
10842             if(el != docEl){
10843                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10844                                                               // catch case where it hasn't been appended
10845                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10846             }
10847             return el;
10848         }else if(el.isComposite){
10849             return el;
10850         }else if(el instanceof Array){
10851             return El.select(el);
10852         }else if(el == document){
10853             // create a bogus element object representing the document object
10854             if(!docEl){
10855                 var f = function(){};
10856                 f.prototype = El.prototype;
10857                 docEl = new f();
10858                 docEl.dom = document;
10859             }
10860             return docEl;
10861         }
10862         return null;
10863     };
10864
10865     // private
10866     El.uncache = function(el){
10867         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10868             if(a[i]){
10869                 delete El.cache[a[i].id || a[i]];
10870             }
10871         }
10872     };
10873
10874     // private
10875     // Garbage collection - uncache elements/purge listeners on orphaned elements
10876     // so we don't hold a reference and cause the browser to retain them
10877     El.garbageCollect = function(){
10878         if(!Roo.enableGarbageCollector){
10879             clearInterval(El.collectorThread);
10880             return;
10881         }
10882         for(var eid in El.cache){
10883             var el = El.cache[eid], d = el.dom;
10884             // -------------------------------------------------------
10885             // Determining what is garbage:
10886             // -------------------------------------------------------
10887             // !d
10888             // dom node is null, definitely garbage
10889             // -------------------------------------------------------
10890             // !d.parentNode
10891             // no parentNode == direct orphan, definitely garbage
10892             // -------------------------------------------------------
10893             // !d.offsetParent && !document.getElementById(eid)
10894             // display none elements have no offsetParent so we will
10895             // also try to look it up by it's id. However, check
10896             // offsetParent first so we don't do unneeded lookups.
10897             // This enables collection of elements that are not orphans
10898             // directly, but somewhere up the line they have an orphan
10899             // parent.
10900             // -------------------------------------------------------
10901             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10902                 delete El.cache[eid];
10903                 if(d && Roo.enableListenerCollection){
10904                     E.purgeElement(d);
10905                 }
10906             }
10907         }
10908     }
10909     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10910
10911
10912     // dom is optional
10913     El.Flyweight = function(dom){
10914         this.dom = dom;
10915     };
10916     El.Flyweight.prototype = El.prototype;
10917
10918     El._flyweights = {};
10919     /**
10920      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10921      * the dom node can be overwritten by other code.
10922      * @param {String/HTMLElement} el The dom node or id
10923      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10924      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10925      * @static
10926      * @return {Element} The shared Element object
10927      */
10928     El.fly = function(el, named){
10929         named = named || '_global';
10930         el = Roo.getDom(el);
10931         if(!el){
10932             return null;
10933         }
10934         if(!El._flyweights[named]){
10935             El._flyweights[named] = new El.Flyweight();
10936         }
10937         El._flyweights[named].dom = el;
10938         return El._flyweights[named];
10939     };
10940
10941     /**
10942      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10943      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10944      * Shorthand of {@link Roo.Element#get}
10945      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10946      * @return {Element} The Element object
10947      * @member Roo
10948      * @method get
10949      */
10950     Roo.get = El.get;
10951     /**
10952      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10953      * the dom node can be overwritten by other code.
10954      * Shorthand of {@link Roo.Element#fly}
10955      * @param {String/HTMLElement} el The dom node or id
10956      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10957      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10958      * @static
10959      * @return {Element} The shared Element object
10960      * @member Roo
10961      * @method fly
10962      */
10963     Roo.fly = El.fly;
10964
10965     // speedy lookup for elements never to box adjust
10966     var noBoxAdjust = Roo.isStrict ? {
10967         select:1
10968     } : {
10969         input:1, select:1, textarea:1
10970     };
10971     if(Roo.isIE || Roo.isGecko){
10972         noBoxAdjust['button'] = 1;
10973     }
10974
10975
10976     Roo.EventManager.on(window, 'unload', function(){
10977         delete El.cache;
10978         delete El._flyweights;
10979     });
10980 })();
10981
10982
10983
10984
10985 if(Roo.DomQuery){
10986     Roo.Element.selectorFunction = Roo.DomQuery.select;
10987 }
10988
10989 Roo.Element.select = function(selector, unique, root){
10990     var els;
10991     if(typeof selector == "string"){
10992         els = Roo.Element.selectorFunction(selector, root);
10993     }else if(selector.length !== undefined){
10994         els = selector;
10995     }else{
10996         throw "Invalid selector";
10997     }
10998     if(unique === true){
10999         return new Roo.CompositeElement(els);
11000     }else{
11001         return new Roo.CompositeElementLite(els);
11002     }
11003 };
11004 /**
11005  * Selects elements based on the passed CSS selector to enable working on them as 1.
11006  * @param {String/Array} selector The CSS selector or an array of elements
11007  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11008  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11009  * @return {CompositeElementLite/CompositeElement}
11010  * @member Roo
11011  * @method select
11012  */
11013 Roo.select = Roo.Element.select;
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027
11028 /*
11029  * Based on:
11030  * Ext JS Library 1.1.1
11031  * Copyright(c) 2006-2007, Ext JS, LLC.
11032  *
11033  * Originally Released Under LGPL - original licence link has changed is not relivant.
11034  *
11035  * Fork - LGPL
11036  * <script type="text/javascript">
11037  */
11038
11039
11040
11041 //Notifies Element that fx methods are available
11042 Roo.enableFx = true;
11043
11044 /**
11045  * @class Roo.Fx
11046  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11047  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11048  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11049  * Element effects to work.</p><br/>
11050  *
11051  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11052  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11053  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11054  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11055  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11056  * expected results and should be done with care.</p><br/>
11057  *
11058  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11059  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11060 <pre>
11061 Value  Description
11062 -----  -----------------------------
11063 tl     The top left corner
11064 t      The center of the top edge
11065 tr     The top right corner
11066 l      The center of the left edge
11067 r      The center of the right edge
11068 bl     The bottom left corner
11069 b      The center of the bottom edge
11070 br     The bottom right corner
11071 </pre>
11072  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11073  * below are common options that can be passed to any Fx method.</b>
11074  * @cfg {Function} callback A function called when the effect is finished
11075  * @cfg {Object} scope The scope of the effect function
11076  * @cfg {String} easing A valid Easing value for the effect
11077  * @cfg {String} afterCls A css class to apply after the effect
11078  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11079  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11080  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11081  * effects that end with the element being visually hidden, ignored otherwise)
11082  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11083  * a function which returns such a specification that will be applied to the Element after the effect finishes
11084  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11085  * @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
11086  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11087  */
11088 Roo.Fx = {
11089         /**
11090          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11091          * origin for the slide effect.  This function automatically handles wrapping the element with
11092          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11093          * Usage:
11094          *<pre><code>
11095 // default: slide the element in from the top
11096 el.slideIn();
11097
11098 // custom: slide the element in from the right with a 2-second duration
11099 el.slideIn('r', { duration: 2 });
11100
11101 // common config options shown with default values
11102 el.slideIn('t', {
11103     easing: 'easeOut',
11104     duration: .5
11105 });
11106 </code></pre>
11107          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11108          * @param {Object} options (optional) Object literal with any of the Fx config options
11109          * @return {Roo.Element} The Element
11110          */
11111     slideIn : function(anchor, o){
11112         var el = this.getFxEl();
11113         o = o || {};
11114
11115         el.queueFx(o, function(){
11116
11117             anchor = anchor || "t";
11118
11119             // fix display to visibility
11120             this.fixDisplay();
11121
11122             // restore values after effect
11123             var r = this.getFxRestore();
11124             var b = this.getBox();
11125             // fixed size for slide
11126             this.setSize(b);
11127
11128             // wrap if needed
11129             var wrap = this.fxWrap(r.pos, o, "hidden");
11130
11131             var st = this.dom.style;
11132             st.visibility = "visible";
11133             st.position = "absolute";
11134
11135             // clear out temp styles after slide and unwrap
11136             var after = function(){
11137                 el.fxUnwrap(wrap, r.pos, o);
11138                 st.width = r.width;
11139                 st.height = r.height;
11140                 el.afterFx(o);
11141             };
11142             // time to calc the positions
11143             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11144
11145             switch(anchor.toLowerCase()){
11146                 case "t":
11147                     wrap.setSize(b.width, 0);
11148                     st.left = st.bottom = "0";
11149                     a = {height: bh};
11150                 break;
11151                 case "l":
11152                     wrap.setSize(0, b.height);
11153                     st.right = st.top = "0";
11154                     a = {width: bw};
11155                 break;
11156                 case "r":
11157                     wrap.setSize(0, b.height);
11158                     wrap.setX(b.right);
11159                     st.left = st.top = "0";
11160                     a = {width: bw, points: pt};
11161                 break;
11162                 case "b":
11163                     wrap.setSize(b.width, 0);
11164                     wrap.setY(b.bottom);
11165                     st.left = st.top = "0";
11166                     a = {height: bh, points: pt};
11167                 break;
11168                 case "tl":
11169                     wrap.setSize(0, 0);
11170                     st.right = st.bottom = "0";
11171                     a = {width: bw, height: bh};
11172                 break;
11173                 case "bl":
11174                     wrap.setSize(0, 0);
11175                     wrap.setY(b.y+b.height);
11176                     st.right = st.top = "0";
11177                     a = {width: bw, height: bh, points: pt};
11178                 break;
11179                 case "br":
11180                     wrap.setSize(0, 0);
11181                     wrap.setXY([b.right, b.bottom]);
11182                     st.left = st.top = "0";
11183                     a = {width: bw, height: bh, points: pt};
11184                 break;
11185                 case "tr":
11186                     wrap.setSize(0, 0);
11187                     wrap.setX(b.x+b.width);
11188                     st.left = st.bottom = "0";
11189                     a = {width: bw, height: bh, points: pt};
11190                 break;
11191             }
11192             this.dom.style.visibility = "visible";
11193             wrap.show();
11194
11195             arguments.callee.anim = wrap.fxanim(a,
11196                 o,
11197                 'motion',
11198                 .5,
11199                 'easeOut', after);
11200         });
11201         return this;
11202     },
11203     
11204         /**
11205          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11206          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11207          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11208          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11209          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11210          * Usage:
11211          *<pre><code>
11212 // default: slide the element out to the top
11213 el.slideOut();
11214
11215 // custom: slide the element out to the right with a 2-second duration
11216 el.slideOut('r', { duration: 2 });
11217
11218 // common config options shown with default values
11219 el.slideOut('t', {
11220     easing: 'easeOut',
11221     duration: .5,
11222     remove: false,
11223     useDisplay: false
11224 });
11225 </code></pre>
11226          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11227          * @param {Object} options (optional) Object literal with any of the Fx config options
11228          * @return {Roo.Element} The Element
11229          */
11230     slideOut : function(anchor, o){
11231         var el = this.getFxEl();
11232         o = o || {};
11233
11234         el.queueFx(o, function(){
11235
11236             anchor = anchor || "t";
11237
11238             // restore values after effect
11239             var r = this.getFxRestore();
11240             
11241             var b = this.getBox();
11242             // fixed size for slide
11243             this.setSize(b);
11244
11245             // wrap if needed
11246             var wrap = this.fxWrap(r.pos, o, "visible");
11247
11248             var st = this.dom.style;
11249             st.visibility = "visible";
11250             st.position = "absolute";
11251
11252             wrap.setSize(b);
11253
11254             var after = function(){
11255                 if(o.useDisplay){
11256                     el.setDisplayed(false);
11257                 }else{
11258                     el.hide();
11259                 }
11260
11261                 el.fxUnwrap(wrap, r.pos, o);
11262
11263                 st.width = r.width;
11264                 st.height = r.height;
11265
11266                 el.afterFx(o);
11267             };
11268
11269             var a, zero = {to: 0};
11270             switch(anchor.toLowerCase()){
11271                 case "t":
11272                     st.left = st.bottom = "0";
11273                     a = {height: zero};
11274                 break;
11275                 case "l":
11276                     st.right = st.top = "0";
11277                     a = {width: zero};
11278                 break;
11279                 case "r":
11280                     st.left = st.top = "0";
11281                     a = {width: zero, points: {to:[b.right, b.y]}};
11282                 break;
11283                 case "b":
11284                     st.left = st.top = "0";
11285                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11286                 break;
11287                 case "tl":
11288                     st.right = st.bottom = "0";
11289                     a = {width: zero, height: zero};
11290                 break;
11291                 case "bl":
11292                     st.right = st.top = "0";
11293                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11294                 break;
11295                 case "br":
11296                     st.left = st.top = "0";
11297                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11298                 break;
11299                 case "tr":
11300                     st.left = st.bottom = "0";
11301                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11302                 break;
11303             }
11304
11305             arguments.callee.anim = wrap.fxanim(a,
11306                 o,
11307                 'motion',
11308                 .5,
11309                 "easeOut", after);
11310         });
11311         return this;
11312     },
11313
11314         /**
11315          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11316          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11317          * The element must be removed from the DOM using the 'remove' config option if desired.
11318          * Usage:
11319          *<pre><code>
11320 // default
11321 el.puff();
11322
11323 // common config options shown with default values
11324 el.puff({
11325     easing: 'easeOut',
11326     duration: .5,
11327     remove: false,
11328     useDisplay: false
11329 });
11330 </code></pre>
11331          * @param {Object} options (optional) Object literal with any of the Fx config options
11332          * @return {Roo.Element} The Element
11333          */
11334     puff : function(o){
11335         var el = this.getFxEl();
11336         o = o || {};
11337
11338         el.queueFx(o, function(){
11339             this.clearOpacity();
11340             this.show();
11341
11342             // restore values after effect
11343             var r = this.getFxRestore();
11344             var st = this.dom.style;
11345
11346             var after = function(){
11347                 if(o.useDisplay){
11348                     el.setDisplayed(false);
11349                 }else{
11350                     el.hide();
11351                 }
11352
11353                 el.clearOpacity();
11354
11355                 el.setPositioning(r.pos);
11356                 st.width = r.width;
11357                 st.height = r.height;
11358                 st.fontSize = '';
11359                 el.afterFx(o);
11360             };
11361
11362             var width = this.getWidth();
11363             var height = this.getHeight();
11364
11365             arguments.callee.anim = this.fxanim({
11366                     width : {to: this.adjustWidth(width * 2)},
11367                     height : {to: this.adjustHeight(height * 2)},
11368                     points : {by: [-(width * .5), -(height * .5)]},
11369                     opacity : {to: 0},
11370                     fontSize: {to:200, unit: "%"}
11371                 },
11372                 o,
11373                 'motion',
11374                 .5,
11375                 "easeOut", after);
11376         });
11377         return this;
11378     },
11379
11380         /**
11381          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11382          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11383          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11384          * Usage:
11385          *<pre><code>
11386 // default
11387 el.switchOff();
11388
11389 // all config options shown with default values
11390 el.switchOff({
11391     easing: 'easeIn',
11392     duration: .3,
11393     remove: false,
11394     useDisplay: false
11395 });
11396 </code></pre>
11397          * @param {Object} options (optional) Object literal with any of the Fx config options
11398          * @return {Roo.Element} The Element
11399          */
11400     switchOff : function(o){
11401         var el = this.getFxEl();
11402         o = o || {};
11403
11404         el.queueFx(o, function(){
11405             this.clearOpacity();
11406             this.clip();
11407
11408             // restore values after effect
11409             var r = this.getFxRestore();
11410             var st = this.dom.style;
11411
11412             var after = function(){
11413                 if(o.useDisplay){
11414                     el.setDisplayed(false);
11415                 }else{
11416                     el.hide();
11417                 }
11418
11419                 el.clearOpacity();
11420                 el.setPositioning(r.pos);
11421                 st.width = r.width;
11422                 st.height = r.height;
11423
11424                 el.afterFx(o);
11425             };
11426
11427             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11428                 this.clearOpacity();
11429                 (function(){
11430                     this.fxanim({
11431                         height:{to:1},
11432                         points:{by:[0, this.getHeight() * .5]}
11433                     }, o, 'motion', 0.3, 'easeIn', after);
11434                 }).defer(100, this);
11435             });
11436         });
11437         return this;
11438     },
11439
11440     /**
11441      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11442      * changed using the "attr" config option) and then fading back to the original color. If no original
11443      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11444      * Usage:
11445 <pre><code>
11446 // default: highlight background to yellow
11447 el.highlight();
11448
11449 // custom: highlight foreground text to blue for 2 seconds
11450 el.highlight("0000ff", { attr: 'color', duration: 2 });
11451
11452 // common config options shown with default values
11453 el.highlight("ffff9c", {
11454     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11455     endColor: (current color) or "ffffff",
11456     easing: 'easeIn',
11457     duration: 1
11458 });
11459 </code></pre>
11460      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11461      * @param {Object} options (optional) Object literal with any of the Fx config options
11462      * @return {Roo.Element} The Element
11463      */ 
11464     highlight : function(color, o){
11465         var el = this.getFxEl();
11466         o = o || {};
11467
11468         el.queueFx(o, function(){
11469             color = color || "ffff9c";
11470             attr = o.attr || "backgroundColor";
11471
11472             this.clearOpacity();
11473             this.show();
11474
11475             var origColor = this.getColor(attr);
11476             var restoreColor = this.dom.style[attr];
11477             endColor = (o.endColor || origColor) || "ffffff";
11478
11479             var after = function(){
11480                 el.dom.style[attr] = restoreColor;
11481                 el.afterFx(o);
11482             };
11483
11484             var a = {};
11485             a[attr] = {from: color, to: endColor};
11486             arguments.callee.anim = this.fxanim(a,
11487                 o,
11488                 'color',
11489                 1,
11490                 'easeIn', after);
11491         });
11492         return this;
11493     },
11494
11495    /**
11496     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11497     * Usage:
11498 <pre><code>
11499 // default: a single light blue ripple
11500 el.frame();
11501
11502 // custom: 3 red ripples lasting 3 seconds total
11503 el.frame("ff0000", 3, { duration: 3 });
11504
11505 // common config options shown with default values
11506 el.frame("C3DAF9", 1, {
11507     duration: 1 //duration of entire animation (not each individual ripple)
11508     // Note: Easing is not configurable and will be ignored if included
11509 });
11510 </code></pre>
11511     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11512     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11513     * @param {Object} options (optional) Object literal with any of the Fx config options
11514     * @return {Roo.Element} The Element
11515     */
11516     frame : function(color, count, o){
11517         var el = this.getFxEl();
11518         o = o || {};
11519
11520         el.queueFx(o, function(){
11521             color = color || "#C3DAF9";
11522             if(color.length == 6){
11523                 color = "#" + color;
11524             }
11525             count = count || 1;
11526             duration = o.duration || 1;
11527             this.show();
11528
11529             var b = this.getBox();
11530             var animFn = function(){
11531                 var proxy = this.createProxy({
11532
11533                      style:{
11534                         visbility:"hidden",
11535                         position:"absolute",
11536                         "z-index":"35000", // yee haw
11537                         border:"0px solid " + color
11538                      }
11539                   });
11540                 var scale = Roo.isBorderBox ? 2 : 1;
11541                 proxy.animate({
11542                     top:{from:b.y, to:b.y - 20},
11543                     left:{from:b.x, to:b.x - 20},
11544                     borderWidth:{from:0, to:10},
11545                     opacity:{from:1, to:0},
11546                     height:{from:b.height, to:(b.height + (20*scale))},
11547                     width:{from:b.width, to:(b.width + (20*scale))}
11548                 }, duration, function(){
11549                     proxy.remove();
11550                 });
11551                 if(--count > 0){
11552                      animFn.defer((duration/2)*1000, this);
11553                 }else{
11554                     el.afterFx(o);
11555                 }
11556             };
11557             animFn.call(this);
11558         });
11559         return this;
11560     },
11561
11562    /**
11563     * Creates a pause before any subsequent queued effects begin.  If there are
11564     * no effects queued after the pause it will have no effect.
11565     * Usage:
11566 <pre><code>
11567 el.pause(1);
11568 </code></pre>
11569     * @param {Number} seconds The length of time to pause (in seconds)
11570     * @return {Roo.Element} The Element
11571     */
11572     pause : function(seconds){
11573         var el = this.getFxEl();
11574         var o = {};
11575
11576         el.queueFx(o, function(){
11577             setTimeout(function(){
11578                 el.afterFx(o);
11579             }, seconds * 1000);
11580         });
11581         return this;
11582     },
11583
11584    /**
11585     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11586     * using the "endOpacity" config option.
11587     * Usage:
11588 <pre><code>
11589 // default: fade in from opacity 0 to 100%
11590 el.fadeIn();
11591
11592 // custom: fade in from opacity 0 to 75% over 2 seconds
11593 el.fadeIn({ endOpacity: .75, duration: 2});
11594
11595 // common config options shown with default values
11596 el.fadeIn({
11597     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11598     easing: 'easeOut',
11599     duration: .5
11600 });
11601 </code></pre>
11602     * @param {Object} options (optional) Object literal with any of the Fx config options
11603     * @return {Roo.Element} The Element
11604     */
11605     fadeIn : function(o){
11606         var el = this.getFxEl();
11607         o = o || {};
11608         el.queueFx(o, function(){
11609             this.setOpacity(0);
11610             this.fixDisplay();
11611             this.dom.style.visibility = 'visible';
11612             var to = o.endOpacity || 1;
11613             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11614                 o, null, .5, "easeOut", function(){
11615                 if(to == 1){
11616                     this.clearOpacity();
11617                 }
11618                 el.afterFx(o);
11619             });
11620         });
11621         return this;
11622     },
11623
11624    /**
11625     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11626     * using the "endOpacity" config option.
11627     * Usage:
11628 <pre><code>
11629 // default: fade out from the element's current opacity to 0
11630 el.fadeOut();
11631
11632 // custom: fade out from the element's current opacity to 25% over 2 seconds
11633 el.fadeOut({ endOpacity: .25, duration: 2});
11634
11635 // common config options shown with default values
11636 el.fadeOut({
11637     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11638     easing: 'easeOut',
11639     duration: .5
11640     remove: false,
11641     useDisplay: false
11642 });
11643 </code></pre>
11644     * @param {Object} options (optional) Object literal with any of the Fx config options
11645     * @return {Roo.Element} The Element
11646     */
11647     fadeOut : function(o){
11648         var el = this.getFxEl();
11649         o = o || {};
11650         el.queueFx(o, function(){
11651             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11652                 o, null, .5, "easeOut", function(){
11653                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11654                      this.dom.style.display = "none";
11655                 }else{
11656                      this.dom.style.visibility = "hidden";
11657                 }
11658                 this.clearOpacity();
11659                 el.afterFx(o);
11660             });
11661         });
11662         return this;
11663     },
11664
11665    /**
11666     * Animates the transition of an element's dimensions from a starting height/width
11667     * to an ending height/width.
11668     * Usage:
11669 <pre><code>
11670 // change height and width to 100x100 pixels
11671 el.scale(100, 100);
11672
11673 // common config options shown with default values.  The height and width will default to
11674 // the element's existing values if passed as null.
11675 el.scale(
11676     [element's width],
11677     [element's height], {
11678     easing: 'easeOut',
11679     duration: .35
11680 });
11681 </code></pre>
11682     * @param {Number} width  The new width (pass undefined to keep the original width)
11683     * @param {Number} height  The new height (pass undefined to keep the original height)
11684     * @param {Object} options (optional) Object literal with any of the Fx config options
11685     * @return {Roo.Element} The Element
11686     */
11687     scale : function(w, h, o){
11688         this.shift(Roo.apply({}, o, {
11689             width: w,
11690             height: h
11691         }));
11692         return this;
11693     },
11694
11695    /**
11696     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11697     * Any of these properties not specified in the config object will not be changed.  This effect 
11698     * requires that at least one new dimension, position or opacity setting must be passed in on
11699     * the config object in order for the function to have any effect.
11700     * Usage:
11701 <pre><code>
11702 // slide the element horizontally to x position 200 while changing the height and opacity
11703 el.shift({ x: 200, height: 50, opacity: .8 });
11704
11705 // common config options shown with default values.
11706 el.shift({
11707     width: [element's width],
11708     height: [element's height],
11709     x: [element's x position],
11710     y: [element's y position],
11711     opacity: [element's opacity],
11712     easing: 'easeOut',
11713     duration: .35
11714 });
11715 </code></pre>
11716     * @param {Object} options  Object literal with any of the Fx config options
11717     * @return {Roo.Element} The Element
11718     */
11719     shift : function(o){
11720         var el = this.getFxEl();
11721         o = o || {};
11722         el.queueFx(o, function(){
11723             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11724             if(w !== undefined){
11725                 a.width = {to: this.adjustWidth(w)};
11726             }
11727             if(h !== undefined){
11728                 a.height = {to: this.adjustHeight(h)};
11729             }
11730             if(x !== undefined || y !== undefined){
11731                 a.points = {to: [
11732                     x !== undefined ? x : this.getX(),
11733                     y !== undefined ? y : this.getY()
11734                 ]};
11735             }
11736             if(op !== undefined){
11737                 a.opacity = {to: op};
11738             }
11739             if(o.xy !== undefined){
11740                 a.points = {to: o.xy};
11741             }
11742             arguments.callee.anim = this.fxanim(a,
11743                 o, 'motion', .35, "easeOut", function(){
11744                 el.afterFx(o);
11745             });
11746         });
11747         return this;
11748     },
11749
11750         /**
11751          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11752          * ending point of the effect.
11753          * Usage:
11754          *<pre><code>
11755 // default: slide the element downward while fading out
11756 el.ghost();
11757
11758 // custom: slide the element out to the right with a 2-second duration
11759 el.ghost('r', { duration: 2 });
11760
11761 // common config options shown with default values
11762 el.ghost('b', {
11763     easing: 'easeOut',
11764     duration: .5
11765     remove: false,
11766     useDisplay: false
11767 });
11768 </code></pre>
11769          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11770          * @param {Object} options (optional) Object literal with any of the Fx config options
11771          * @return {Roo.Element} The Element
11772          */
11773     ghost : function(anchor, o){
11774         var el = this.getFxEl();
11775         o = o || {};
11776
11777         el.queueFx(o, function(){
11778             anchor = anchor || "b";
11779
11780             // restore values after effect
11781             var r = this.getFxRestore();
11782             var w = this.getWidth(),
11783                 h = this.getHeight();
11784
11785             var st = this.dom.style;
11786
11787             var after = function(){
11788                 if(o.useDisplay){
11789                     el.setDisplayed(false);
11790                 }else{
11791                     el.hide();
11792                 }
11793
11794                 el.clearOpacity();
11795                 el.setPositioning(r.pos);
11796                 st.width = r.width;
11797                 st.height = r.height;
11798
11799                 el.afterFx(o);
11800             };
11801
11802             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11803             switch(anchor.toLowerCase()){
11804                 case "t":
11805                     pt.by = [0, -h];
11806                 break;
11807                 case "l":
11808                     pt.by = [-w, 0];
11809                 break;
11810                 case "r":
11811                     pt.by = [w, 0];
11812                 break;
11813                 case "b":
11814                     pt.by = [0, h];
11815                 break;
11816                 case "tl":
11817                     pt.by = [-w, -h];
11818                 break;
11819                 case "bl":
11820                     pt.by = [-w, h];
11821                 break;
11822                 case "br":
11823                     pt.by = [w, h];
11824                 break;
11825                 case "tr":
11826                     pt.by = [w, -h];
11827                 break;
11828             }
11829
11830             arguments.callee.anim = this.fxanim(a,
11831                 o,
11832                 'motion',
11833                 .5,
11834                 "easeOut", after);
11835         });
11836         return this;
11837     },
11838
11839         /**
11840          * Ensures that all effects queued after syncFx is called on the element are
11841          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11842          * @return {Roo.Element} The Element
11843          */
11844     syncFx : function(){
11845         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11846             block : false,
11847             concurrent : true,
11848             stopFx : false
11849         });
11850         return this;
11851     },
11852
11853         /**
11854          * Ensures that all effects queued after sequenceFx is called on the element are
11855          * run in sequence.  This is the opposite of {@link #syncFx}.
11856          * @return {Roo.Element} The Element
11857          */
11858     sequenceFx : function(){
11859         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11860             block : false,
11861             concurrent : false,
11862             stopFx : false
11863         });
11864         return this;
11865     },
11866
11867         /* @private */
11868     nextFx : function(){
11869         var ef = this.fxQueue[0];
11870         if(ef){
11871             ef.call(this);
11872         }
11873     },
11874
11875         /**
11876          * Returns true if the element has any effects actively running or queued, else returns false.
11877          * @return {Boolean} True if element has active effects, else false
11878          */
11879     hasActiveFx : function(){
11880         return this.fxQueue && this.fxQueue[0];
11881     },
11882
11883         /**
11884          * Stops any running effects and clears the element's internal effects queue if it contains
11885          * any additional effects that haven't started yet.
11886          * @return {Roo.Element} The Element
11887          */
11888     stopFx : function(){
11889         if(this.hasActiveFx()){
11890             var cur = this.fxQueue[0];
11891             if(cur && cur.anim && cur.anim.isAnimated()){
11892                 this.fxQueue = [cur]; // clear out others
11893                 cur.anim.stop(true);
11894             }
11895         }
11896         return this;
11897     },
11898
11899         /* @private */
11900     beforeFx : function(o){
11901         if(this.hasActiveFx() && !o.concurrent){
11902            if(o.stopFx){
11903                this.stopFx();
11904                return true;
11905            }
11906            return false;
11907         }
11908         return true;
11909     },
11910
11911         /**
11912          * Returns true if the element is currently blocking so that no other effect can be queued
11913          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11914          * used to ensure that an effect initiated by a user action runs to completion prior to the
11915          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11916          * @return {Boolean} True if blocking, else false
11917          */
11918     hasFxBlock : function(){
11919         var q = this.fxQueue;
11920         return q && q[0] && q[0].block;
11921     },
11922
11923         /* @private */
11924     queueFx : function(o, fn){
11925         if(!this.fxQueue){
11926             this.fxQueue = [];
11927         }
11928         if(!this.hasFxBlock()){
11929             Roo.applyIf(o, this.fxDefaults);
11930             if(!o.concurrent){
11931                 var run = this.beforeFx(o);
11932                 fn.block = o.block;
11933                 this.fxQueue.push(fn);
11934                 if(run){
11935                     this.nextFx();
11936                 }
11937             }else{
11938                 fn.call(this);
11939             }
11940         }
11941         return this;
11942     },
11943
11944         /* @private */
11945     fxWrap : function(pos, o, vis){
11946         var wrap;
11947         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11948             var wrapXY;
11949             if(o.fixPosition){
11950                 wrapXY = this.getXY();
11951             }
11952             var div = document.createElement("div");
11953             div.style.visibility = vis;
11954             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11955             wrap.setPositioning(pos);
11956             if(wrap.getStyle("position") == "static"){
11957                 wrap.position("relative");
11958             }
11959             this.clearPositioning('auto');
11960             wrap.clip();
11961             wrap.dom.appendChild(this.dom);
11962             if(wrapXY){
11963                 wrap.setXY(wrapXY);
11964             }
11965         }
11966         return wrap;
11967     },
11968
11969         /* @private */
11970     fxUnwrap : function(wrap, pos, o){
11971         this.clearPositioning();
11972         this.setPositioning(pos);
11973         if(!o.wrap){
11974             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11975             wrap.remove();
11976         }
11977     },
11978
11979         /* @private */
11980     getFxRestore : function(){
11981         var st = this.dom.style;
11982         return {pos: this.getPositioning(), width: st.width, height : st.height};
11983     },
11984
11985         /* @private */
11986     afterFx : function(o){
11987         if(o.afterStyle){
11988             this.applyStyles(o.afterStyle);
11989         }
11990         if(o.afterCls){
11991             this.addClass(o.afterCls);
11992         }
11993         if(o.remove === true){
11994             this.remove();
11995         }
11996         Roo.callback(o.callback, o.scope, [this]);
11997         if(!o.concurrent){
11998             this.fxQueue.shift();
11999             this.nextFx();
12000         }
12001     },
12002
12003         /* @private */
12004     getFxEl : function(){ // support for composite element fx
12005         return Roo.get(this.dom);
12006     },
12007
12008         /* @private */
12009     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12010         animType = animType || 'run';
12011         opt = opt || {};
12012         var anim = Roo.lib.Anim[animType](
12013             this.dom, args,
12014             (opt.duration || defaultDur) || .35,
12015             (opt.easing || defaultEase) || 'easeOut',
12016             function(){
12017                 Roo.callback(cb, this);
12018             },
12019             this
12020         );
12021         opt.anim = anim;
12022         return anim;
12023     }
12024 };
12025
12026 // backwords compat
12027 Roo.Fx.resize = Roo.Fx.scale;
12028
12029 //When included, Roo.Fx is automatically applied to Element so that all basic
12030 //effects are available directly via the Element API
12031 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12032  * Based on:
12033  * Ext JS Library 1.1.1
12034  * Copyright(c) 2006-2007, Ext JS, LLC.
12035  *
12036  * Originally Released Under LGPL - original licence link has changed is not relivant.
12037  *
12038  * Fork - LGPL
12039  * <script type="text/javascript">
12040  */
12041
12042
12043 /**
12044  * @class Roo.CompositeElement
12045  * Standard composite class. Creates a Roo.Element for every element in the collection.
12046  * <br><br>
12047  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12048  * actions will be performed on all the elements in this collection.</b>
12049  * <br><br>
12050  * All methods return <i>this</i> and can be chained.
12051  <pre><code>
12052  var els = Roo.select("#some-el div.some-class", true);
12053  // or select directly from an existing element
12054  var el = Roo.get('some-el');
12055  el.select('div.some-class', true);
12056
12057  els.setWidth(100); // all elements become 100 width
12058  els.hide(true); // all elements fade out and hide
12059  // or
12060  els.setWidth(100).hide(true);
12061  </code></pre>
12062  */
12063 Roo.CompositeElement = function(els){
12064     this.elements = [];
12065     this.addElements(els);
12066 };
12067 Roo.CompositeElement.prototype = {
12068     isComposite: true,
12069     addElements : function(els){
12070         if(!els) {
12071             return this;
12072         }
12073         if(typeof els == "string"){
12074             els = Roo.Element.selectorFunction(els);
12075         }
12076         var yels = this.elements;
12077         var index = yels.length-1;
12078         for(var i = 0, len = els.length; i < len; i++) {
12079                 yels[++index] = Roo.get(els[i]);
12080         }
12081         return this;
12082     },
12083
12084     /**
12085     * Clears this composite and adds the elements returned by the passed selector.
12086     * @param {String/Array} els A string CSS selector, an array of elements or an element
12087     * @return {CompositeElement} this
12088     */
12089     fill : function(els){
12090         this.elements = [];
12091         this.add(els);
12092         return this;
12093     },
12094
12095     /**
12096     * Filters this composite to only elements that match the passed selector.
12097     * @param {String} selector A string CSS selector
12098     * @param {Boolean} inverse return inverse filter (not matches)
12099     * @return {CompositeElement} this
12100     */
12101     filter : function(selector, inverse){
12102         var els = [];
12103         inverse = inverse || false;
12104         this.each(function(el){
12105             var match = inverse ? !el.is(selector) : el.is(selector);
12106             if(match){
12107                 els[els.length] = el.dom;
12108             }
12109         });
12110         this.fill(els);
12111         return this;
12112     },
12113
12114     invoke : function(fn, args){
12115         var els = this.elements;
12116         for(var i = 0, len = els.length; i < len; i++) {
12117                 Roo.Element.prototype[fn].apply(els[i], args);
12118         }
12119         return this;
12120     },
12121     /**
12122     * Adds elements to this composite.
12123     * @param {String/Array} els A string CSS selector, an array of elements or an element
12124     * @return {CompositeElement} this
12125     */
12126     add : function(els){
12127         if(typeof els == "string"){
12128             this.addElements(Roo.Element.selectorFunction(els));
12129         }else if(els.length !== undefined){
12130             this.addElements(els);
12131         }else{
12132             this.addElements([els]);
12133         }
12134         return this;
12135     },
12136     /**
12137     * Calls the passed function passing (el, this, index) for each element in this composite.
12138     * @param {Function} fn The function to call
12139     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12140     * @return {CompositeElement} this
12141     */
12142     each : function(fn, scope){
12143         var els = this.elements;
12144         for(var i = 0, len = els.length; i < len; i++){
12145             if(fn.call(scope || els[i], els[i], this, i) === false) {
12146                 break;
12147             }
12148         }
12149         return this;
12150     },
12151
12152     /**
12153      * Returns the Element object at the specified index
12154      * @param {Number} index
12155      * @return {Roo.Element}
12156      */
12157     item : function(index){
12158         return this.elements[index] || null;
12159     },
12160
12161     /**
12162      * Returns the first Element
12163      * @return {Roo.Element}
12164      */
12165     first : function(){
12166         return this.item(0);
12167     },
12168
12169     /**
12170      * Returns the last Element
12171      * @return {Roo.Element}
12172      */
12173     last : function(){
12174         return this.item(this.elements.length-1);
12175     },
12176
12177     /**
12178      * Returns the number of elements in this composite
12179      * @return Number
12180      */
12181     getCount : function(){
12182         return this.elements.length;
12183     },
12184
12185     /**
12186      * Returns true if this composite contains the passed element
12187      * @return Boolean
12188      */
12189     contains : function(el){
12190         return this.indexOf(el) !== -1;
12191     },
12192
12193     /**
12194      * Returns true if this composite contains the passed element
12195      * @return Boolean
12196      */
12197     indexOf : function(el){
12198         return this.elements.indexOf(Roo.get(el));
12199     },
12200
12201
12202     /**
12203     * Removes the specified element(s).
12204     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12205     * or an array of any of those.
12206     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12207     * @return {CompositeElement} this
12208     */
12209     removeElement : function(el, removeDom){
12210         if(el instanceof Array){
12211             for(var i = 0, len = el.length; i < len; i++){
12212                 this.removeElement(el[i]);
12213             }
12214             return this;
12215         }
12216         var index = typeof el == 'number' ? el : this.indexOf(el);
12217         if(index !== -1){
12218             if(removeDom){
12219                 var d = this.elements[index];
12220                 if(d.dom){
12221                     d.remove();
12222                 }else{
12223                     d.parentNode.removeChild(d);
12224                 }
12225             }
12226             this.elements.splice(index, 1);
12227         }
12228         return this;
12229     },
12230
12231     /**
12232     * Replaces the specified element with the passed element.
12233     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12234     * to replace.
12235     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12236     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12237     * @return {CompositeElement} this
12238     */
12239     replaceElement : function(el, replacement, domReplace){
12240         var index = typeof el == 'number' ? el : this.indexOf(el);
12241         if(index !== -1){
12242             if(domReplace){
12243                 this.elements[index].replaceWith(replacement);
12244             }else{
12245                 this.elements.splice(index, 1, Roo.get(replacement))
12246             }
12247         }
12248         return this;
12249     },
12250
12251     /**
12252      * Removes all elements.
12253      */
12254     clear : function(){
12255         this.elements = [];
12256     }
12257 };
12258 (function(){
12259     Roo.CompositeElement.createCall = function(proto, fnName){
12260         if(!proto[fnName]){
12261             proto[fnName] = function(){
12262                 return this.invoke(fnName, arguments);
12263             };
12264         }
12265     };
12266     for(var fnName in Roo.Element.prototype){
12267         if(typeof Roo.Element.prototype[fnName] == "function"){
12268             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12269         }
12270     };
12271 })();
12272 /*
12273  * Based on:
12274  * Ext JS Library 1.1.1
12275  * Copyright(c) 2006-2007, Ext JS, LLC.
12276  *
12277  * Originally Released Under LGPL - original licence link has changed is not relivant.
12278  *
12279  * Fork - LGPL
12280  * <script type="text/javascript">
12281  */
12282
12283 /**
12284  * @class Roo.CompositeElementLite
12285  * @extends Roo.CompositeElement
12286  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12287  <pre><code>
12288  var els = Roo.select("#some-el div.some-class");
12289  // or select directly from an existing element
12290  var el = Roo.get('some-el');
12291  el.select('div.some-class');
12292
12293  els.setWidth(100); // all elements become 100 width
12294  els.hide(true); // all elements fade out and hide
12295  // or
12296  els.setWidth(100).hide(true);
12297  </code></pre><br><br>
12298  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12299  * actions will be performed on all the elements in this collection.</b>
12300  */
12301 Roo.CompositeElementLite = function(els){
12302     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12303     this.el = new Roo.Element.Flyweight();
12304 };
12305 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12306     addElements : function(els){
12307         if(els){
12308             if(els instanceof Array){
12309                 this.elements = this.elements.concat(els);
12310             }else{
12311                 var yels = this.elements;
12312                 var index = yels.length-1;
12313                 for(var i = 0, len = els.length; i < len; i++) {
12314                     yels[++index] = els[i];
12315                 }
12316             }
12317         }
12318         return this;
12319     },
12320     invoke : function(fn, args){
12321         var els = this.elements;
12322         var el = this.el;
12323         for(var i = 0, len = els.length; i < len; i++) {
12324             el.dom = els[i];
12325                 Roo.Element.prototype[fn].apply(el, args);
12326         }
12327         return this;
12328     },
12329     /**
12330      * Returns a flyweight Element of the dom element object at the specified index
12331      * @param {Number} index
12332      * @return {Roo.Element}
12333      */
12334     item : function(index){
12335         if(!this.elements[index]){
12336             return null;
12337         }
12338         this.el.dom = this.elements[index];
12339         return this.el;
12340     },
12341
12342     // fixes scope with flyweight
12343     addListener : function(eventName, handler, scope, opt){
12344         var els = this.elements;
12345         for(var i = 0, len = els.length; i < len; i++) {
12346             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12347         }
12348         return this;
12349     },
12350
12351     /**
12352     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12353     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12354     * a reference to the dom node, use el.dom.</b>
12355     * @param {Function} fn The function to call
12356     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12357     * @return {CompositeElement} this
12358     */
12359     each : function(fn, scope){
12360         var els = this.elements;
12361         var el = this.el;
12362         for(var i = 0, len = els.length; i < len; i++){
12363             el.dom = els[i];
12364                 if(fn.call(scope || el, el, this, i) === false){
12365                 break;
12366             }
12367         }
12368         return this;
12369     },
12370
12371     indexOf : function(el){
12372         return this.elements.indexOf(Roo.getDom(el));
12373     },
12374
12375     replaceElement : function(el, replacement, domReplace){
12376         var index = typeof el == 'number' ? el : this.indexOf(el);
12377         if(index !== -1){
12378             replacement = Roo.getDom(replacement);
12379             if(domReplace){
12380                 var d = this.elements[index];
12381                 d.parentNode.insertBefore(replacement, d);
12382                 d.parentNode.removeChild(d);
12383             }
12384             this.elements.splice(index, 1, replacement);
12385         }
12386         return this;
12387     }
12388 });
12389 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12390
12391 /*
12392  * Based on:
12393  * Ext JS Library 1.1.1
12394  * Copyright(c) 2006-2007, Ext JS, LLC.
12395  *
12396  * Originally Released Under LGPL - original licence link has changed is not relivant.
12397  *
12398  * Fork - LGPL
12399  * <script type="text/javascript">
12400  */
12401
12402  
12403
12404 /**
12405  * @class Roo.data.Connection
12406  * @extends Roo.util.Observable
12407  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12408  * either to a configured URL, or to a URL specified at request time. 
12409  * 
12410  * Requests made by this class are asynchronous, and will return immediately. No data from
12411  * the server will be available to the statement immediately following the {@link #request} call.
12412  * To process returned data, use a callback in the request options object, or an event listener.
12413  * 
12414  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12415  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12416  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12417  * property and, if present, the IFRAME's XML document as the responseXML property.
12418  * 
12419  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12420  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12421  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12422  * standard DOM methods.
12423  * @constructor
12424  * @param {Object} config a configuration object.
12425  */
12426 Roo.data.Connection = function(config){
12427     Roo.apply(this, config);
12428     this.addEvents({
12429         /**
12430          * @event beforerequest
12431          * Fires before a network request is made to retrieve a data object.
12432          * @param {Connection} conn This Connection object.
12433          * @param {Object} options The options config object passed to the {@link #request} method.
12434          */
12435         "beforerequest" : true,
12436         /**
12437          * @event requestcomplete
12438          * Fires if the request was successfully completed.
12439          * @param {Connection} conn This Connection object.
12440          * @param {Object} response The XHR object containing the response data.
12441          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12442          * @param {Object} options The options config object passed to the {@link #request} method.
12443          */
12444         "requestcomplete" : true,
12445         /**
12446          * @event requestexception
12447          * Fires if an error HTTP status was returned from the server.
12448          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12449          * @param {Connection} conn This Connection object.
12450          * @param {Object} response The XHR object containing the response data.
12451          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12452          * @param {Object} options The options config object passed to the {@link #request} method.
12453          */
12454         "requestexception" : true
12455     });
12456     Roo.data.Connection.superclass.constructor.call(this);
12457 };
12458
12459 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12460     /**
12461      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12462      */
12463     /**
12464      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12465      * extra parameters to each request made by this object. (defaults to undefined)
12466      */
12467     /**
12468      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12469      *  to each request made by this object. (defaults to undefined)
12470      */
12471     /**
12472      * @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)
12473      */
12474     /**
12475      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12476      */
12477     timeout : 30000,
12478     /**
12479      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12480      * @type Boolean
12481      */
12482     autoAbort:false,
12483
12484     /**
12485      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12486      * @type Boolean
12487      */
12488     disableCaching: true,
12489
12490     /**
12491      * Sends an HTTP request to a remote server.
12492      * @param {Object} options An object which may contain the following properties:<ul>
12493      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12494      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12495      * request, a url encoded string or a function to call to get either.</li>
12496      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12497      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12498      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12499      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12500      * <li>options {Object} The parameter to the request call.</li>
12501      * <li>success {Boolean} True if the request succeeded.</li>
12502      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12503      * </ul></li>
12504      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12505      * The callback is passed the following parameters:<ul>
12506      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12507      * <li>options {Object} The parameter to the request call.</li>
12508      * </ul></li>
12509      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12510      * The callback is passed the following parameters:<ul>
12511      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12512      * <li>options {Object} The parameter to the request call.</li>
12513      * </ul></li>
12514      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12515      * for the callback function. Defaults to the browser window.</li>
12516      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12517      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12518      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12519      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12520      * params for the post data. Any params will be appended to the URL.</li>
12521      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12522      * </ul>
12523      * @return {Number} transactionId
12524      */
12525     request : function(o){
12526         if(this.fireEvent("beforerequest", this, o) !== false){
12527             var p = o.params;
12528
12529             if(typeof p == "function"){
12530                 p = p.call(o.scope||window, o);
12531             }
12532             if(typeof p == "object"){
12533                 p = Roo.urlEncode(o.params);
12534             }
12535             if(this.extraParams){
12536                 var extras = Roo.urlEncode(this.extraParams);
12537                 p = p ? (p + '&' + extras) : extras;
12538             }
12539
12540             var url = o.url || this.url;
12541             if(typeof url == 'function'){
12542                 url = url.call(o.scope||window, o);
12543             }
12544
12545             if(o.form){
12546                 var form = Roo.getDom(o.form);
12547                 url = url || form.action;
12548
12549                 var enctype = form.getAttribute("enctype");
12550                 
12551                 if (o.formData) {
12552                     return this.doFormDataUpload(o, url);
12553                 }
12554                 
12555                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12556                     return this.doFormUpload(o, p, url);
12557                 }
12558                 var f = Roo.lib.Ajax.serializeForm(form);
12559                 p = p ? (p + '&' + f) : f;
12560             }
12561             
12562             if (!o.form && o.formData) {
12563                 o.formData = o.formData === true ? new FormData() : o.formData;
12564                 for (var k in o.params) {
12565                     o.formData.append(k,o.params[k]);
12566                 }
12567                     
12568                 return this.doFormDataUpload(o, url);
12569             }
12570             
12571
12572             var hs = o.headers;
12573             if(this.defaultHeaders){
12574                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12575                 if(!o.headers){
12576                     o.headers = hs;
12577                 }
12578             }
12579
12580             var cb = {
12581                 success: this.handleResponse,
12582                 failure: this.handleFailure,
12583                 scope: this,
12584                 argument: {options: o},
12585                 timeout : o.timeout || this.timeout
12586             };
12587
12588             var method = o.method||this.method||(p ? "POST" : "GET");
12589
12590             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12591                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12592             }
12593
12594             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12595                 if(o.autoAbort){
12596                     this.abort();
12597                 }
12598             }else if(this.autoAbort !== false){
12599                 this.abort();
12600             }
12601
12602             if((method == 'GET' && p) || o.xmlData){
12603                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12604                 p = '';
12605             }
12606             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12607             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12608             Roo.lib.Ajax.useDefaultHeader == true;
12609             return this.transId;
12610         }else{
12611             Roo.callback(o.callback, o.scope, [o, null, null]);
12612             return null;
12613         }
12614     },
12615
12616     /**
12617      * Determine whether this object has a request outstanding.
12618      * @param {Number} transactionId (Optional) defaults to the last transaction
12619      * @return {Boolean} True if there is an outstanding request.
12620      */
12621     isLoading : function(transId){
12622         if(transId){
12623             return Roo.lib.Ajax.isCallInProgress(transId);
12624         }else{
12625             return this.transId ? true : false;
12626         }
12627     },
12628
12629     /**
12630      * Aborts any outstanding request.
12631      * @param {Number} transactionId (Optional) defaults to the last transaction
12632      */
12633     abort : function(transId){
12634         if(transId || this.isLoading()){
12635             Roo.lib.Ajax.abort(transId || this.transId);
12636         }
12637     },
12638
12639     // private
12640     handleResponse : function(response){
12641         this.transId = false;
12642         var options = response.argument.options;
12643         response.argument = options ? options.argument : null;
12644         this.fireEvent("requestcomplete", this, response, options);
12645         Roo.callback(options.success, options.scope, [response, options]);
12646         Roo.callback(options.callback, options.scope, [options, true, response]);
12647     },
12648
12649     // private
12650     handleFailure : function(response, e){
12651         this.transId = false;
12652         var options = response.argument.options;
12653         response.argument = options ? options.argument : null;
12654         this.fireEvent("requestexception", this, response, options, e);
12655         Roo.callback(options.failure, options.scope, [response, options]);
12656         Roo.callback(options.callback, options.scope, [options, false, response]);
12657     },
12658
12659     // private
12660     doFormUpload : function(o, ps, url){
12661         var id = Roo.id();
12662         var frame = document.createElement('iframe');
12663         frame.id = id;
12664         frame.name = id;
12665         frame.className = 'x-hidden';
12666         if(Roo.isIE){
12667             frame.src = Roo.SSL_SECURE_URL;
12668         }
12669         document.body.appendChild(frame);
12670
12671         if(Roo.isIE){
12672            document.frames[id].name = id;
12673         }
12674
12675         var form = Roo.getDom(o.form);
12676         form.target = id;
12677         form.method = 'POST';
12678         form.enctype = form.encoding = 'multipart/form-data';
12679         if(url){
12680             form.action = url;
12681         }
12682
12683         var hiddens, hd;
12684         if(ps){ // add dynamic params
12685             hiddens = [];
12686             ps = Roo.urlDecode(ps, false);
12687             for(var k in ps){
12688                 if(ps.hasOwnProperty(k)){
12689                     hd = document.createElement('input');
12690                     hd.type = 'hidden';
12691                     hd.name = k;
12692                     hd.value = ps[k];
12693                     form.appendChild(hd);
12694                     hiddens.push(hd);
12695                 }
12696             }
12697         }
12698
12699         function cb(){
12700             var r = {  // bogus response object
12701                 responseText : '',
12702                 responseXML : null
12703             };
12704
12705             r.argument = o ? o.argument : null;
12706
12707             try { //
12708                 var doc;
12709                 if(Roo.isIE){
12710                     doc = frame.contentWindow.document;
12711                 }else {
12712                     doc = (frame.contentDocument || window.frames[id].document);
12713                 }
12714                 if(doc && doc.body){
12715                     r.responseText = doc.body.innerHTML;
12716                 }
12717                 if(doc && doc.XMLDocument){
12718                     r.responseXML = doc.XMLDocument;
12719                 }else {
12720                     r.responseXML = doc;
12721                 }
12722             }
12723             catch(e) {
12724                 // ignore
12725             }
12726
12727             Roo.EventManager.removeListener(frame, 'load', cb, this);
12728
12729             this.fireEvent("requestcomplete", this, r, o);
12730             Roo.callback(o.success, o.scope, [r, o]);
12731             Roo.callback(o.callback, o.scope, [o, true, r]);
12732
12733             setTimeout(function(){document.body.removeChild(frame);}, 100);
12734         }
12735
12736         Roo.EventManager.on(frame, 'load', cb, this);
12737         form.submit();
12738
12739         if(hiddens){ // remove dynamic params
12740             for(var i = 0, len = hiddens.length; i < len; i++){
12741                 form.removeChild(hiddens[i]);
12742             }
12743         }
12744     },
12745     // this is a 'formdata version???'
12746     
12747     
12748     doFormDataUpload : function(o,  url)
12749     {
12750         var formData;
12751         if (o.form) {
12752             var form =  Roo.getDom(o.form);
12753             form.enctype = form.encoding = 'multipart/form-data';
12754             formData = o.formData === true ? new FormData(form) : o.formData;
12755         } else {
12756             formData = o.formData === true ? new FormData() : o.formData;
12757         }
12758         
12759       
12760         var cb = {
12761             success: this.handleResponse,
12762             failure: this.handleFailure,
12763             scope: this,
12764             argument: {options: o},
12765             timeout : o.timeout || this.timeout
12766         };
12767  
12768         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12769             if(o.autoAbort){
12770                 this.abort();
12771             }
12772         }else if(this.autoAbort !== false){
12773             this.abort();
12774         }
12775
12776         //Roo.lib.Ajax.defaultPostHeader = null;
12777         Roo.lib.Ajax.useDefaultHeader = false;
12778         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12779         Roo.lib.Ajax.useDefaultHeader = true;
12780  
12781          
12782     }
12783     
12784 });
12785 /*
12786  * Based on:
12787  * Ext JS Library 1.1.1
12788  * Copyright(c) 2006-2007, Ext JS, LLC.
12789  *
12790  * Originally Released Under LGPL - original licence link has changed is not relivant.
12791  *
12792  * Fork - LGPL
12793  * <script type="text/javascript">
12794  */
12795  
12796 /**
12797  * Global Ajax request class.
12798  * 
12799  * @class Roo.Ajax
12800  * @extends Roo.data.Connection
12801  * @static
12802  * 
12803  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12804  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12805  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12806  * @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)
12807  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12808  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12809  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12810  */
12811 Roo.Ajax = new Roo.data.Connection({
12812     // fix up the docs
12813     /**
12814      * @scope Roo.Ajax
12815      * @type {Boolear} 
12816      */
12817     autoAbort : false,
12818
12819     /**
12820      * Serialize the passed form into a url encoded string
12821      * @scope Roo.Ajax
12822      * @param {String/HTMLElement} form
12823      * @return {String}
12824      */
12825     serializeForm : function(form){
12826         return Roo.lib.Ajax.serializeForm(form);
12827     }
12828 });/*
12829  * Based on:
12830  * Ext JS Library 1.1.1
12831  * Copyright(c) 2006-2007, Ext JS, LLC.
12832  *
12833  * Originally Released Under LGPL - original licence link has changed is not relivant.
12834  *
12835  * Fork - LGPL
12836  * <script type="text/javascript">
12837  */
12838
12839  
12840 /**
12841  * @class Roo.UpdateManager
12842  * @extends Roo.util.Observable
12843  * Provides AJAX-style update for Element object.<br><br>
12844  * Usage:<br>
12845  * <pre><code>
12846  * // Get it from a Roo.Element object
12847  * var el = Roo.get("foo");
12848  * var mgr = el.getUpdateManager();
12849  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12850  * ...
12851  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12852  * <br>
12853  * // or directly (returns the same UpdateManager instance)
12854  * var mgr = new Roo.UpdateManager("myElementId");
12855  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12856  * mgr.on("update", myFcnNeedsToKnow);
12857  * <br>
12858    // short handed call directly from the element object
12859    Roo.get("foo").load({
12860         url: "bar.php",
12861         scripts:true,
12862         params: "for=bar",
12863         text: "Loading Foo..."
12864    });
12865  * </code></pre>
12866  * @constructor
12867  * Create new UpdateManager directly.
12868  * @param {String/HTMLElement/Roo.Element} el The element to update
12869  * @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).
12870  */
12871 Roo.UpdateManager = function(el, forceNew){
12872     el = Roo.get(el);
12873     if(!forceNew && el.updateManager){
12874         return el.updateManager;
12875     }
12876     /**
12877      * The Element object
12878      * @type Roo.Element
12879      */
12880     this.el = el;
12881     /**
12882      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12883      * @type String
12884      */
12885     this.defaultUrl = null;
12886
12887     this.addEvents({
12888         /**
12889          * @event beforeupdate
12890          * Fired before an update is made, return false from your handler and the update is cancelled.
12891          * @param {Roo.Element} el
12892          * @param {String/Object/Function} url
12893          * @param {String/Object} params
12894          */
12895         "beforeupdate": true,
12896         /**
12897          * @event update
12898          * Fired after successful update is made.
12899          * @param {Roo.Element} el
12900          * @param {Object} oResponseObject The response Object
12901          */
12902         "update": true,
12903         /**
12904          * @event failure
12905          * Fired on update failure.
12906          * @param {Roo.Element} el
12907          * @param {Object} oResponseObject The response Object
12908          */
12909         "failure": true
12910     });
12911     var d = Roo.UpdateManager.defaults;
12912     /**
12913      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12914      * @type String
12915      */
12916     this.sslBlankUrl = d.sslBlankUrl;
12917     /**
12918      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12919      * @type Boolean
12920      */
12921     this.disableCaching = d.disableCaching;
12922     /**
12923      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12924      * @type String
12925      */
12926     this.indicatorText = d.indicatorText;
12927     /**
12928      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12929      * @type String
12930      */
12931     this.showLoadIndicator = d.showLoadIndicator;
12932     /**
12933      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12934      * @type Number
12935      */
12936     this.timeout = d.timeout;
12937
12938     /**
12939      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12940      * @type Boolean
12941      */
12942     this.loadScripts = d.loadScripts;
12943
12944     /**
12945      * Transaction object of current executing transaction
12946      */
12947     this.transaction = null;
12948
12949     /**
12950      * @private
12951      */
12952     this.autoRefreshProcId = null;
12953     /**
12954      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12955      * @type Function
12956      */
12957     this.refreshDelegate = this.refresh.createDelegate(this);
12958     /**
12959      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12960      * @type Function
12961      */
12962     this.updateDelegate = this.update.createDelegate(this);
12963     /**
12964      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12965      * @type Function
12966      */
12967     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12968     /**
12969      * @private
12970      */
12971     this.successDelegate = this.processSuccess.createDelegate(this);
12972     /**
12973      * @private
12974      */
12975     this.failureDelegate = this.processFailure.createDelegate(this);
12976
12977     if(!this.renderer){
12978      /**
12979       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12980       */
12981     this.renderer = new Roo.UpdateManager.BasicRenderer();
12982     }
12983     
12984     Roo.UpdateManager.superclass.constructor.call(this);
12985 };
12986
12987 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12988     /**
12989      * Get the Element this UpdateManager is bound to
12990      * @return {Roo.Element} The element
12991      */
12992     getEl : function(){
12993         return this.el;
12994     },
12995     /**
12996      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12997      * @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:
12998 <pre><code>
12999 um.update({<br/>
13000     url: "your-url.php",<br/>
13001     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13002     callback: yourFunction,<br/>
13003     scope: yourObject, //(optional scope)  <br/>
13004     discardUrl: false, <br/>
13005     nocache: false,<br/>
13006     text: "Loading...",<br/>
13007     timeout: 30,<br/>
13008     scripts: false<br/>
13009 });
13010 </code></pre>
13011      * The only required property is url. The optional properties nocache, text and scripts
13012      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13013      * @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}
13014      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13015      * @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.
13016      */
13017     update : function(url, params, callback, discardUrl){
13018         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13019             var method = this.method,
13020                 cfg;
13021             if(typeof url == "object"){ // must be config object
13022                 cfg = url;
13023                 url = cfg.url;
13024                 params = params || cfg.params;
13025                 callback = callback || cfg.callback;
13026                 discardUrl = discardUrl || cfg.discardUrl;
13027                 if(callback && cfg.scope){
13028                     callback = callback.createDelegate(cfg.scope);
13029                 }
13030                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13031                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13032                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13033                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13034                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13035             }
13036             this.showLoading();
13037             if(!discardUrl){
13038                 this.defaultUrl = url;
13039             }
13040             if(typeof url == "function"){
13041                 url = url.call(this);
13042             }
13043
13044             method = method || (params ? "POST" : "GET");
13045             if(method == "GET"){
13046                 url = this.prepareUrl(url);
13047             }
13048
13049             var o = Roo.apply(cfg ||{}, {
13050                 url : url,
13051                 params: params,
13052                 success: this.successDelegate,
13053                 failure: this.failureDelegate,
13054                 callback: undefined,
13055                 timeout: (this.timeout*1000),
13056                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13057             });
13058             Roo.log("updated manager called with timeout of " + o.timeout);
13059             this.transaction = Roo.Ajax.request(o);
13060         }
13061     },
13062
13063     /**
13064      * 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.
13065      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13066      * @param {String/HTMLElement} form The form Id or form element
13067      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13068      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13069      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13070      */
13071     formUpdate : function(form, url, reset, callback){
13072         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13073             if(typeof url == "function"){
13074                 url = url.call(this);
13075             }
13076             form = Roo.getDom(form);
13077             this.transaction = Roo.Ajax.request({
13078                 form: form,
13079                 url:url,
13080                 success: this.successDelegate,
13081                 failure: this.failureDelegate,
13082                 timeout: (this.timeout*1000),
13083                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13084             });
13085             this.showLoading.defer(1, this);
13086         }
13087     },
13088
13089     /**
13090      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13091      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13092      */
13093     refresh : function(callback){
13094         if(this.defaultUrl == null){
13095             return;
13096         }
13097         this.update(this.defaultUrl, null, callback, true);
13098     },
13099
13100     /**
13101      * Set this element to auto refresh.
13102      * @param {Number} interval How often to update (in seconds).
13103      * @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)
13104      * @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}
13105      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13106      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13107      */
13108     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13109         if(refreshNow){
13110             this.update(url || this.defaultUrl, params, callback, true);
13111         }
13112         if(this.autoRefreshProcId){
13113             clearInterval(this.autoRefreshProcId);
13114         }
13115         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13116     },
13117
13118     /**
13119      * Stop auto refresh on this element.
13120      */
13121      stopAutoRefresh : function(){
13122         if(this.autoRefreshProcId){
13123             clearInterval(this.autoRefreshProcId);
13124             delete this.autoRefreshProcId;
13125         }
13126     },
13127
13128     isAutoRefreshing : function(){
13129        return this.autoRefreshProcId ? true : false;
13130     },
13131     /**
13132      * Called to update the element to "Loading" state. Override to perform custom action.
13133      */
13134     showLoading : function(){
13135         if(this.showLoadIndicator){
13136             this.el.update(this.indicatorText);
13137         }
13138     },
13139
13140     /**
13141      * Adds unique parameter to query string if disableCaching = true
13142      * @private
13143      */
13144     prepareUrl : function(url){
13145         if(this.disableCaching){
13146             var append = "_dc=" + (new Date().getTime());
13147             if(url.indexOf("?") !== -1){
13148                 url += "&" + append;
13149             }else{
13150                 url += "?" + append;
13151             }
13152         }
13153         return url;
13154     },
13155
13156     /**
13157      * @private
13158      */
13159     processSuccess : function(response){
13160         this.transaction = null;
13161         if(response.argument.form && response.argument.reset){
13162             try{ // put in try/catch since some older FF releases had problems with this
13163                 response.argument.form.reset();
13164             }catch(e){}
13165         }
13166         if(this.loadScripts){
13167             this.renderer.render(this.el, response, this,
13168                 this.updateComplete.createDelegate(this, [response]));
13169         }else{
13170             this.renderer.render(this.el, response, this);
13171             this.updateComplete(response);
13172         }
13173     },
13174
13175     updateComplete : function(response){
13176         this.fireEvent("update", this.el, response);
13177         if(typeof response.argument.callback == "function"){
13178             response.argument.callback(this.el, true, response);
13179         }
13180     },
13181
13182     /**
13183      * @private
13184      */
13185     processFailure : function(response){
13186         this.transaction = null;
13187         this.fireEvent("failure", this.el, response);
13188         if(typeof response.argument.callback == "function"){
13189             response.argument.callback(this.el, false, response);
13190         }
13191     },
13192
13193     /**
13194      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13195      * @param {Object} renderer The object implementing the render() method
13196      */
13197     setRenderer : function(renderer){
13198         this.renderer = renderer;
13199     },
13200
13201     getRenderer : function(){
13202        return this.renderer;
13203     },
13204
13205     /**
13206      * Set the defaultUrl used for updates
13207      * @param {String/Function} defaultUrl The url or a function to call to get the url
13208      */
13209     setDefaultUrl : function(defaultUrl){
13210         this.defaultUrl = defaultUrl;
13211     },
13212
13213     /**
13214      * Aborts the executing transaction
13215      */
13216     abort : function(){
13217         if(this.transaction){
13218             Roo.Ajax.abort(this.transaction);
13219         }
13220     },
13221
13222     /**
13223      * Returns true if an update is in progress
13224      * @return {Boolean}
13225      */
13226     isUpdating : function(){
13227         if(this.transaction){
13228             return Roo.Ajax.isLoading(this.transaction);
13229         }
13230         return false;
13231     }
13232 });
13233
13234 /**
13235  * @class Roo.UpdateManager.defaults
13236  * @static (not really - but it helps the doc tool)
13237  * The defaults collection enables customizing the default properties of UpdateManager
13238  */
13239    Roo.UpdateManager.defaults = {
13240        /**
13241          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13242          * @type Number
13243          */
13244          timeout : 30,
13245
13246          /**
13247          * True to process scripts by default (Defaults to false).
13248          * @type Boolean
13249          */
13250         loadScripts : false,
13251
13252         /**
13253         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13254         * @type String
13255         */
13256         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13257         /**
13258          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13259          * @type Boolean
13260          */
13261         disableCaching : false,
13262         /**
13263          * Whether to show indicatorText when loading (Defaults to true).
13264          * @type Boolean
13265          */
13266         showLoadIndicator : true,
13267         /**
13268          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13269          * @type String
13270          */
13271         indicatorText : '<div class="loading-indicator">Loading...</div>'
13272    };
13273
13274 /**
13275  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13276  *Usage:
13277  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13278  * @param {String/HTMLElement/Roo.Element} el The element to update
13279  * @param {String} url The url
13280  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13281  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13282  * @static
13283  * @deprecated
13284  * @member Roo.UpdateManager
13285  */
13286 Roo.UpdateManager.updateElement = function(el, url, params, options){
13287     var um = Roo.get(el, true).getUpdateManager();
13288     Roo.apply(um, options);
13289     um.update(url, params, options ? options.callback : null);
13290 };
13291 // alias for backwards compat
13292 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13293 /**
13294  * @class Roo.UpdateManager.BasicRenderer
13295  * Default Content renderer. Updates the elements innerHTML with the responseText.
13296  */
13297 Roo.UpdateManager.BasicRenderer = function(){};
13298
13299 Roo.UpdateManager.BasicRenderer.prototype = {
13300     /**
13301      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13302      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13303      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13304      * @param {Roo.Element} el The element being rendered
13305      * @param {Object} response The YUI Connect response object
13306      * @param {UpdateManager} updateManager The calling update manager
13307      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13308      */
13309      render : function(el, response, updateManager, callback){
13310         el.update(response.responseText, updateManager.loadScripts, callback);
13311     }
13312 };
13313 /*
13314  * Based on:
13315  * Roo JS
13316  * (c)) Alan Knowles
13317  * Licence : LGPL
13318  */
13319
13320
13321 /**
13322  * @class Roo.DomTemplate
13323  * @extends Roo.Template
13324  * An effort at a dom based template engine..
13325  *
13326  * Similar to XTemplate, except it uses dom parsing to create the template..
13327  *
13328  * Supported features:
13329  *
13330  *  Tags:
13331
13332 <pre><code>
13333       {a_variable} - output encoded.
13334       {a_variable.format:("Y-m-d")} - call a method on the variable
13335       {a_variable:raw} - unencoded output
13336       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13337       {a_variable:this.method_on_template(...)} - call a method on the template object.
13338  
13339 </code></pre>
13340  *  The tpl tag:
13341 <pre><code>
13342         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13343         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13344         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13345         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13346   
13347 </code></pre>
13348  *      
13349  */
13350 Roo.DomTemplate = function()
13351 {
13352      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13353      if (this.html) {
13354         this.compile();
13355      }
13356 };
13357
13358
13359 Roo.extend(Roo.DomTemplate, Roo.Template, {
13360     /**
13361      * id counter for sub templates.
13362      */
13363     id : 0,
13364     /**
13365      * flag to indicate if dom parser is inside a pre,
13366      * it will strip whitespace if not.
13367      */
13368     inPre : false,
13369     
13370     /**
13371      * The various sub templates
13372      */
13373     tpls : false,
13374     
13375     
13376     
13377     /**
13378      *
13379      * basic tag replacing syntax
13380      * WORD:WORD()
13381      *
13382      * // you can fake an object call by doing this
13383      *  x.t:(test,tesT) 
13384      * 
13385      */
13386     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13387     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13388     
13389     iterChild : function (node, method) {
13390         
13391         var oldPre = this.inPre;
13392         if (node.tagName == 'PRE') {
13393             this.inPre = true;
13394         }
13395         for( var i = 0; i < node.childNodes.length; i++) {
13396             method.call(this, node.childNodes[i]);
13397         }
13398         this.inPre = oldPre;
13399     },
13400     
13401     
13402     
13403     /**
13404      * compile the template
13405      *
13406      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13407      *
13408      */
13409     compile: function()
13410     {
13411         var s = this.html;
13412         
13413         // covert the html into DOM...
13414         var doc = false;
13415         var div =false;
13416         try {
13417             doc = document.implementation.createHTMLDocument("");
13418             doc.documentElement.innerHTML =   this.html  ;
13419             div = doc.documentElement;
13420         } catch (e) {
13421             // old IE... - nasty -- it causes all sorts of issues.. with
13422             // images getting pulled from server..
13423             div = document.createElement('div');
13424             div.innerHTML = this.html;
13425         }
13426         //doc.documentElement.innerHTML = htmlBody
13427          
13428         
13429         
13430         this.tpls = [];
13431         var _t = this;
13432         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13433         
13434         var tpls = this.tpls;
13435         
13436         // create a top level template from the snippet..
13437         
13438         //Roo.log(div.innerHTML);
13439         
13440         var tpl = {
13441             uid : 'master',
13442             id : this.id++,
13443             attr : false,
13444             value : false,
13445             body : div.innerHTML,
13446             
13447             forCall : false,
13448             execCall : false,
13449             dom : div,
13450             isTop : true
13451             
13452         };
13453         tpls.unshift(tpl);
13454         
13455         
13456         // compile them...
13457         this.tpls = [];
13458         Roo.each(tpls, function(tp){
13459             this.compileTpl(tp);
13460             this.tpls[tp.id] = tp;
13461         }, this);
13462         
13463         this.master = tpls[0];
13464         return this;
13465         
13466         
13467     },
13468     
13469     compileNode : function(node, istop) {
13470         // test for
13471         //Roo.log(node);
13472         
13473         
13474         // skip anything not a tag..
13475         if (node.nodeType != 1) {
13476             if (node.nodeType == 3 && !this.inPre) {
13477                 // reduce white space..
13478                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13479                 
13480             }
13481             return;
13482         }
13483         
13484         var tpl = {
13485             uid : false,
13486             id : false,
13487             attr : false,
13488             value : false,
13489             body : '',
13490             
13491             forCall : false,
13492             execCall : false,
13493             dom : false,
13494             isTop : istop
13495             
13496             
13497         };
13498         
13499         
13500         switch(true) {
13501             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13502             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13503             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13504             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13505             // no default..
13506         }
13507         
13508         
13509         if (!tpl.attr) {
13510             // just itterate children..
13511             this.iterChild(node,this.compileNode);
13512             return;
13513         }
13514         tpl.uid = this.id++;
13515         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13516         node.removeAttribute('roo-'+ tpl.attr);
13517         if (tpl.attr != 'name') {
13518             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13519             node.parentNode.replaceChild(placeholder,  node);
13520         } else {
13521             
13522             var placeholder =  document.createElement('span');
13523             placeholder.className = 'roo-tpl-' + tpl.value;
13524             node.parentNode.replaceChild(placeholder,  node);
13525         }
13526         
13527         // parent now sees '{domtplXXXX}
13528         this.iterChild(node,this.compileNode);
13529         
13530         // we should now have node body...
13531         var div = document.createElement('div');
13532         div.appendChild(node);
13533         tpl.dom = node;
13534         // this has the unfortunate side effect of converting tagged attributes
13535         // eg. href="{...}" into %7C...%7D
13536         // this has been fixed by searching for those combo's although it's a bit hacky..
13537         
13538         
13539         tpl.body = div.innerHTML;
13540         
13541         
13542          
13543         tpl.id = tpl.uid;
13544         switch(tpl.attr) {
13545             case 'for' :
13546                 switch (tpl.value) {
13547                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13548                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13549                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13550                 }
13551                 break;
13552             
13553             case 'exec':
13554                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13555                 break;
13556             
13557             case 'if':     
13558                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13559                 break;
13560             
13561             case 'name':
13562                 tpl.id  = tpl.value; // replace non characters???
13563                 break;
13564             
13565         }
13566         
13567         
13568         this.tpls.push(tpl);
13569         
13570         
13571         
13572     },
13573     
13574     
13575     
13576     
13577     /**
13578      * Compile a segment of the template into a 'sub-template'
13579      *
13580      * 
13581      * 
13582      *
13583      */
13584     compileTpl : function(tpl)
13585     {
13586         var fm = Roo.util.Format;
13587         var useF = this.disableFormats !== true;
13588         
13589         var sep = Roo.isGecko ? "+\n" : ",\n";
13590         
13591         var undef = function(str) {
13592             Roo.debug && Roo.log("Property not found :"  + str);
13593             return '';
13594         };
13595           
13596         //Roo.log(tpl.body);
13597         
13598         
13599         
13600         var fn = function(m, lbrace, name, format, args)
13601         {
13602             //Roo.log("ARGS");
13603             //Roo.log(arguments);
13604             args = args ? args.replace(/\\'/g,"'") : args;
13605             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13606             if (typeof(format) == 'undefined') {
13607                 format =  'htmlEncode'; 
13608             }
13609             if (format == 'raw' ) {
13610                 format = false;
13611             }
13612             
13613             if(name.substr(0, 6) == 'domtpl'){
13614                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13615             }
13616             
13617             // build an array of options to determine if value is undefined..
13618             
13619             // basically get 'xxxx.yyyy' then do
13620             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13621             //    (function () { Roo.log("Property not found"); return ''; })() :
13622             //    ......
13623             
13624             var udef_ar = [];
13625             var lookfor = '';
13626             Roo.each(name.split('.'), function(st) {
13627                 lookfor += (lookfor.length ? '.': '') + st;
13628                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13629             });
13630             
13631             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13632             
13633             
13634             if(format && useF){
13635                 
13636                 args = args ? ',' + args : "";
13637                  
13638                 if(format.substr(0, 5) != "this."){
13639                     format = "fm." + format + '(';
13640                 }else{
13641                     format = 'this.call("'+ format.substr(5) + '", ';
13642                     args = ", values";
13643                 }
13644                 
13645                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13646             }
13647              
13648             if (args && args.length) {
13649                 // called with xxyx.yuu:(test,test)
13650                 // change to ()
13651                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13652             }
13653             // raw.. - :raw modifier..
13654             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13655             
13656         };
13657         var body;
13658         // branched to use + in gecko and [].join() in others
13659         if(Roo.isGecko){
13660             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13661                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13662                     "';};};";
13663         }else{
13664             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13665             body.push(tpl.body.replace(/(\r\n|\n)/g,
13666                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13667             body.push("'].join('');};};");
13668             body = body.join('');
13669         }
13670         
13671         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13672        
13673         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13674         eval(body);
13675         
13676         return this;
13677     },
13678      
13679     /**
13680      * same as applyTemplate, except it's done to one of the subTemplates
13681      * when using named templates, you can do:
13682      *
13683      * var str = pl.applySubTemplate('your-name', values);
13684      *
13685      * 
13686      * @param {Number} id of the template
13687      * @param {Object} values to apply to template
13688      * @param {Object} parent (normaly the instance of this object)
13689      */
13690     applySubTemplate : function(id, values, parent)
13691     {
13692         
13693         
13694         var t = this.tpls[id];
13695         
13696         
13697         try { 
13698             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13699                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13700                 return '';
13701             }
13702         } catch(e) {
13703             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13704             Roo.log(values);
13705           
13706             return '';
13707         }
13708         try { 
13709             
13710             if(t.execCall && t.execCall.call(this, values, parent)){
13711                 return '';
13712             }
13713         } catch(e) {
13714             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13715             Roo.log(values);
13716             return '';
13717         }
13718         
13719         try {
13720             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13721             parent = t.target ? values : parent;
13722             if(t.forCall && vs instanceof Array){
13723                 var buf = [];
13724                 for(var i = 0, len = vs.length; i < len; i++){
13725                     try {
13726                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13727                     } catch (e) {
13728                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13729                         Roo.log(e.body);
13730                         //Roo.log(t.compiled);
13731                         Roo.log(vs[i]);
13732                     }   
13733                 }
13734                 return buf.join('');
13735             }
13736         } catch (e) {
13737             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13738             Roo.log(values);
13739             return '';
13740         }
13741         try {
13742             return t.compiled.call(this, vs, parent);
13743         } catch (e) {
13744             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13745             Roo.log(e.body);
13746             //Roo.log(t.compiled);
13747             Roo.log(values);
13748             return '';
13749         }
13750     },
13751
13752    
13753
13754     applyTemplate : function(values){
13755         return this.master.compiled.call(this, values, {});
13756         //var s = this.subs;
13757     },
13758
13759     apply : function(){
13760         return this.applyTemplate.apply(this, arguments);
13761     }
13762
13763  });
13764
13765 Roo.DomTemplate.from = function(el){
13766     el = Roo.getDom(el);
13767     return new Roo.Domtemplate(el.value || el.innerHTML);
13768 };/*
13769  * Based on:
13770  * Ext JS Library 1.1.1
13771  * Copyright(c) 2006-2007, Ext JS, LLC.
13772  *
13773  * Originally Released Under LGPL - original licence link has changed is not relivant.
13774  *
13775  * Fork - LGPL
13776  * <script type="text/javascript">
13777  */
13778
13779 /**
13780  * @class Roo.util.DelayedTask
13781  * Provides a convenient method of performing setTimeout where a new
13782  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13783  * You can use this class to buffer
13784  * the keypress events for a certain number of milliseconds, and perform only if they stop
13785  * for that amount of time.
13786  * @constructor The parameters to this constructor serve as defaults and are not required.
13787  * @param {Function} fn (optional) The default function to timeout
13788  * @param {Object} scope (optional) The default scope of that timeout
13789  * @param {Array} args (optional) The default Array of arguments
13790  */
13791 Roo.util.DelayedTask = function(fn, scope, args){
13792     var id = null, d, t;
13793
13794     var call = function(){
13795         var now = new Date().getTime();
13796         if(now - t >= d){
13797             clearInterval(id);
13798             id = null;
13799             fn.apply(scope, args || []);
13800         }
13801     };
13802     /**
13803      * Cancels any pending timeout and queues a new one
13804      * @param {Number} delay The milliseconds to delay
13805      * @param {Function} newFn (optional) Overrides function passed to constructor
13806      * @param {Object} newScope (optional) Overrides scope passed to constructor
13807      * @param {Array} newArgs (optional) Overrides args passed to constructor
13808      */
13809     this.delay = function(delay, newFn, newScope, newArgs){
13810         if(id && delay != d){
13811             this.cancel();
13812         }
13813         d = delay;
13814         t = new Date().getTime();
13815         fn = newFn || fn;
13816         scope = newScope || scope;
13817         args = newArgs || args;
13818         if(!id){
13819             id = setInterval(call, d);
13820         }
13821     };
13822
13823     /**
13824      * Cancel the last queued timeout
13825      */
13826     this.cancel = function(){
13827         if(id){
13828             clearInterval(id);
13829             id = null;
13830         }
13831     };
13832 };/*
13833  * Based on:
13834  * Ext JS Library 1.1.1
13835  * Copyright(c) 2006-2007, Ext JS, LLC.
13836  *
13837  * Originally Released Under LGPL - original licence link has changed is not relivant.
13838  *
13839  * Fork - LGPL
13840  * <script type="text/javascript">
13841  */
13842 /**
13843  * @class Roo.util.TaskRunner
13844  * Manage background tasks - not sure why this is better that setInterval?
13845  * @static
13846  *
13847  */
13848  
13849 Roo.util.TaskRunner = function(interval){
13850     interval = interval || 10;
13851     var tasks = [], removeQueue = [];
13852     var id = 0;
13853     var running = false;
13854
13855     var stopThread = function(){
13856         running = false;
13857         clearInterval(id);
13858         id = 0;
13859     };
13860
13861     var startThread = function(){
13862         if(!running){
13863             running = true;
13864             id = setInterval(runTasks, interval);
13865         }
13866     };
13867
13868     var removeTask = function(task){
13869         removeQueue.push(task);
13870         if(task.onStop){
13871             task.onStop();
13872         }
13873     };
13874
13875     var runTasks = function(){
13876         if(removeQueue.length > 0){
13877             for(var i = 0, len = removeQueue.length; i < len; i++){
13878                 tasks.remove(removeQueue[i]);
13879             }
13880             removeQueue = [];
13881             if(tasks.length < 1){
13882                 stopThread();
13883                 return;
13884             }
13885         }
13886         var now = new Date().getTime();
13887         for(var i = 0, len = tasks.length; i < len; ++i){
13888             var t = tasks[i];
13889             var itime = now - t.taskRunTime;
13890             if(t.interval <= itime){
13891                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13892                 t.taskRunTime = now;
13893                 if(rt === false || t.taskRunCount === t.repeat){
13894                     removeTask(t);
13895                     return;
13896                 }
13897             }
13898             if(t.duration && t.duration <= (now - t.taskStartTime)){
13899                 removeTask(t);
13900             }
13901         }
13902     };
13903
13904     /**
13905      * Queues a new task.
13906      * @param {Object} task
13907      *
13908      * Task property : interval = how frequent to run.
13909      * Task object should implement
13910      * function run()
13911      * Task object may implement
13912      * function onStop()
13913      */
13914     this.start = function(task){
13915         tasks.push(task);
13916         task.taskStartTime = new Date().getTime();
13917         task.taskRunTime = 0;
13918         task.taskRunCount = 0;
13919         startThread();
13920         return task;
13921     };
13922     /**
13923      * Stop  new task.
13924      * @param {Object} task
13925      */
13926     this.stop = function(task){
13927         removeTask(task);
13928         return task;
13929     };
13930     /**
13931      * Stop all Tasks
13932      */
13933     this.stopAll = function(){
13934         stopThread();
13935         for(var i = 0, len = tasks.length; i < len; i++){
13936             if(tasks[i].onStop){
13937                 tasks[i].onStop();
13938             }
13939         }
13940         tasks = [];
13941         removeQueue = [];
13942     };
13943 };
13944
13945 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13946  * Based on:
13947  * Ext JS Library 1.1.1
13948  * Copyright(c) 2006-2007, Ext JS, LLC.
13949  *
13950  * Originally Released Under LGPL - original licence link has changed is not relivant.
13951  *
13952  * Fork - LGPL
13953  * <script type="text/javascript">
13954  */
13955
13956  
13957 /**
13958  * @class Roo.util.MixedCollection
13959  * @extends Roo.util.Observable
13960  * A Collection class that maintains both numeric indexes and keys and exposes events.
13961  * @constructor
13962  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13963  * collection (defaults to false)
13964  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13965  * and return the key value for that item.  This is used when available to look up the key on items that
13966  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13967  * equivalent to providing an implementation for the {@link #getKey} method.
13968  */
13969 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13970     this.items = [];
13971     this.map = {};
13972     this.keys = [];
13973     this.length = 0;
13974     this.addEvents({
13975         /**
13976          * @event clear
13977          * Fires when the collection is cleared.
13978          */
13979         "clear" : true,
13980         /**
13981          * @event add
13982          * Fires when an item is added to the collection.
13983          * @param {Number} index The index at which the item was added.
13984          * @param {Object} o The item added.
13985          * @param {String} key The key associated with the added item.
13986          */
13987         "add" : true,
13988         /**
13989          * @event replace
13990          * Fires when an item is replaced in the collection.
13991          * @param {String} key he key associated with the new added.
13992          * @param {Object} old The item being replaced.
13993          * @param {Object} new The new item.
13994          */
13995         "replace" : true,
13996         /**
13997          * @event remove
13998          * Fires when an item is removed from the collection.
13999          * @param {Object} o The item being removed.
14000          * @param {String} key (optional) The key associated with the removed item.
14001          */
14002         "remove" : true,
14003         "sort" : true
14004     });
14005     this.allowFunctions = allowFunctions === true;
14006     if(keyFn){
14007         this.getKey = keyFn;
14008     }
14009     Roo.util.MixedCollection.superclass.constructor.call(this);
14010 };
14011
14012 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14013     allowFunctions : false,
14014     
14015 /**
14016  * Adds an item to the collection.
14017  * @param {String} key The key to associate with the item
14018  * @param {Object} o The item to add.
14019  * @return {Object} The item added.
14020  */
14021     add : function(key, o){
14022         if(arguments.length == 1){
14023             o = arguments[0];
14024             key = this.getKey(o);
14025         }
14026         if(typeof key == "undefined" || key === null){
14027             this.length++;
14028             this.items.push(o);
14029             this.keys.push(null);
14030         }else{
14031             var old = this.map[key];
14032             if(old){
14033                 return this.replace(key, o);
14034             }
14035             this.length++;
14036             this.items.push(o);
14037             this.map[key] = o;
14038             this.keys.push(key);
14039         }
14040         this.fireEvent("add", this.length-1, o, key);
14041         return o;
14042     },
14043        
14044 /**
14045   * MixedCollection has a generic way to fetch keys if you implement getKey.
14046 <pre><code>
14047 // normal way
14048 var mc = new Roo.util.MixedCollection();
14049 mc.add(someEl.dom.id, someEl);
14050 mc.add(otherEl.dom.id, otherEl);
14051 //and so on
14052
14053 // using getKey
14054 var mc = new Roo.util.MixedCollection();
14055 mc.getKey = function(el){
14056    return el.dom.id;
14057 };
14058 mc.add(someEl);
14059 mc.add(otherEl);
14060
14061 // or via the constructor
14062 var mc = new Roo.util.MixedCollection(false, function(el){
14063    return el.dom.id;
14064 });
14065 mc.add(someEl);
14066 mc.add(otherEl);
14067 </code></pre>
14068  * @param o {Object} The item for which to find the key.
14069  * @return {Object} The key for the passed item.
14070  */
14071     getKey : function(o){
14072          return o.id; 
14073     },
14074    
14075 /**
14076  * Replaces an item in the collection.
14077  * @param {String} key The key associated with the item to replace, or the item to replace.
14078  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14079  * @return {Object}  The new item.
14080  */
14081     replace : function(key, o){
14082         if(arguments.length == 1){
14083             o = arguments[0];
14084             key = this.getKey(o);
14085         }
14086         var old = this.item(key);
14087         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14088              return this.add(key, o);
14089         }
14090         var index = this.indexOfKey(key);
14091         this.items[index] = o;
14092         this.map[key] = o;
14093         this.fireEvent("replace", key, old, o);
14094         return o;
14095     },
14096    
14097 /**
14098  * Adds all elements of an Array or an Object to the collection.
14099  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14100  * an Array of values, each of which are added to the collection.
14101  */
14102     addAll : function(objs){
14103         if(arguments.length > 1 || objs instanceof Array){
14104             var args = arguments.length > 1 ? arguments : objs;
14105             for(var i = 0, len = args.length; i < len; i++){
14106                 this.add(args[i]);
14107             }
14108         }else{
14109             for(var key in objs){
14110                 if(this.allowFunctions || typeof objs[key] != "function"){
14111                     this.add(key, objs[key]);
14112                 }
14113             }
14114         }
14115     },
14116    
14117 /**
14118  * Executes the specified function once for every item in the collection, passing each
14119  * item as the first and only parameter. returning false from the function will stop the iteration.
14120  * @param {Function} fn The function to execute for each item.
14121  * @param {Object} scope (optional) The scope in which to execute the function.
14122  */
14123     each : function(fn, scope){
14124         var items = [].concat(this.items); // each safe for removal
14125         for(var i = 0, len = items.length; i < len; i++){
14126             if(fn.call(scope || items[i], items[i], i, len) === false){
14127                 break;
14128             }
14129         }
14130     },
14131    
14132 /**
14133  * Executes the specified function once for every key in the collection, passing each
14134  * key, and its associated item as the first two parameters.
14135  * @param {Function} fn The function to execute for each item.
14136  * @param {Object} scope (optional) The scope in which to execute the function.
14137  */
14138     eachKey : function(fn, scope){
14139         for(var i = 0, len = this.keys.length; i < len; i++){
14140             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14141         }
14142     },
14143    
14144 /**
14145  * Returns the first item in the collection which elicits a true return value from the
14146  * passed selection function.
14147  * @param {Function} fn The selection function to execute for each item.
14148  * @param {Object} scope (optional) The scope in which to execute the function.
14149  * @return {Object} The first item in the collection which returned true from the selection function.
14150  */
14151     find : function(fn, scope){
14152         for(var i = 0, len = this.items.length; i < len; i++){
14153             if(fn.call(scope || window, this.items[i], this.keys[i])){
14154                 return this.items[i];
14155             }
14156         }
14157         return null;
14158     },
14159    
14160 /**
14161  * Inserts an item at the specified index in the collection.
14162  * @param {Number} index The index to insert the item at.
14163  * @param {String} key The key to associate with the new item, or the item itself.
14164  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14165  * @return {Object} The item inserted.
14166  */
14167     insert : function(index, key, o){
14168         if(arguments.length == 2){
14169             o = arguments[1];
14170             key = this.getKey(o);
14171         }
14172         if(index >= this.length){
14173             return this.add(key, o);
14174         }
14175         this.length++;
14176         this.items.splice(index, 0, o);
14177         if(typeof key != "undefined" && key != null){
14178             this.map[key] = o;
14179         }
14180         this.keys.splice(index, 0, key);
14181         this.fireEvent("add", index, o, key);
14182         return o;
14183     },
14184    
14185 /**
14186  * Removed an item from the collection.
14187  * @param {Object} o The item to remove.
14188  * @return {Object} The item removed.
14189  */
14190     remove : function(o){
14191         return this.removeAt(this.indexOf(o));
14192     },
14193    
14194 /**
14195  * Remove an item from a specified index in the collection.
14196  * @param {Number} index The index within the collection of the item to remove.
14197  */
14198     removeAt : function(index){
14199         if(index < this.length && index >= 0){
14200             this.length--;
14201             var o = this.items[index];
14202             this.items.splice(index, 1);
14203             var key = this.keys[index];
14204             if(typeof key != "undefined"){
14205                 delete this.map[key];
14206             }
14207             this.keys.splice(index, 1);
14208             this.fireEvent("remove", o, key);
14209         }
14210     },
14211    
14212 /**
14213  * Removed an item associated with the passed key fom the collection.
14214  * @param {String} key The key of the item to remove.
14215  */
14216     removeKey : function(key){
14217         return this.removeAt(this.indexOfKey(key));
14218     },
14219    
14220 /**
14221  * Returns the number of items in the collection.
14222  * @return {Number} the number of items in the collection.
14223  */
14224     getCount : function(){
14225         return this.length; 
14226     },
14227    
14228 /**
14229  * Returns index within the collection of the passed Object.
14230  * @param {Object} o The item to find the index of.
14231  * @return {Number} index of the item.
14232  */
14233     indexOf : function(o){
14234         if(!this.items.indexOf){
14235             for(var i = 0, len = this.items.length; i < len; i++){
14236                 if(this.items[i] == o) {
14237                     return i;
14238                 }
14239             }
14240             return -1;
14241         }else{
14242             return this.items.indexOf(o);
14243         }
14244     },
14245    
14246 /**
14247  * Returns index within the collection of the passed key.
14248  * @param {String} key The key to find the index of.
14249  * @return {Number} index of the key.
14250  */
14251     indexOfKey : function(key){
14252         if(!this.keys.indexOf){
14253             for(var i = 0, len = this.keys.length; i < len; i++){
14254                 if(this.keys[i] == key) {
14255                     return i;
14256                 }
14257             }
14258             return -1;
14259         }else{
14260             return this.keys.indexOf(key);
14261         }
14262     },
14263    
14264 /**
14265  * Returns the item associated with the passed key OR index. Key has priority over index.
14266  * @param {String/Number} key The key or index of the item.
14267  * @return {Object} The item associated with the passed key.
14268  */
14269     item : function(key){
14270         if (key === 'length') {
14271             return null;
14272         }
14273         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14274         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14275     },
14276     
14277 /**
14278  * Returns the item at the specified index.
14279  * @param {Number} index The index of the item.
14280  * @return {Object}
14281  */
14282     itemAt : function(index){
14283         return this.items[index];
14284     },
14285     
14286 /**
14287  * Returns the item associated with the passed key.
14288  * @param {String/Number} key The key of the item.
14289  * @return {Object} The item associated with the passed key.
14290  */
14291     key : function(key){
14292         return this.map[key];
14293     },
14294    
14295 /**
14296  * Returns true if the collection contains the passed Object as an item.
14297  * @param {Object} o  The Object to look for in the collection.
14298  * @return {Boolean} True if the collection contains the Object as an item.
14299  */
14300     contains : function(o){
14301         return this.indexOf(o) != -1;
14302     },
14303    
14304 /**
14305  * Returns true if the collection contains the passed Object as a key.
14306  * @param {String} key The key to look for in the collection.
14307  * @return {Boolean} True if the collection contains the Object as a key.
14308  */
14309     containsKey : function(key){
14310         return typeof this.map[key] != "undefined";
14311     },
14312    
14313 /**
14314  * Removes all items from the collection.
14315  */
14316     clear : function(){
14317         this.length = 0;
14318         this.items = [];
14319         this.keys = [];
14320         this.map = {};
14321         this.fireEvent("clear");
14322     },
14323    
14324 /**
14325  * Returns the first item in the collection.
14326  * @return {Object} the first item in the collection..
14327  */
14328     first : function(){
14329         return this.items[0]; 
14330     },
14331    
14332 /**
14333  * Returns the last item in the collection.
14334  * @return {Object} the last item in the collection..
14335  */
14336     last : function(){
14337         return this.items[this.length-1];   
14338     },
14339     
14340     _sort : function(property, dir, fn){
14341         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14342         fn = fn || function(a, b){
14343             return a-b;
14344         };
14345         var c = [], k = this.keys, items = this.items;
14346         for(var i = 0, len = items.length; i < len; i++){
14347             c[c.length] = {key: k[i], value: items[i], index: i};
14348         }
14349         c.sort(function(a, b){
14350             var v = fn(a[property], b[property]) * dsc;
14351             if(v == 0){
14352                 v = (a.index < b.index ? -1 : 1);
14353             }
14354             return v;
14355         });
14356         for(var i = 0, len = c.length; i < len; i++){
14357             items[i] = c[i].value;
14358             k[i] = c[i].key;
14359         }
14360         this.fireEvent("sort", this);
14361     },
14362     
14363     /**
14364      * Sorts this collection with the passed comparison function
14365      * @param {String} direction (optional) "ASC" or "DESC"
14366      * @param {Function} fn (optional) comparison function
14367      */
14368     sort : function(dir, fn){
14369         this._sort("value", dir, fn);
14370     },
14371     
14372     /**
14373      * Sorts this collection by keys
14374      * @param {String} direction (optional) "ASC" or "DESC"
14375      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14376      */
14377     keySort : function(dir, fn){
14378         this._sort("key", dir, fn || function(a, b){
14379             return String(a).toUpperCase()-String(b).toUpperCase();
14380         });
14381     },
14382     
14383     /**
14384      * Returns a range of items in this collection
14385      * @param {Number} startIndex (optional) defaults to 0
14386      * @param {Number} endIndex (optional) default to the last item
14387      * @return {Array} An array of items
14388      */
14389     getRange : function(start, end){
14390         var items = this.items;
14391         if(items.length < 1){
14392             return [];
14393         }
14394         start = start || 0;
14395         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14396         var r = [];
14397         if(start <= end){
14398             for(var i = start; i <= end; i++) {
14399                     r[r.length] = items[i];
14400             }
14401         }else{
14402             for(var i = start; i >= end; i--) {
14403                     r[r.length] = items[i];
14404             }
14405         }
14406         return r;
14407     },
14408         
14409     /**
14410      * Filter the <i>objects</i> in this collection by a specific property. 
14411      * Returns a new collection that has been filtered.
14412      * @param {String} property A property on your objects
14413      * @param {String/RegExp} value Either string that the property values 
14414      * should start with or a RegExp to test against the property
14415      * @return {MixedCollection} The new filtered collection
14416      */
14417     filter : function(property, value){
14418         if(!value.exec){ // not a regex
14419             value = String(value);
14420             if(value.length == 0){
14421                 return this.clone();
14422             }
14423             value = new RegExp("^" + Roo.escapeRe(value), "i");
14424         }
14425         return this.filterBy(function(o){
14426             return o && value.test(o[property]);
14427         });
14428         },
14429     
14430     /**
14431      * Filter by a function. * Returns a new collection that has been filtered.
14432      * The passed function will be called with each 
14433      * object in the collection. If the function returns true, the value is included 
14434      * otherwise it is filtered.
14435      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14436      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14437      * @return {MixedCollection} The new filtered collection
14438      */
14439     filterBy : function(fn, scope){
14440         var r = new Roo.util.MixedCollection();
14441         r.getKey = this.getKey;
14442         var k = this.keys, it = this.items;
14443         for(var i = 0, len = it.length; i < len; i++){
14444             if(fn.call(scope||this, it[i], k[i])){
14445                                 r.add(k[i], it[i]);
14446                         }
14447         }
14448         return r;
14449     },
14450     
14451     /**
14452      * Creates a duplicate of this collection
14453      * @return {MixedCollection}
14454      */
14455     clone : function(){
14456         var r = new Roo.util.MixedCollection();
14457         var k = this.keys, it = this.items;
14458         for(var i = 0, len = it.length; i < len; i++){
14459             r.add(k[i], it[i]);
14460         }
14461         r.getKey = this.getKey;
14462         return r;
14463     }
14464 });
14465 /**
14466  * Returns the item associated with the passed key or index.
14467  * @method
14468  * @param {String/Number} key The key or index of the item.
14469  * @return {Object} The item associated with the passed key.
14470  */
14471 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14472  * Based on:
14473  * Ext JS Library 1.1.1
14474  * Copyright(c) 2006-2007, Ext JS, LLC.
14475  *
14476  * Originally Released Under LGPL - original licence link has changed is not relivant.
14477  *
14478  * Fork - LGPL
14479  * <script type="text/javascript">
14480  */
14481 /**
14482  * @class Roo.util.JSON
14483  * Modified version of Douglas Crockford"s json.js that doesn"t
14484  * mess with the Object prototype 
14485  * http://www.json.org/js.html
14486  * @static
14487  */
14488 Roo.util.JSON = new (function(){
14489     var useHasOwn = {}.hasOwnProperty ? true : false;
14490     
14491     // crashes Safari in some instances
14492     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14493     
14494     var pad = function(n) {
14495         return n < 10 ? "0" + n : n;
14496     };
14497     
14498     var m = {
14499         "\b": '\\b',
14500         "\t": '\\t',
14501         "\n": '\\n',
14502         "\f": '\\f',
14503         "\r": '\\r',
14504         '"' : '\\"',
14505         "\\": '\\\\'
14506     };
14507
14508     var encodeString = function(s){
14509         if (/["\\\x00-\x1f]/.test(s)) {
14510             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14511                 var c = m[b];
14512                 if(c){
14513                     return c;
14514                 }
14515                 c = b.charCodeAt();
14516                 return "\\u00" +
14517                     Math.floor(c / 16).toString(16) +
14518                     (c % 16).toString(16);
14519             }) + '"';
14520         }
14521         return '"' + s + '"';
14522     };
14523     
14524     var encodeArray = function(o){
14525         var a = ["["], b, i, l = o.length, v;
14526             for (i = 0; i < l; i += 1) {
14527                 v = o[i];
14528                 switch (typeof v) {
14529                     case "undefined":
14530                     case "function":
14531                     case "unknown":
14532                         break;
14533                     default:
14534                         if (b) {
14535                             a.push(',');
14536                         }
14537                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14538                         b = true;
14539                 }
14540             }
14541             a.push("]");
14542             return a.join("");
14543     };
14544     
14545     var encodeDate = function(o){
14546         return '"' + o.getFullYear() + "-" +
14547                 pad(o.getMonth() + 1) + "-" +
14548                 pad(o.getDate()) + "T" +
14549                 pad(o.getHours()) + ":" +
14550                 pad(o.getMinutes()) + ":" +
14551                 pad(o.getSeconds()) + '"';
14552     };
14553     
14554     /**
14555      * Encodes an Object, Array or other value
14556      * @param {Mixed} o The variable to encode
14557      * @return {String} The JSON string
14558      */
14559     this.encode = function(o)
14560     {
14561         // should this be extended to fully wrap stringify..
14562         
14563         if(typeof o == "undefined" || o === null){
14564             return "null";
14565         }else if(o instanceof Array){
14566             return encodeArray(o);
14567         }else if(o instanceof Date){
14568             return encodeDate(o);
14569         }else if(typeof o == "string"){
14570             return encodeString(o);
14571         }else if(typeof o == "number"){
14572             return isFinite(o) ? String(o) : "null";
14573         }else if(typeof o == "boolean"){
14574             return String(o);
14575         }else {
14576             var a = ["{"], b, i, v;
14577             for (i in o) {
14578                 if(!useHasOwn || o.hasOwnProperty(i)) {
14579                     v = o[i];
14580                     switch (typeof v) {
14581                     case "undefined":
14582                     case "function":
14583                     case "unknown":
14584                         break;
14585                     default:
14586                         if(b){
14587                             a.push(',');
14588                         }
14589                         a.push(this.encode(i), ":",
14590                                 v === null ? "null" : this.encode(v));
14591                         b = true;
14592                     }
14593                 }
14594             }
14595             a.push("}");
14596             return a.join("");
14597         }
14598     };
14599     
14600     /**
14601      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14602      * @param {String} json The JSON string
14603      * @return {Object} The resulting object
14604      */
14605     this.decode = function(json){
14606         
14607         return  /** eval:var:json */ eval("(" + json + ')');
14608     };
14609 })();
14610 /** 
14611  * Shorthand for {@link Roo.util.JSON#encode}
14612  * @member Roo encode 
14613  * @method */
14614 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14615 /** 
14616  * Shorthand for {@link Roo.util.JSON#decode}
14617  * @member Roo decode 
14618  * @method */
14619 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14620 /*
14621  * Based on:
14622  * Ext JS Library 1.1.1
14623  * Copyright(c) 2006-2007, Ext JS, LLC.
14624  *
14625  * Originally Released Under LGPL - original licence link has changed is not relivant.
14626  *
14627  * Fork - LGPL
14628  * <script type="text/javascript">
14629  */
14630  
14631 /**
14632  * @class Roo.util.Format
14633  * Reusable data formatting functions
14634  * @static
14635  */
14636 Roo.util.Format = function(){
14637     var trimRe = /^\s+|\s+$/g;
14638     return {
14639         /**
14640          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14641          * @param {String} value The string to truncate
14642          * @param {Number} length The maximum length to allow before truncating
14643          * @return {String} The converted text
14644          */
14645         ellipsis : function(value, len){
14646             if(value && value.length > len){
14647                 return value.substr(0, len-3)+"...";
14648             }
14649             return value;
14650         },
14651
14652         /**
14653          * Checks a reference and converts it to empty string if it is undefined
14654          * @param {Mixed} value Reference to check
14655          * @return {Mixed} Empty string if converted, otherwise the original value
14656          */
14657         undef : function(value){
14658             return typeof value != "undefined" ? value : "";
14659         },
14660
14661         /**
14662          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14663          * @param {String} value The string to encode
14664          * @return {String} The encoded text
14665          */
14666         htmlEncode : function(value){
14667             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14668         },
14669
14670         /**
14671          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14672          * @param {String} value The string to decode
14673          * @return {String} The decoded text
14674          */
14675         htmlDecode : function(value){
14676             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14677         },
14678
14679         /**
14680          * Trims any whitespace from either side of a string
14681          * @param {String} value The text to trim
14682          * @return {String} The trimmed text
14683          */
14684         trim : function(value){
14685             return String(value).replace(trimRe, "");
14686         },
14687
14688         /**
14689          * Returns a substring from within an original string
14690          * @param {String} value The original text
14691          * @param {Number} start The start index of the substring
14692          * @param {Number} length The length of the substring
14693          * @return {String} The substring
14694          */
14695         substr : function(value, start, length){
14696             return String(value).substr(start, length);
14697         },
14698
14699         /**
14700          * Converts a string to all lower case letters
14701          * @param {String} value The text to convert
14702          * @return {String} The converted text
14703          */
14704         lowercase : function(value){
14705             return String(value).toLowerCase();
14706         },
14707
14708         /**
14709          * Converts a string to all upper case letters
14710          * @param {String} value The text to convert
14711          * @return {String} The converted text
14712          */
14713         uppercase : function(value){
14714             return String(value).toUpperCase();
14715         },
14716
14717         /**
14718          * Converts the first character only of a string to upper case
14719          * @param {String} value The text to convert
14720          * @return {String} The converted text
14721          */
14722         capitalize : function(value){
14723             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14724         },
14725
14726         // private
14727         call : function(value, fn){
14728             if(arguments.length > 2){
14729                 var args = Array.prototype.slice.call(arguments, 2);
14730                 args.unshift(value);
14731                  
14732                 return /** eval:var:value */  eval(fn).apply(window, args);
14733             }else{
14734                 /** eval:var:value */
14735                 return /** eval:var:value */ eval(fn).call(window, value);
14736             }
14737         },
14738
14739        
14740         /**
14741          * safer version of Math.toFixed..??/
14742          * @param {Number/String} value The numeric value to format
14743          * @param {Number/String} value Decimal places 
14744          * @return {String} The formatted currency string
14745          */
14746         toFixed : function(v, n)
14747         {
14748             // why not use to fixed - precision is buggered???
14749             if (!n) {
14750                 return Math.round(v-0);
14751             }
14752             var fact = Math.pow(10,n+1);
14753             v = (Math.round((v-0)*fact))/fact;
14754             var z = (''+fact).substring(2);
14755             if (v == Math.floor(v)) {
14756                 return Math.floor(v) + '.' + z;
14757             }
14758             
14759             // now just padd decimals..
14760             var ps = String(v).split('.');
14761             var fd = (ps[1] + z);
14762             var r = fd.substring(0,n); 
14763             var rm = fd.substring(n); 
14764             if (rm < 5) {
14765                 return ps[0] + '.' + r;
14766             }
14767             r*=1; // turn it into a number;
14768             r++;
14769             if (String(r).length != n) {
14770                 ps[0]*=1;
14771                 ps[0]++;
14772                 r = String(r).substring(1); // chop the end off.
14773             }
14774             
14775             return ps[0] + '.' + r;
14776              
14777         },
14778         
14779         /**
14780          * Format a number as US currency
14781          * @param {Number/String} value The numeric value to format
14782          * @return {String} The formatted currency string
14783          */
14784         usMoney : function(v){
14785             return '$' + Roo.util.Format.number(v);
14786         },
14787         
14788         /**
14789          * Format a number
14790          * eventually this should probably emulate php's number_format
14791          * @param {Number/String} value The numeric value to format
14792          * @param {Number} decimals number of decimal places
14793          * @param {String} delimiter for thousands (default comma)
14794          * @return {String} The formatted currency string
14795          */
14796         number : function(v, decimals, thousandsDelimiter)
14797         {
14798             // multiply and round.
14799             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14800             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14801             
14802             var mul = Math.pow(10, decimals);
14803             var zero = String(mul).substring(1);
14804             v = (Math.round((v-0)*mul))/mul;
14805             
14806             // if it's '0' number.. then
14807             
14808             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14809             v = String(v);
14810             var ps = v.split('.');
14811             var whole = ps[0];
14812             
14813             var r = /(\d+)(\d{3})/;
14814             // add comma's
14815             
14816             if(thousandsDelimiter.length != 0) {
14817                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14818             } 
14819             
14820             var sub = ps[1] ?
14821                     // has decimals..
14822                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14823                     // does not have decimals
14824                     (decimals ? ('.' + zero) : '');
14825             
14826             
14827             return whole + sub ;
14828         },
14829         
14830         /**
14831          * Parse a value into a formatted date using the specified format pattern.
14832          * @param {Mixed} value The value to format
14833          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14834          * @return {String} The formatted date string
14835          */
14836         date : function(v, format){
14837             if(!v){
14838                 return "";
14839             }
14840             if(!(v instanceof Date)){
14841                 v = new Date(Date.parse(v));
14842             }
14843             return v.dateFormat(format || Roo.util.Format.defaults.date);
14844         },
14845
14846         /**
14847          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14848          * @param {String} format Any valid date format string
14849          * @return {Function} The date formatting function
14850          */
14851         dateRenderer : function(format){
14852             return function(v){
14853                 return Roo.util.Format.date(v, format);  
14854             };
14855         },
14856
14857         // private
14858         stripTagsRE : /<\/?[^>]+>/gi,
14859         
14860         /**
14861          * Strips all HTML tags
14862          * @param {Mixed} value The text from which to strip tags
14863          * @return {String} The stripped text
14864          */
14865         stripTags : function(v){
14866             return !v ? v : String(v).replace(this.stripTagsRE, "");
14867         },
14868         
14869         /**
14870          * Size in Mb,Gb etc.
14871          * @param {Number} value The number to be formated
14872          * @param {number} decimals how many decimal places
14873          * @return {String} the formated string
14874          */
14875         size : function(value, decimals)
14876         {
14877             var sizes = ['b', 'k', 'M', 'G', 'T'];
14878             if (value == 0) {
14879                 return 0;
14880             }
14881             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14882             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14883         }
14884         
14885         
14886         
14887     };
14888 }();
14889 Roo.util.Format.defaults = {
14890     date : 'd/M/Y'
14891 };/*
14892  * Based on:
14893  * Ext JS Library 1.1.1
14894  * Copyright(c) 2006-2007, Ext JS, LLC.
14895  *
14896  * Originally Released Under LGPL - original licence link has changed is not relivant.
14897  *
14898  * Fork - LGPL
14899  * <script type="text/javascript">
14900  */
14901
14902
14903  
14904
14905 /**
14906  * @class Roo.MasterTemplate
14907  * @extends Roo.Template
14908  * Provides a template that can have child templates. The syntax is:
14909 <pre><code>
14910 var t = new Roo.MasterTemplate(
14911         '&lt;select name="{name}"&gt;',
14912                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14913         '&lt;/select&gt;'
14914 );
14915 t.add('options', {value: 'foo', text: 'bar'});
14916 // or you can add multiple child elements in one shot
14917 t.addAll('options', [
14918     {value: 'foo', text: 'bar'},
14919     {value: 'foo2', text: 'bar2'},
14920     {value: 'foo3', text: 'bar3'}
14921 ]);
14922 // then append, applying the master template values
14923 t.append('my-form', {name: 'my-select'});
14924 </code></pre>
14925 * A name attribute for the child template is not required if you have only one child
14926 * template or you want to refer to them by index.
14927  */
14928 Roo.MasterTemplate = function(){
14929     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14930     this.originalHtml = this.html;
14931     var st = {};
14932     var m, re = this.subTemplateRe;
14933     re.lastIndex = 0;
14934     var subIndex = 0;
14935     while(m = re.exec(this.html)){
14936         var name = m[1], content = m[2];
14937         st[subIndex] = {
14938             name: name,
14939             index: subIndex,
14940             buffer: [],
14941             tpl : new Roo.Template(content)
14942         };
14943         if(name){
14944             st[name] = st[subIndex];
14945         }
14946         st[subIndex].tpl.compile();
14947         st[subIndex].tpl.call = this.call.createDelegate(this);
14948         subIndex++;
14949     }
14950     this.subCount = subIndex;
14951     this.subs = st;
14952 };
14953 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14954     /**
14955     * The regular expression used to match sub templates
14956     * @type RegExp
14957     * @property
14958     */
14959     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14960
14961     /**
14962      * Applies the passed values to a child template.
14963      * @param {String/Number} name (optional) The name or index of the child template
14964      * @param {Array/Object} values The values to be applied to the template
14965      * @return {MasterTemplate} this
14966      */
14967      add : function(name, values){
14968         if(arguments.length == 1){
14969             values = arguments[0];
14970             name = 0;
14971         }
14972         var s = this.subs[name];
14973         s.buffer[s.buffer.length] = s.tpl.apply(values);
14974         return this;
14975     },
14976
14977     /**
14978      * Applies all the passed values to a child template.
14979      * @param {String/Number} name (optional) The name or index of the child template
14980      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14981      * @param {Boolean} reset (optional) True to reset the template first
14982      * @return {MasterTemplate} this
14983      */
14984     fill : function(name, values, reset){
14985         var a = arguments;
14986         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14987             values = a[0];
14988             name = 0;
14989             reset = a[1];
14990         }
14991         if(reset){
14992             this.reset();
14993         }
14994         for(var i = 0, len = values.length; i < len; i++){
14995             this.add(name, values[i]);
14996         }
14997         return this;
14998     },
14999
15000     /**
15001      * Resets the template for reuse
15002      * @return {MasterTemplate} this
15003      */
15004      reset : function(){
15005         var s = this.subs;
15006         for(var i = 0; i < this.subCount; i++){
15007             s[i].buffer = [];
15008         }
15009         return this;
15010     },
15011
15012     applyTemplate : function(values){
15013         var s = this.subs;
15014         var replaceIndex = -1;
15015         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15016             return s[++replaceIndex].buffer.join("");
15017         });
15018         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15019     },
15020
15021     apply : function(){
15022         return this.applyTemplate.apply(this, arguments);
15023     },
15024
15025     compile : function(){return this;}
15026 });
15027
15028 /**
15029  * Alias for fill().
15030  * @method
15031  */
15032 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15033  /**
15034  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15035  * var tpl = Roo.MasterTemplate.from('element-id');
15036  * @param {String/HTMLElement} el
15037  * @param {Object} config
15038  * @static
15039  */
15040 Roo.MasterTemplate.from = function(el, config){
15041     el = Roo.getDom(el);
15042     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15043 };/*
15044  * Based on:
15045  * Ext JS Library 1.1.1
15046  * Copyright(c) 2006-2007, Ext JS, LLC.
15047  *
15048  * Originally Released Under LGPL - original licence link has changed is not relivant.
15049  *
15050  * Fork - LGPL
15051  * <script type="text/javascript">
15052  */
15053
15054  
15055 /**
15056  * @class Roo.util.CSS
15057  * Utility class for manipulating CSS rules
15058  * @static
15059
15060  */
15061 Roo.util.CSS = function(){
15062         var rules = null;
15063         var doc = document;
15064
15065     var camelRe = /(-[a-z])/gi;
15066     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15067
15068    return {
15069    /**
15070     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15071     * tag and appended to the HEAD of the document.
15072     * @param {String|Object} cssText The text containing the css rules
15073     * @param {String} id An id to add to the stylesheet for later removal
15074     * @return {StyleSheet}
15075     */
15076     createStyleSheet : function(cssText, id){
15077         var ss;
15078         var head = doc.getElementsByTagName("head")[0];
15079         var nrules = doc.createElement("style");
15080         nrules.setAttribute("type", "text/css");
15081         if(id){
15082             nrules.setAttribute("id", id);
15083         }
15084         if (typeof(cssText) != 'string') {
15085             // support object maps..
15086             // not sure if this a good idea.. 
15087             // perhaps it should be merged with the general css handling
15088             // and handle js style props.
15089             var cssTextNew = [];
15090             for(var n in cssText) {
15091                 var citems = [];
15092                 for(var k in cssText[n]) {
15093                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15094                 }
15095                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15096                 
15097             }
15098             cssText = cssTextNew.join("\n");
15099             
15100         }
15101        
15102        
15103        if(Roo.isIE){
15104            head.appendChild(nrules);
15105            ss = nrules.styleSheet;
15106            ss.cssText = cssText;
15107        }else{
15108            try{
15109                 nrules.appendChild(doc.createTextNode(cssText));
15110            }catch(e){
15111                nrules.cssText = cssText; 
15112            }
15113            head.appendChild(nrules);
15114            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15115        }
15116        this.cacheStyleSheet(ss);
15117        return ss;
15118    },
15119
15120    /**
15121     * Removes a style or link tag by id
15122     * @param {String} id The id of the tag
15123     */
15124    removeStyleSheet : function(id){
15125        var existing = doc.getElementById(id);
15126        if(existing){
15127            existing.parentNode.removeChild(existing);
15128        }
15129    },
15130
15131    /**
15132     * Dynamically swaps an existing stylesheet reference for a new one
15133     * @param {String} id The id of an existing link tag to remove
15134     * @param {String} url The href of the new stylesheet to include
15135     */
15136    swapStyleSheet : function(id, url){
15137        this.removeStyleSheet(id);
15138        var ss = doc.createElement("link");
15139        ss.setAttribute("rel", "stylesheet");
15140        ss.setAttribute("type", "text/css");
15141        ss.setAttribute("id", id);
15142        ss.setAttribute("href", url);
15143        doc.getElementsByTagName("head")[0].appendChild(ss);
15144    },
15145    
15146    /**
15147     * Refresh the rule cache if you have dynamically added stylesheets
15148     * @return {Object} An object (hash) of rules indexed by selector
15149     */
15150    refreshCache : function(){
15151        return this.getRules(true);
15152    },
15153
15154    // private
15155    cacheStyleSheet : function(stylesheet){
15156        if(!rules){
15157            rules = {};
15158        }
15159        try{// try catch for cross domain access issue
15160            var ssRules = stylesheet.cssRules || stylesheet.rules;
15161            for(var j = ssRules.length-1; j >= 0; --j){
15162                rules[ssRules[j].selectorText] = ssRules[j];
15163            }
15164        }catch(e){}
15165    },
15166    
15167    /**
15168     * Gets all css rules for the document
15169     * @param {Boolean} refreshCache true to refresh the internal cache
15170     * @return {Object} An object (hash) of rules indexed by selector
15171     */
15172    getRules : function(refreshCache){
15173                 if(rules == null || refreshCache){
15174                         rules = {};
15175                         var ds = doc.styleSheets;
15176                         for(var i =0, len = ds.length; i < len; i++){
15177                             try{
15178                         this.cacheStyleSheet(ds[i]);
15179                     }catch(e){} 
15180                 }
15181                 }
15182                 return rules;
15183         },
15184         
15185         /**
15186     * Gets an an individual CSS rule by selector(s)
15187     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15188     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15189     * @return {CSSRule} The CSS rule or null if one is not found
15190     */
15191    getRule : function(selector, refreshCache){
15192                 var rs = this.getRules(refreshCache);
15193                 if(!(selector instanceof Array)){
15194                     return rs[selector];
15195                 }
15196                 for(var i = 0; i < selector.length; i++){
15197                         if(rs[selector[i]]){
15198                                 return rs[selector[i]];
15199                         }
15200                 }
15201                 return null;
15202         },
15203         
15204         
15205         /**
15206     * Updates a rule property
15207     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15208     * @param {String} property The css property
15209     * @param {String} value The new value for the property
15210     * @return {Boolean} true If a rule was found and updated
15211     */
15212    updateRule : function(selector, property, value){
15213                 if(!(selector instanceof Array)){
15214                         var rule = this.getRule(selector);
15215                         if(rule){
15216                                 rule.style[property.replace(camelRe, camelFn)] = value;
15217                                 return true;
15218                         }
15219                 }else{
15220                         for(var i = 0; i < selector.length; i++){
15221                                 if(this.updateRule(selector[i], property, value)){
15222                                         return true;
15223                                 }
15224                         }
15225                 }
15226                 return false;
15227         }
15228    };   
15229 }();/*
15230  * Based on:
15231  * Ext JS Library 1.1.1
15232  * Copyright(c) 2006-2007, Ext JS, LLC.
15233  *
15234  * Originally Released Under LGPL - original licence link has changed is not relivant.
15235  *
15236  * Fork - LGPL
15237  * <script type="text/javascript">
15238  */
15239
15240  
15241
15242 /**
15243  * @class Roo.util.ClickRepeater
15244  * @extends Roo.util.Observable
15245  * 
15246  * A wrapper class which can be applied to any element. Fires a "click" event while the
15247  * mouse is pressed. The interval between firings may be specified in the config but
15248  * defaults to 10 milliseconds.
15249  * 
15250  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15251  * 
15252  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15253  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15254  * Similar to an autorepeat key delay.
15255  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15256  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15257  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15258  *           "interval" and "delay" are ignored. "immediate" is honored.
15259  * @cfg {Boolean} preventDefault True to prevent the default click event
15260  * @cfg {Boolean} stopDefault True to stop the default click event
15261  * 
15262  * @history
15263  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15264  *     2007-02-02 jvs Renamed to ClickRepeater
15265  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15266  *
15267  *  @constructor
15268  * @param {String/HTMLElement/Element} el The element to listen on
15269  * @param {Object} config
15270  **/
15271 Roo.util.ClickRepeater = function(el, config)
15272 {
15273     this.el = Roo.get(el);
15274     this.el.unselectable();
15275
15276     Roo.apply(this, config);
15277
15278     this.addEvents({
15279     /**
15280      * @event mousedown
15281      * Fires when the mouse button is depressed.
15282      * @param {Roo.util.ClickRepeater} this
15283      */
15284         "mousedown" : true,
15285     /**
15286      * @event click
15287      * Fires on a specified interval during the time the element is pressed.
15288      * @param {Roo.util.ClickRepeater} this
15289      */
15290         "click" : true,
15291     /**
15292      * @event mouseup
15293      * Fires when the mouse key is released.
15294      * @param {Roo.util.ClickRepeater} this
15295      */
15296         "mouseup" : true
15297     });
15298
15299     this.el.on("mousedown", this.handleMouseDown, this);
15300     if(this.preventDefault || this.stopDefault){
15301         this.el.on("click", function(e){
15302             if(this.preventDefault){
15303                 e.preventDefault();
15304             }
15305             if(this.stopDefault){
15306                 e.stopEvent();
15307             }
15308         }, this);
15309     }
15310
15311     // allow inline handler
15312     if(this.handler){
15313         this.on("click", this.handler,  this.scope || this);
15314     }
15315
15316     Roo.util.ClickRepeater.superclass.constructor.call(this);
15317 };
15318
15319 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15320     interval : 20,
15321     delay: 250,
15322     preventDefault : true,
15323     stopDefault : false,
15324     timer : 0,
15325
15326     // private
15327     handleMouseDown : function(){
15328         clearTimeout(this.timer);
15329         this.el.blur();
15330         if(this.pressClass){
15331             this.el.addClass(this.pressClass);
15332         }
15333         this.mousedownTime = new Date();
15334
15335         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15336         this.el.on("mouseout", this.handleMouseOut, this);
15337
15338         this.fireEvent("mousedown", this);
15339         this.fireEvent("click", this);
15340         
15341         this.timer = this.click.defer(this.delay || this.interval, this);
15342     },
15343
15344     // private
15345     click : function(){
15346         this.fireEvent("click", this);
15347         this.timer = this.click.defer(this.getInterval(), this);
15348     },
15349
15350     // private
15351     getInterval: function(){
15352         if(!this.accelerate){
15353             return this.interval;
15354         }
15355         var pressTime = this.mousedownTime.getElapsed();
15356         if(pressTime < 500){
15357             return 400;
15358         }else if(pressTime < 1700){
15359             return 320;
15360         }else if(pressTime < 2600){
15361             return 250;
15362         }else if(pressTime < 3500){
15363             return 180;
15364         }else if(pressTime < 4400){
15365             return 140;
15366         }else if(pressTime < 5300){
15367             return 80;
15368         }else if(pressTime < 6200){
15369             return 50;
15370         }else{
15371             return 10;
15372         }
15373     },
15374
15375     // private
15376     handleMouseOut : function(){
15377         clearTimeout(this.timer);
15378         if(this.pressClass){
15379             this.el.removeClass(this.pressClass);
15380         }
15381         this.el.on("mouseover", this.handleMouseReturn, this);
15382     },
15383
15384     // private
15385     handleMouseReturn : function(){
15386         this.el.un("mouseover", this.handleMouseReturn);
15387         if(this.pressClass){
15388             this.el.addClass(this.pressClass);
15389         }
15390         this.click();
15391     },
15392
15393     // private
15394     handleMouseUp : function(){
15395         clearTimeout(this.timer);
15396         this.el.un("mouseover", this.handleMouseReturn);
15397         this.el.un("mouseout", this.handleMouseOut);
15398         Roo.get(document).un("mouseup", this.handleMouseUp);
15399         this.el.removeClass(this.pressClass);
15400         this.fireEvent("mouseup", this);
15401     }
15402 });/**
15403  * @class Roo.util.Clipboard
15404  * @static
15405  * 
15406  * Clipboard UTILS
15407  * 
15408  **/
15409 Roo.util.Clipboard = {
15410     /**
15411      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15412      * @param {String} text to copy to clipboard
15413      */
15414     write : function(text) {
15415         // navigator clipboard api needs a secure context (https)
15416         if (navigator.clipboard && window.isSecureContext) {
15417             // navigator clipboard api method'
15418             navigator.clipboard.writeText(text);
15419             return ;
15420         } 
15421         // text area method
15422         var ta = document.createElement("textarea");
15423         ta.value = text;
15424         // make the textarea out of viewport
15425         ta.style.position = "fixed";
15426         ta.style.left = "-999999px";
15427         ta.style.top = "-999999px";
15428         document.body.appendChild(ta);
15429         ta.focus();
15430         ta.select();
15431         document.execCommand('copy');
15432         (function() {
15433             ta.remove();
15434         }).defer(100);
15435         
15436     }
15437         
15438 }
15439     /*
15440  * Based on:
15441  * Ext JS Library 1.1.1
15442  * Copyright(c) 2006-2007, Ext JS, LLC.
15443  *
15444  * Originally Released Under LGPL - original licence link has changed is not relivant.
15445  *
15446  * Fork - LGPL
15447  * <script type="text/javascript">
15448  */
15449
15450  
15451 /**
15452  * @class Roo.KeyNav
15453  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15454  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15455  * way to implement custom navigation schemes for any UI component.</p>
15456  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15457  * pageUp, pageDown, del, home, end.  Usage:</p>
15458  <pre><code>
15459 var nav = new Roo.KeyNav("my-element", {
15460     "left" : function(e){
15461         this.moveLeft(e.ctrlKey);
15462     },
15463     "right" : function(e){
15464         this.moveRight(e.ctrlKey);
15465     },
15466     "enter" : function(e){
15467         this.save();
15468     },
15469     scope : this
15470 });
15471 </code></pre>
15472  * @constructor
15473  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15474  * @param {Object} config The config
15475  */
15476 Roo.KeyNav = function(el, config){
15477     this.el = Roo.get(el);
15478     Roo.apply(this, config);
15479     if(!this.disabled){
15480         this.disabled = true;
15481         this.enable();
15482     }
15483 };
15484
15485 Roo.KeyNav.prototype = {
15486     /**
15487      * @cfg {Boolean} disabled
15488      * True to disable this KeyNav instance (defaults to false)
15489      */
15490     disabled : false,
15491     /**
15492      * @cfg {String} defaultEventAction
15493      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15494      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15495      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15496      */
15497     defaultEventAction: "stopEvent",
15498     /**
15499      * @cfg {Boolean} forceKeyDown
15500      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15501      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15502      * handle keydown instead of keypress.
15503      */
15504     forceKeyDown : false,
15505
15506     // private
15507     prepareEvent : function(e){
15508         var k = e.getKey();
15509         var h = this.keyToHandler[k];
15510         //if(h && this[h]){
15511         //    e.stopPropagation();
15512         //}
15513         if(Roo.isSafari && h && k >= 37 && k <= 40){
15514             e.stopEvent();
15515         }
15516     },
15517
15518     // private
15519     relay : function(e){
15520         var k = e.getKey();
15521         var h = this.keyToHandler[k];
15522         if(h && this[h]){
15523             if(this.doRelay(e, this[h], h) !== true){
15524                 e[this.defaultEventAction]();
15525             }
15526         }
15527     },
15528
15529     // private
15530     doRelay : function(e, h, hname){
15531         return h.call(this.scope || this, e);
15532     },
15533
15534     // possible handlers
15535     enter : false,
15536     left : false,
15537     right : false,
15538     up : false,
15539     down : false,
15540     tab : false,
15541     esc : false,
15542     pageUp : false,
15543     pageDown : false,
15544     del : false,
15545     home : false,
15546     end : false,
15547
15548     // quick lookup hash
15549     keyToHandler : {
15550         37 : "left",
15551         39 : "right",
15552         38 : "up",
15553         40 : "down",
15554         33 : "pageUp",
15555         34 : "pageDown",
15556         46 : "del",
15557         36 : "home",
15558         35 : "end",
15559         13 : "enter",
15560         27 : "esc",
15561         9  : "tab"
15562     },
15563
15564         /**
15565          * Enable this KeyNav
15566          */
15567         enable: function(){
15568                 if(this.disabled){
15569             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15570             // the EventObject will normalize Safari automatically
15571             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15572                 this.el.on("keydown", this.relay,  this);
15573             }else{
15574                 this.el.on("keydown", this.prepareEvent,  this);
15575                 this.el.on("keypress", this.relay,  this);
15576             }
15577                     this.disabled = false;
15578                 }
15579         },
15580
15581         /**
15582          * Disable this KeyNav
15583          */
15584         disable: function(){
15585                 if(!this.disabled){
15586                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15587                 this.el.un("keydown", this.relay);
15588             }else{
15589                 this.el.un("keydown", this.prepareEvent);
15590                 this.el.un("keypress", this.relay);
15591             }
15592                     this.disabled = true;
15593                 }
15594         }
15595 };/*
15596  * Based on:
15597  * Ext JS Library 1.1.1
15598  * Copyright(c) 2006-2007, Ext JS, LLC.
15599  *
15600  * Originally Released Under LGPL - original licence link has changed is not relivant.
15601  *
15602  * Fork - LGPL
15603  * <script type="text/javascript">
15604  */
15605
15606  
15607 /**
15608  * @class Roo.KeyMap
15609  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15610  * The constructor accepts the same config object as defined by {@link #addBinding}.
15611  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15612  * combination it will call the function with this signature (if the match is a multi-key
15613  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15614  * A KeyMap can also handle a string representation of keys.<br />
15615  * Usage:
15616  <pre><code>
15617 // map one key by key code
15618 var map = new Roo.KeyMap("my-element", {
15619     key: 13, // or Roo.EventObject.ENTER
15620     fn: myHandler,
15621     scope: myObject
15622 });
15623
15624 // map multiple keys to one action by string
15625 var map = new Roo.KeyMap("my-element", {
15626     key: "a\r\n\t",
15627     fn: myHandler,
15628     scope: myObject
15629 });
15630
15631 // map multiple keys to multiple actions by strings and array of codes
15632 var map = new Roo.KeyMap("my-element", [
15633     {
15634         key: [10,13],
15635         fn: function(){ alert("Return was pressed"); }
15636     }, {
15637         key: "abc",
15638         fn: function(){ alert('a, b or c was pressed'); }
15639     }, {
15640         key: "\t",
15641         ctrl:true,
15642         shift:true,
15643         fn: function(){ alert('Control + shift + tab was pressed.'); }
15644     }
15645 ]);
15646 </code></pre>
15647  * <b>Note: A KeyMap starts enabled</b>
15648  * @constructor
15649  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15650  * @param {Object} config The config (see {@link #addBinding})
15651  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15652  */
15653 Roo.KeyMap = function(el, config, eventName){
15654     this.el  = Roo.get(el);
15655     this.eventName = eventName || "keydown";
15656     this.bindings = [];
15657     if(config){
15658         this.addBinding(config);
15659     }
15660     this.enable();
15661 };
15662
15663 Roo.KeyMap.prototype = {
15664     /**
15665      * True to stop the event from bubbling and prevent the default browser action if the
15666      * key was handled by the KeyMap (defaults to false)
15667      * @type Boolean
15668      */
15669     stopEvent : false,
15670
15671     /**
15672      * Add a new binding to this KeyMap. The following config object properties are supported:
15673      * <pre>
15674 Property    Type             Description
15675 ----------  ---------------  ----------------------------------------------------------------------
15676 key         String/Array     A single keycode or an array of keycodes to handle
15677 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15678 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15679 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15680 fn          Function         The function to call when KeyMap finds the expected key combination
15681 scope       Object           The scope of the callback function
15682 </pre>
15683      *
15684      * Usage:
15685      * <pre><code>
15686 // Create a KeyMap
15687 var map = new Roo.KeyMap(document, {
15688     key: Roo.EventObject.ENTER,
15689     fn: handleKey,
15690     scope: this
15691 });
15692
15693 //Add a new binding to the existing KeyMap later
15694 map.addBinding({
15695     key: 'abc',
15696     shift: true,
15697     fn: handleKey,
15698     scope: this
15699 });
15700 </code></pre>
15701      * @param {Object/Array} config A single KeyMap config or an array of configs
15702      */
15703         addBinding : function(config){
15704         if(config instanceof Array){
15705             for(var i = 0, len = config.length; i < len; i++){
15706                 this.addBinding(config[i]);
15707             }
15708             return;
15709         }
15710         var keyCode = config.key,
15711             shift = config.shift, 
15712             ctrl = config.ctrl, 
15713             alt = config.alt,
15714             fn = config.fn,
15715             scope = config.scope;
15716         if(typeof keyCode == "string"){
15717             var ks = [];
15718             var keyString = keyCode.toUpperCase();
15719             for(var j = 0, len = keyString.length; j < len; j++){
15720                 ks.push(keyString.charCodeAt(j));
15721             }
15722             keyCode = ks;
15723         }
15724         var keyArray = keyCode instanceof Array;
15725         var handler = function(e){
15726             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15727                 var k = e.getKey();
15728                 if(keyArray){
15729                     for(var i = 0, len = keyCode.length; i < len; i++){
15730                         if(keyCode[i] == k){
15731                           if(this.stopEvent){
15732                               e.stopEvent();
15733                           }
15734                           fn.call(scope || window, k, e);
15735                           return;
15736                         }
15737                     }
15738                 }else{
15739                     if(k == keyCode){
15740                         if(this.stopEvent){
15741                            e.stopEvent();
15742                         }
15743                         fn.call(scope || window, k, e);
15744                     }
15745                 }
15746             }
15747         };
15748         this.bindings.push(handler);  
15749         },
15750
15751     /**
15752      * Shorthand for adding a single key listener
15753      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15754      * following options:
15755      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15756      * @param {Function} fn The function to call
15757      * @param {Object} scope (optional) The scope of the function
15758      */
15759     on : function(key, fn, scope){
15760         var keyCode, shift, ctrl, alt;
15761         if(typeof key == "object" && !(key instanceof Array)){
15762             keyCode = key.key;
15763             shift = key.shift;
15764             ctrl = key.ctrl;
15765             alt = key.alt;
15766         }else{
15767             keyCode = key;
15768         }
15769         this.addBinding({
15770             key: keyCode,
15771             shift: shift,
15772             ctrl: ctrl,
15773             alt: alt,
15774             fn: fn,
15775             scope: scope
15776         })
15777     },
15778
15779     // private
15780     handleKeyDown : function(e){
15781             if(this.enabled){ //just in case
15782             var b = this.bindings;
15783             for(var i = 0, len = b.length; i < len; i++){
15784                 b[i].call(this, e);
15785             }
15786             }
15787         },
15788         
15789         /**
15790          * Returns true if this KeyMap is enabled
15791          * @return {Boolean} 
15792          */
15793         isEnabled : function(){
15794             return this.enabled;  
15795         },
15796         
15797         /**
15798          * Enables this KeyMap
15799          */
15800         enable: function(){
15801                 if(!this.enabled){
15802                     this.el.on(this.eventName, this.handleKeyDown, this);
15803                     this.enabled = true;
15804                 }
15805         },
15806
15807         /**
15808          * Disable this KeyMap
15809          */
15810         disable: function(){
15811                 if(this.enabled){
15812                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15813                     this.enabled = false;
15814                 }
15815         }
15816 };/*
15817  * Based on:
15818  * Ext JS Library 1.1.1
15819  * Copyright(c) 2006-2007, Ext JS, LLC.
15820  *
15821  * Originally Released Under LGPL - original licence link has changed is not relivant.
15822  *
15823  * Fork - LGPL
15824  * <script type="text/javascript">
15825  */
15826
15827  
15828 /**
15829  * @class Roo.util.TextMetrics
15830  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15831  * wide, in pixels, a given block of text will be.
15832  * @static
15833  */
15834 Roo.util.TextMetrics = function(){
15835     var shared;
15836     return {
15837         /**
15838          * Measures the size of the specified text
15839          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15840          * that can affect the size of the rendered text
15841          * @param {String} text The text to measure
15842          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15843          * in order to accurately measure the text height
15844          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15845          */
15846         measure : function(el, text, fixedWidth){
15847             if(!shared){
15848                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15849             }
15850             shared.bind(el);
15851             shared.setFixedWidth(fixedWidth || 'auto');
15852             return shared.getSize(text);
15853         },
15854
15855         /**
15856          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15857          * the overhead of multiple calls to initialize the style properties on each measurement.
15858          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15859          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15860          * in order to accurately measure the text height
15861          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15862          */
15863         createInstance : function(el, fixedWidth){
15864             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15865         }
15866     };
15867 }();
15868
15869 /**
15870  * @class Roo.util.TextMetrics.Instance
15871  * Instance of  TextMetrics Calcuation
15872  * @constructor
15873  * Create a new TextMetrics Instance
15874  * @param {Object} bindto
15875  * @param {Boolean} fixedWidth
15876  */
15877
15878 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15879 {
15880     var ml = new Roo.Element(document.createElement('div'));
15881     document.body.appendChild(ml.dom);
15882     ml.position('absolute');
15883     ml.setLeftTop(-1000, -1000);
15884     ml.hide();
15885
15886     if(fixedWidth){
15887         ml.setWidth(fixedWidth);
15888     }
15889      
15890     var instance = {
15891         /**
15892          * Returns the size of the specified text based on the internal element's style and width properties
15893          * @param {String} text The text to measure
15894          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15895          */
15896         getSize : function(text){
15897             ml.update(text);
15898             var s = ml.getSize();
15899             ml.update('');
15900             return s;
15901         },
15902
15903         /**
15904          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15905          * that can affect the size of the rendered text
15906          * @param {String/HTMLElement} el The element, dom node or id
15907          */
15908         bind : function(el){
15909             ml.setStyle(
15910                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15911             );
15912         },
15913
15914         /**
15915          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15916          * to set a fixed width in order to accurately measure the text height.
15917          * @param {Number} width The width to set on the element
15918          */
15919         setFixedWidth : function(width){
15920             ml.setWidth(width);
15921         },
15922
15923         /**
15924          * Returns the measured width of the specified text
15925          * @param {String} text The text to measure
15926          * @return {Number} width The width in pixels
15927          */
15928         getWidth : function(text){
15929             ml.dom.style.width = 'auto';
15930             return this.getSize(text).width;
15931         },
15932
15933         /**
15934          * Returns the measured height of the specified text.  For multiline text, be sure to call
15935          * {@link #setFixedWidth} if necessary.
15936          * @param {String} text The text to measure
15937          * @return {Number} height The height in pixels
15938          */
15939         getHeight : function(text){
15940             return this.getSize(text).height;
15941         }
15942     };
15943
15944     instance.bind(bindTo);
15945
15946     return instance;
15947 };
15948
15949 // backwards compat
15950 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15951  * Based on:
15952  * Ext JS Library 1.1.1
15953  * Copyright(c) 2006-2007, Ext JS, LLC.
15954  *
15955  * Originally Released Under LGPL - original licence link has changed is not relivant.
15956  *
15957  * Fork - LGPL
15958  * <script type="text/javascript">
15959  */
15960
15961 /**
15962  * @class Roo.state.Provider
15963  * Abstract base class for state provider implementations. This class provides methods
15964  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15965  * Provider interface.
15966  */
15967 Roo.state.Provider = function(){
15968     /**
15969      * @event statechange
15970      * Fires when a state change occurs.
15971      * @param {Provider} this This state provider
15972      * @param {String} key The state key which was changed
15973      * @param {String} value The encoded value for the state
15974      */
15975     this.addEvents({
15976         "statechange": true
15977     });
15978     this.state = {};
15979     Roo.state.Provider.superclass.constructor.call(this);
15980 };
15981 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15982     /**
15983      * Returns the current value for a key
15984      * @param {String} name The key name
15985      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15986      * @return {Mixed} The state data
15987      */
15988     get : function(name, defaultValue){
15989         return typeof this.state[name] == "undefined" ?
15990             defaultValue : this.state[name];
15991     },
15992     
15993     /**
15994      * Clears a value from the state
15995      * @param {String} name The key name
15996      */
15997     clear : function(name){
15998         delete this.state[name];
15999         this.fireEvent("statechange", this, name, null);
16000     },
16001     
16002     /**
16003      * Sets the value for a key
16004      * @param {String} name The key name
16005      * @param {Mixed} value The value to set
16006      */
16007     set : function(name, value){
16008         this.state[name] = value;
16009         this.fireEvent("statechange", this, name, value);
16010     },
16011     
16012     /**
16013      * Decodes a string previously encoded with {@link #encodeValue}.
16014      * @param {String} value The value to decode
16015      * @return {Mixed} The decoded value
16016      */
16017     decodeValue : function(cookie){
16018         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16019         var matches = re.exec(unescape(cookie));
16020         if(!matches || !matches[1]) {
16021             return; // non state cookie
16022         }
16023         var type = matches[1];
16024         var v = matches[2];
16025         switch(type){
16026             case "n":
16027                 return parseFloat(v);
16028             case "d":
16029                 return new Date(Date.parse(v));
16030             case "b":
16031                 return (v == "1");
16032             case "a":
16033                 var all = [];
16034                 var values = v.split("^");
16035                 for(var i = 0, len = values.length; i < len; i++){
16036                     all.push(this.decodeValue(values[i]));
16037                 }
16038                 return all;
16039            case "o":
16040                 var all = {};
16041                 var values = v.split("^");
16042                 for(var i = 0, len = values.length; i < len; i++){
16043                     var kv = values[i].split("=");
16044                     all[kv[0]] = this.decodeValue(kv[1]);
16045                 }
16046                 return all;
16047            default:
16048                 return v;
16049         }
16050     },
16051     
16052     /**
16053      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16054      * @param {Mixed} value The value to encode
16055      * @return {String} The encoded value
16056      */
16057     encodeValue : function(v){
16058         var enc;
16059         if(typeof v == "number"){
16060             enc = "n:" + v;
16061         }else if(typeof v == "boolean"){
16062             enc = "b:" + (v ? "1" : "0");
16063         }else if(v instanceof Date){
16064             enc = "d:" + v.toGMTString();
16065         }else if(v instanceof Array){
16066             var flat = "";
16067             for(var i = 0, len = v.length; i < len; i++){
16068                 flat += this.encodeValue(v[i]);
16069                 if(i != len-1) {
16070                     flat += "^";
16071                 }
16072             }
16073             enc = "a:" + flat;
16074         }else if(typeof v == "object"){
16075             var flat = "";
16076             for(var key in v){
16077                 if(typeof v[key] != "function"){
16078                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16079                 }
16080             }
16081             enc = "o:" + flat.substring(0, flat.length-1);
16082         }else{
16083             enc = "s:" + v;
16084         }
16085         return escape(enc);        
16086     }
16087 });
16088
16089 /*
16090  * Based on:
16091  * Ext JS Library 1.1.1
16092  * Copyright(c) 2006-2007, Ext JS, LLC.
16093  *
16094  * Originally Released Under LGPL - original licence link has changed is not relivant.
16095  *
16096  * Fork - LGPL
16097  * <script type="text/javascript">
16098  */
16099 /**
16100  * @class Roo.state.Manager
16101  * This is the global state manager. By default all components that are "state aware" check this class
16102  * for state information if you don't pass them a custom state provider. In order for this class
16103  * to be useful, it must be initialized with a provider when your application initializes.
16104  <pre><code>
16105 // in your initialization function
16106 init : function(){
16107    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16108    ...
16109    // supposed you have a {@link Roo.BorderLayout}
16110    var layout = new Roo.BorderLayout(...);
16111    layout.restoreState();
16112    // or a {Roo.BasicDialog}
16113    var dialog = new Roo.BasicDialog(...);
16114    dialog.restoreState();
16115  </code></pre>
16116  * @static
16117  */
16118 Roo.state.Manager = function(){
16119     var provider = new Roo.state.Provider();
16120     
16121     return {
16122         /**
16123          * Configures the default state provider for your application
16124          * @param {Provider} stateProvider The state provider to set
16125          */
16126         setProvider : function(stateProvider){
16127             provider = stateProvider;
16128         },
16129         
16130         /**
16131          * Returns the current value for a key
16132          * @param {String} name The key name
16133          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16134          * @return {Mixed} The state data
16135          */
16136         get : function(key, defaultValue){
16137             return provider.get(key, defaultValue);
16138         },
16139         
16140         /**
16141          * Sets the value for a key
16142          * @param {String} name The key name
16143          * @param {Mixed} value The state data
16144          */
16145          set : function(key, value){
16146             provider.set(key, value);
16147         },
16148         
16149         /**
16150          * Clears a value from the state
16151          * @param {String} name The key name
16152          */
16153         clear : function(key){
16154             provider.clear(key);
16155         },
16156         
16157         /**
16158          * Gets the currently configured state provider
16159          * @return {Provider} The state provider
16160          */
16161         getProvider : function(){
16162             return provider;
16163         }
16164     };
16165 }();
16166 /*
16167  * Based on:
16168  * Ext JS Library 1.1.1
16169  * Copyright(c) 2006-2007, Ext JS, LLC.
16170  *
16171  * Originally Released Under LGPL - original licence link has changed is not relivant.
16172  *
16173  * Fork - LGPL
16174  * <script type="text/javascript">
16175  */
16176 /**
16177  * @class Roo.state.CookieProvider
16178  * @extends Roo.state.Provider
16179  * The default Provider implementation which saves state via cookies.
16180  * <br />Usage:
16181  <pre><code>
16182    var cp = new Roo.state.CookieProvider({
16183        path: "/cgi-bin/",
16184        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16185        domain: "roojs.com"
16186    })
16187    Roo.state.Manager.setProvider(cp);
16188  </code></pre>
16189  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16190  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16191  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16192  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16193  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16194  * domain the page is running on including the 'www' like 'www.roojs.com')
16195  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16196  * @constructor
16197  * Create a new CookieProvider
16198  * @param {Object} config The configuration object
16199  */
16200 Roo.state.CookieProvider = function(config){
16201     Roo.state.CookieProvider.superclass.constructor.call(this);
16202     this.path = "/";
16203     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16204     this.domain = null;
16205     this.secure = false;
16206     Roo.apply(this, config);
16207     this.state = this.readCookies();
16208 };
16209
16210 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16211     // private
16212     set : function(name, value){
16213         if(typeof value == "undefined" || value === null){
16214             this.clear(name);
16215             return;
16216         }
16217         this.setCookie(name, value);
16218         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16219     },
16220
16221     // private
16222     clear : function(name){
16223         this.clearCookie(name);
16224         Roo.state.CookieProvider.superclass.clear.call(this, name);
16225     },
16226
16227     // private
16228     readCookies : function(){
16229         var cookies = {};
16230         var c = document.cookie + ";";
16231         var re = /\s?(.*?)=(.*?);/g;
16232         var matches;
16233         while((matches = re.exec(c)) != null){
16234             var name = matches[1];
16235             var value = matches[2];
16236             if(name && name.substring(0,3) == "ys-"){
16237                 cookies[name.substr(3)] = this.decodeValue(value);
16238             }
16239         }
16240         return cookies;
16241     },
16242
16243     // private
16244     setCookie : function(name, value){
16245         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16246            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16247            ((this.path == null) ? "" : ("; path=" + this.path)) +
16248            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16249            ((this.secure == true) ? "; secure" : "");
16250     },
16251
16252     // private
16253     clearCookie : function(name){
16254         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16255            ((this.path == null) ? "" : ("; path=" + this.path)) +
16256            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16257            ((this.secure == true) ? "; secure" : "");
16258     }
16259 });/*
16260  * Based on:
16261  * Ext JS Library 1.1.1
16262  * Copyright(c) 2006-2007, Ext JS, LLC.
16263  *
16264  * Originally Released Under LGPL - original licence link has changed is not relivant.
16265  *
16266  * Fork - LGPL
16267  * <script type="text/javascript">
16268  */
16269  
16270
16271 /**
16272  * @class Roo.ComponentMgr
16273  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16274  * @static
16275  */
16276 Roo.ComponentMgr = function(){
16277     var all = new Roo.util.MixedCollection();
16278
16279     return {
16280         /**
16281          * Registers a component.
16282          * @param {Roo.Component} c The component
16283          */
16284         register : function(c){
16285             all.add(c);
16286         },
16287
16288         /**
16289          * Unregisters a component.
16290          * @param {Roo.Component} c The component
16291          */
16292         unregister : function(c){
16293             all.remove(c);
16294         },
16295
16296         /**
16297          * Returns a component by id
16298          * @param {String} id The component id
16299          */
16300         get : function(id){
16301             return all.get(id);
16302         },
16303
16304         /**
16305          * Registers a function that will be called when a specified component is added to ComponentMgr
16306          * @param {String} id The component id
16307          * @param {Funtction} fn The callback function
16308          * @param {Object} scope The scope of the callback
16309          */
16310         onAvailable : function(id, fn, scope){
16311             all.on("add", function(index, o){
16312                 if(o.id == id){
16313                     fn.call(scope || o, o);
16314                     all.un("add", fn, scope);
16315                 }
16316             });
16317         }
16318     };
16319 }();/*
16320  * Based on:
16321  * Ext JS Library 1.1.1
16322  * Copyright(c) 2006-2007, Ext JS, LLC.
16323  *
16324  * Originally Released Under LGPL - original licence link has changed is not relivant.
16325  *
16326  * Fork - LGPL
16327  * <script type="text/javascript">
16328  */
16329  
16330 /**
16331  * @class Roo.Component
16332  * @extends Roo.util.Observable
16333  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16334  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16335  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16336  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16337  * All visual components (widgets) that require rendering into a layout should subclass Component.
16338  * @constructor
16339  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16340  * 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
16341  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16342  */
16343 Roo.Component = function(config){
16344     config = config || {};
16345     if(config.tagName || config.dom || typeof config == "string"){ // element object
16346         config = {el: config, id: config.id || config};
16347     }
16348     this.initialConfig = config;
16349
16350     Roo.apply(this, config);
16351     this.addEvents({
16352         /**
16353          * @event disable
16354          * Fires after the component is disabled.
16355              * @param {Roo.Component} this
16356              */
16357         disable : true,
16358         /**
16359          * @event enable
16360          * Fires after the component is enabled.
16361              * @param {Roo.Component} this
16362              */
16363         enable : true,
16364         /**
16365          * @event beforeshow
16366          * Fires before the component is shown.  Return false to stop the show.
16367              * @param {Roo.Component} this
16368              */
16369         beforeshow : true,
16370         /**
16371          * @event show
16372          * Fires after the component is shown.
16373              * @param {Roo.Component} this
16374              */
16375         show : true,
16376         /**
16377          * @event beforehide
16378          * Fires before the component is hidden. Return false to stop the hide.
16379              * @param {Roo.Component} this
16380              */
16381         beforehide : true,
16382         /**
16383          * @event hide
16384          * Fires after the component is hidden.
16385              * @param {Roo.Component} this
16386              */
16387         hide : true,
16388         /**
16389          * @event beforerender
16390          * Fires before the component is rendered. Return false to stop the render.
16391              * @param {Roo.Component} this
16392              */
16393         beforerender : true,
16394         /**
16395          * @event render
16396          * Fires after the component is rendered.
16397              * @param {Roo.Component} this
16398              */
16399         render : true,
16400         /**
16401          * @event beforedestroy
16402          * Fires before the component is destroyed. Return false to stop the destroy.
16403              * @param {Roo.Component} this
16404              */
16405         beforedestroy : true,
16406         /**
16407          * @event destroy
16408          * Fires after the component is destroyed.
16409              * @param {Roo.Component} this
16410              */
16411         destroy : true
16412     });
16413     if(!this.id){
16414         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16415     }
16416     Roo.ComponentMgr.register(this);
16417     Roo.Component.superclass.constructor.call(this);
16418     this.initComponent();
16419     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16420         this.render(this.renderTo);
16421         delete this.renderTo;
16422     }
16423 };
16424
16425 /** @private */
16426 Roo.Component.AUTO_ID = 1000;
16427
16428 Roo.extend(Roo.Component, Roo.util.Observable, {
16429     /**
16430      * @scope Roo.Component.prototype
16431      * @type {Boolean}
16432      * true if this component is hidden. Read-only.
16433      */
16434     hidden : false,
16435     /**
16436      * @type {Boolean}
16437      * true if this component is disabled. Read-only.
16438      */
16439     disabled : false,
16440     /**
16441      * @type {Boolean}
16442      * true if this component has been rendered. Read-only.
16443      */
16444     rendered : false,
16445     
16446     /** @cfg {String} disableClass
16447      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16448      */
16449     disabledClass : "x-item-disabled",
16450         /** @cfg {Boolean} allowDomMove
16451          * Whether the component can move the Dom node when rendering (defaults to true).
16452          */
16453     allowDomMove : true,
16454     /** @cfg {String} hideMode (display|visibility)
16455      * How this component should hidden. Supported values are
16456      * "visibility" (css visibility), "offsets" (negative offset position) and
16457      * "display" (css display) - defaults to "display".
16458      */
16459     hideMode: 'display',
16460
16461     /** @private */
16462     ctype : "Roo.Component",
16463
16464     /**
16465      * @cfg {String} actionMode 
16466      * which property holds the element that used for  hide() / show() / disable() / enable()
16467      * default is 'el' for forms you probably want to set this to fieldEl 
16468      */
16469     actionMode : "el",
16470
16471     /** @private */
16472     getActionEl : function(){
16473         return this[this.actionMode];
16474     },
16475
16476     initComponent : Roo.emptyFn,
16477     /**
16478      * If this is a lazy rendering component, render it to its container element.
16479      * @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.
16480      */
16481     render : function(container, position){
16482         
16483         if(this.rendered){
16484             return this;
16485         }
16486         
16487         if(this.fireEvent("beforerender", this) === false){
16488             return false;
16489         }
16490         
16491         if(!container && this.el){
16492             this.el = Roo.get(this.el);
16493             container = this.el.dom.parentNode;
16494             this.allowDomMove = false;
16495         }
16496         this.container = Roo.get(container);
16497         this.rendered = true;
16498         if(position !== undefined){
16499             if(typeof position == 'number'){
16500                 position = this.container.dom.childNodes[position];
16501             }else{
16502                 position = Roo.getDom(position);
16503             }
16504         }
16505         this.onRender(this.container, position || null);
16506         if(this.cls){
16507             this.el.addClass(this.cls);
16508             delete this.cls;
16509         }
16510         if(this.style){
16511             this.el.applyStyles(this.style);
16512             delete this.style;
16513         }
16514         this.fireEvent("render", this);
16515         this.afterRender(this.container);
16516         if(this.hidden){
16517             this.hide();
16518         }
16519         if(this.disabled){
16520             this.disable();
16521         }
16522
16523         return this;
16524         
16525     },
16526
16527     /** @private */
16528     // default function is not really useful
16529     onRender : function(ct, position){
16530         if(this.el){
16531             this.el = Roo.get(this.el);
16532             if(this.allowDomMove !== false){
16533                 ct.dom.insertBefore(this.el.dom, position);
16534             }
16535         }
16536     },
16537
16538     /** @private */
16539     getAutoCreate : function(){
16540         var cfg = typeof this.autoCreate == "object" ?
16541                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16542         if(this.id && !cfg.id){
16543             cfg.id = this.id;
16544         }
16545         return cfg;
16546     },
16547
16548     /** @private */
16549     afterRender : Roo.emptyFn,
16550
16551     /**
16552      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16553      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16554      */
16555     destroy : function(){
16556         if(this.fireEvent("beforedestroy", this) !== false){
16557             this.purgeListeners();
16558             this.beforeDestroy();
16559             if(this.rendered){
16560                 this.el.removeAllListeners();
16561                 this.el.remove();
16562                 if(this.actionMode == "container"){
16563                     this.container.remove();
16564                 }
16565             }
16566             this.onDestroy();
16567             Roo.ComponentMgr.unregister(this);
16568             this.fireEvent("destroy", this);
16569         }
16570     },
16571
16572         /** @private */
16573     beforeDestroy : function(){
16574
16575     },
16576
16577         /** @private */
16578         onDestroy : function(){
16579
16580     },
16581
16582     /**
16583      * Returns the underlying {@link Roo.Element}.
16584      * @return {Roo.Element} The element
16585      */
16586     getEl : function(){
16587         return this.el;
16588     },
16589
16590     /**
16591      * Returns the id of this component.
16592      * @return {String}
16593      */
16594     getId : function(){
16595         return this.id;
16596     },
16597
16598     /**
16599      * Try to focus this component.
16600      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16601      * @return {Roo.Component} this
16602      */
16603     focus : function(selectText){
16604         if(this.rendered){
16605             this.el.focus();
16606             if(selectText === true){
16607                 this.el.dom.select();
16608             }
16609         }
16610         return this;
16611     },
16612
16613     /** @private */
16614     blur : function(){
16615         if(this.rendered){
16616             this.el.blur();
16617         }
16618         return this;
16619     },
16620
16621     /**
16622      * Disable this component.
16623      * @return {Roo.Component} this
16624      */
16625     disable : function(){
16626         if(this.rendered){
16627             this.onDisable();
16628         }
16629         this.disabled = true;
16630         this.fireEvent("disable", this);
16631         return this;
16632     },
16633
16634         // private
16635     onDisable : function(){
16636         this.getActionEl().addClass(this.disabledClass);
16637         this.el.dom.disabled = true;
16638     },
16639
16640     /**
16641      * Enable this component.
16642      * @return {Roo.Component} this
16643      */
16644     enable : function(){
16645         if(this.rendered){
16646             this.onEnable();
16647         }
16648         this.disabled = false;
16649         this.fireEvent("enable", this);
16650         return this;
16651     },
16652
16653         // private
16654     onEnable : function(){
16655         this.getActionEl().removeClass(this.disabledClass);
16656         this.el.dom.disabled = false;
16657     },
16658
16659     /**
16660      * Convenience function for setting disabled/enabled by boolean.
16661      * @param {Boolean} disabled
16662      */
16663     setDisabled : function(disabled){
16664         this[disabled ? "disable" : "enable"]();
16665     },
16666
16667     /**
16668      * Show this component.
16669      * @return {Roo.Component} this
16670      */
16671     show: function(){
16672         if(this.fireEvent("beforeshow", this) !== false){
16673             this.hidden = false;
16674             if(this.rendered){
16675                 this.onShow();
16676             }
16677             this.fireEvent("show", this);
16678         }
16679         return this;
16680     },
16681
16682     // private
16683     onShow : function(){
16684         var ae = this.getActionEl();
16685         if(this.hideMode == 'visibility'){
16686             ae.dom.style.visibility = "visible";
16687         }else if(this.hideMode == 'offsets'){
16688             ae.removeClass('x-hidden');
16689         }else{
16690             ae.dom.style.display = "";
16691         }
16692     },
16693
16694     /**
16695      * Hide this component.
16696      * @return {Roo.Component} this
16697      */
16698     hide: function(){
16699         if(this.fireEvent("beforehide", this) !== false){
16700             this.hidden = true;
16701             if(this.rendered){
16702                 this.onHide();
16703             }
16704             this.fireEvent("hide", this);
16705         }
16706         return this;
16707     },
16708
16709     // private
16710     onHide : function(){
16711         var ae = this.getActionEl();
16712         if(this.hideMode == 'visibility'){
16713             ae.dom.style.visibility = "hidden";
16714         }else if(this.hideMode == 'offsets'){
16715             ae.addClass('x-hidden');
16716         }else{
16717             ae.dom.style.display = "none";
16718         }
16719     },
16720
16721     /**
16722      * Convenience function to hide or show this component by boolean.
16723      * @param {Boolean} visible True to show, false to hide
16724      * @return {Roo.Component} this
16725      */
16726     setVisible: function(visible){
16727         if(visible) {
16728             this.show();
16729         }else{
16730             this.hide();
16731         }
16732         return this;
16733     },
16734
16735     /**
16736      * Returns true if this component is visible.
16737      */
16738     isVisible : function(){
16739         return this.getActionEl().isVisible();
16740     },
16741
16742     cloneConfig : function(overrides){
16743         overrides = overrides || {};
16744         var id = overrides.id || Roo.id();
16745         var cfg = Roo.applyIf(overrides, this.initialConfig);
16746         cfg.id = id; // prevent dup id
16747         return new this.constructor(cfg);
16748     }
16749 });/*
16750  * Based on:
16751  * Ext JS Library 1.1.1
16752  * Copyright(c) 2006-2007, Ext JS, LLC.
16753  *
16754  * Originally Released Under LGPL - original licence link has changed is not relivant.
16755  *
16756  * Fork - LGPL
16757  * <script type="text/javascript">
16758  */
16759
16760 /**
16761  * @class Roo.BoxComponent
16762  * @extends Roo.Component
16763  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16764  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16765  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16766  * layout containers.
16767  * @constructor
16768  * @param {Roo.Element/String/Object} config The configuration options.
16769  */
16770 Roo.BoxComponent = function(config){
16771     Roo.Component.call(this, config);
16772     this.addEvents({
16773         /**
16774          * @event resize
16775          * Fires after the component is resized.
16776              * @param {Roo.Component} this
16777              * @param {Number} adjWidth The box-adjusted width that was set
16778              * @param {Number} adjHeight The box-adjusted height that was set
16779              * @param {Number} rawWidth The width that was originally specified
16780              * @param {Number} rawHeight The height that was originally specified
16781              */
16782         resize : true,
16783         /**
16784          * @event move
16785          * Fires after the component is moved.
16786              * @param {Roo.Component} this
16787              * @param {Number} x The new x position
16788              * @param {Number} y The new y position
16789              */
16790         move : true
16791     });
16792 };
16793
16794 Roo.extend(Roo.BoxComponent, Roo.Component, {
16795     // private, set in afterRender to signify that the component has been rendered
16796     boxReady : false,
16797     // private, used to defer height settings to subclasses
16798     deferHeight: false,
16799     /** @cfg {Number} width
16800      * width (optional) size of component
16801      */
16802      /** @cfg {Number} height
16803      * height (optional) size of component
16804      */
16805      
16806     /**
16807      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16808      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16809      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16810      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16811      * @return {Roo.BoxComponent} this
16812      */
16813     setSize : function(w, h){
16814         // support for standard size objects
16815         if(typeof w == 'object'){
16816             h = w.height;
16817             w = w.width;
16818         }
16819         // not rendered
16820         if(!this.boxReady){
16821             this.width = w;
16822             this.height = h;
16823             return this;
16824         }
16825
16826         // prevent recalcs when not needed
16827         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16828             return this;
16829         }
16830         this.lastSize = {width: w, height: h};
16831
16832         var adj = this.adjustSize(w, h);
16833         var aw = adj.width, ah = adj.height;
16834         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16835             var rz = this.getResizeEl();
16836             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16837                 rz.setSize(aw, ah);
16838             }else if(!this.deferHeight && ah !== undefined){
16839                 rz.setHeight(ah);
16840             }else if(aw !== undefined){
16841                 rz.setWidth(aw);
16842             }
16843             this.onResize(aw, ah, w, h);
16844             this.fireEvent('resize', this, aw, ah, w, h);
16845         }
16846         return this;
16847     },
16848
16849     /**
16850      * Gets the current size of the component's underlying element.
16851      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16852      */
16853     getSize : function(){
16854         return this.el.getSize();
16855     },
16856
16857     /**
16858      * Gets the current XY position of the component's underlying element.
16859      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16860      * @return {Array} The XY position of the element (e.g., [100, 200])
16861      */
16862     getPosition : function(local){
16863         if(local === true){
16864             return [this.el.getLeft(true), this.el.getTop(true)];
16865         }
16866         return this.xy || this.el.getXY();
16867     },
16868
16869     /**
16870      * Gets the current box measurements of the component's underlying element.
16871      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16872      * @returns {Object} box An object in the format {x, y, width, height}
16873      */
16874     getBox : function(local){
16875         var s = this.el.getSize();
16876         if(local){
16877             s.x = this.el.getLeft(true);
16878             s.y = this.el.getTop(true);
16879         }else{
16880             var xy = this.xy || this.el.getXY();
16881             s.x = xy[0];
16882             s.y = xy[1];
16883         }
16884         return s;
16885     },
16886
16887     /**
16888      * Sets the current box measurements of the component's underlying element.
16889      * @param {Object} box An object in the format {x, y, width, height}
16890      * @returns {Roo.BoxComponent} this
16891      */
16892     updateBox : function(box){
16893         this.setSize(box.width, box.height);
16894         this.setPagePosition(box.x, box.y);
16895         return this;
16896     },
16897
16898     // protected
16899     getResizeEl : function(){
16900         return this.resizeEl || this.el;
16901     },
16902
16903     // protected
16904     getPositionEl : function(){
16905         return this.positionEl || this.el;
16906     },
16907
16908     /**
16909      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16910      * This method fires the move event.
16911      * @param {Number} left The new left
16912      * @param {Number} top The new top
16913      * @returns {Roo.BoxComponent} this
16914      */
16915     setPosition : function(x, y){
16916         this.x = x;
16917         this.y = y;
16918         if(!this.boxReady){
16919             return this;
16920         }
16921         var adj = this.adjustPosition(x, y);
16922         var ax = adj.x, ay = adj.y;
16923
16924         var el = this.getPositionEl();
16925         if(ax !== undefined || ay !== undefined){
16926             if(ax !== undefined && ay !== undefined){
16927                 el.setLeftTop(ax, ay);
16928             }else if(ax !== undefined){
16929                 el.setLeft(ax);
16930             }else if(ay !== undefined){
16931                 el.setTop(ay);
16932             }
16933             this.onPosition(ax, ay);
16934             this.fireEvent('move', this, ax, ay);
16935         }
16936         return this;
16937     },
16938
16939     /**
16940      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16941      * This method fires the move event.
16942      * @param {Number} x The new x position
16943      * @param {Number} y The new y position
16944      * @returns {Roo.BoxComponent} this
16945      */
16946     setPagePosition : function(x, y){
16947         this.pageX = x;
16948         this.pageY = y;
16949         if(!this.boxReady){
16950             return;
16951         }
16952         if(x === undefined || y === undefined){ // cannot translate undefined points
16953             return;
16954         }
16955         var p = this.el.translatePoints(x, y);
16956         this.setPosition(p.left, p.top);
16957         return this;
16958     },
16959
16960     // private
16961     onRender : function(ct, position){
16962         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16963         if(this.resizeEl){
16964             this.resizeEl = Roo.get(this.resizeEl);
16965         }
16966         if(this.positionEl){
16967             this.positionEl = Roo.get(this.positionEl);
16968         }
16969     },
16970
16971     // private
16972     afterRender : function(){
16973         Roo.BoxComponent.superclass.afterRender.call(this);
16974         this.boxReady = true;
16975         this.setSize(this.width, this.height);
16976         if(this.x || this.y){
16977             this.setPosition(this.x, this.y);
16978         }
16979         if(this.pageX || this.pageY){
16980             this.setPagePosition(this.pageX, this.pageY);
16981         }
16982     },
16983
16984     /**
16985      * Force the component's size to recalculate based on the underlying element's current height and width.
16986      * @returns {Roo.BoxComponent} this
16987      */
16988     syncSize : function(){
16989         delete this.lastSize;
16990         this.setSize(this.el.getWidth(), this.el.getHeight());
16991         return this;
16992     },
16993
16994     /**
16995      * Called after the component is resized, this method is empty by default but can be implemented by any
16996      * subclass that needs to perform custom logic after a resize occurs.
16997      * @param {Number} adjWidth The box-adjusted width that was set
16998      * @param {Number} adjHeight The box-adjusted height that was set
16999      * @param {Number} rawWidth The width that was originally specified
17000      * @param {Number} rawHeight The height that was originally specified
17001      */
17002     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17003
17004     },
17005
17006     /**
17007      * Called after the component is moved, this method is empty by default but can be implemented by any
17008      * subclass that needs to perform custom logic after a move occurs.
17009      * @param {Number} x The new x position
17010      * @param {Number} y The new y position
17011      */
17012     onPosition : function(x, y){
17013
17014     },
17015
17016     // private
17017     adjustSize : function(w, h){
17018         if(this.autoWidth){
17019             w = 'auto';
17020         }
17021         if(this.autoHeight){
17022             h = 'auto';
17023         }
17024         return {width : w, height: h};
17025     },
17026
17027     // private
17028     adjustPosition : function(x, y){
17029         return {x : x, y: y};
17030     }
17031 });/*
17032  * Based on:
17033  * Ext JS Library 1.1.1
17034  * Copyright(c) 2006-2007, Ext JS, LLC.
17035  *
17036  * Originally Released Under LGPL - original licence link has changed is not relivant.
17037  *
17038  * Fork - LGPL
17039  * <script type="text/javascript">
17040  */
17041  (function(){ 
17042 /**
17043  * @class Roo.Layer
17044  * @extends Roo.Element
17045  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17046  * automatic maintaining of shadow/shim positions.
17047  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17048  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17049  * you can pass a string with a CSS class name. False turns off the shadow.
17050  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17051  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17052  * @cfg {String} cls CSS class to add to the element
17053  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17054  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17055  * @constructor
17056  * @param {Object} config An object with config options.
17057  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17058  */
17059
17060 Roo.Layer = function(config, existingEl){
17061     config = config || {};
17062     var dh = Roo.DomHelper;
17063     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17064     if(existingEl){
17065         this.dom = Roo.getDom(existingEl);
17066     }
17067     if(!this.dom){
17068         var o = config.dh || {tag: "div", cls: "x-layer"};
17069         this.dom = dh.append(pel, o);
17070     }
17071     if(config.cls){
17072         this.addClass(config.cls);
17073     }
17074     this.constrain = config.constrain !== false;
17075     this.visibilityMode = Roo.Element.VISIBILITY;
17076     if(config.id){
17077         this.id = this.dom.id = config.id;
17078     }else{
17079         this.id = Roo.id(this.dom);
17080     }
17081     this.zindex = config.zindex || this.getZIndex();
17082     this.position("absolute", this.zindex);
17083     if(config.shadow){
17084         this.shadowOffset = config.shadowOffset || 4;
17085         this.shadow = new Roo.Shadow({
17086             offset : this.shadowOffset,
17087             mode : config.shadow
17088         });
17089     }else{
17090         this.shadowOffset = 0;
17091     }
17092     this.useShim = config.shim !== false && Roo.useShims;
17093     this.useDisplay = config.useDisplay;
17094     this.hide();
17095 };
17096
17097 var supr = Roo.Element.prototype;
17098
17099 // shims are shared among layer to keep from having 100 iframes
17100 var shims = [];
17101
17102 Roo.extend(Roo.Layer, Roo.Element, {
17103
17104     getZIndex : function(){
17105         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17106     },
17107
17108     getShim : function(){
17109         if(!this.useShim){
17110             return null;
17111         }
17112         if(this.shim){
17113             return this.shim;
17114         }
17115         var shim = shims.shift();
17116         if(!shim){
17117             shim = this.createShim();
17118             shim.enableDisplayMode('block');
17119             shim.dom.style.display = 'none';
17120             shim.dom.style.visibility = 'visible';
17121         }
17122         var pn = this.dom.parentNode;
17123         if(shim.dom.parentNode != pn){
17124             pn.insertBefore(shim.dom, this.dom);
17125         }
17126         shim.setStyle('z-index', this.getZIndex()-2);
17127         this.shim = shim;
17128         return shim;
17129     },
17130
17131     hideShim : function(){
17132         if(this.shim){
17133             this.shim.setDisplayed(false);
17134             shims.push(this.shim);
17135             delete this.shim;
17136         }
17137     },
17138
17139     disableShadow : function(){
17140         if(this.shadow){
17141             this.shadowDisabled = true;
17142             this.shadow.hide();
17143             this.lastShadowOffset = this.shadowOffset;
17144             this.shadowOffset = 0;
17145         }
17146     },
17147
17148     enableShadow : function(show){
17149         if(this.shadow){
17150             this.shadowDisabled = false;
17151             this.shadowOffset = this.lastShadowOffset;
17152             delete this.lastShadowOffset;
17153             if(show){
17154                 this.sync(true);
17155             }
17156         }
17157     },
17158
17159     // private
17160     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17161     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17162     sync : function(doShow){
17163         var sw = this.shadow;
17164         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17165             var sh = this.getShim();
17166
17167             var w = this.getWidth(),
17168                 h = this.getHeight();
17169
17170             var l = this.getLeft(true),
17171                 t = this.getTop(true);
17172
17173             if(sw && !this.shadowDisabled){
17174                 if(doShow && !sw.isVisible()){
17175                     sw.show(this);
17176                 }else{
17177                     sw.realign(l, t, w, h);
17178                 }
17179                 if(sh){
17180                     if(doShow){
17181                        sh.show();
17182                     }
17183                     // fit the shim behind the shadow, so it is shimmed too
17184                     var a = sw.adjusts, s = sh.dom.style;
17185                     s.left = (Math.min(l, l+a.l))+"px";
17186                     s.top = (Math.min(t, t+a.t))+"px";
17187                     s.width = (w+a.w)+"px";
17188                     s.height = (h+a.h)+"px";
17189                 }
17190             }else if(sh){
17191                 if(doShow){
17192                    sh.show();
17193                 }
17194                 sh.setSize(w, h);
17195                 sh.setLeftTop(l, t);
17196             }
17197             
17198         }
17199     },
17200
17201     // private
17202     destroy : function(){
17203         this.hideShim();
17204         if(this.shadow){
17205             this.shadow.hide();
17206         }
17207         this.removeAllListeners();
17208         var pn = this.dom.parentNode;
17209         if(pn){
17210             pn.removeChild(this.dom);
17211         }
17212         Roo.Element.uncache(this.id);
17213     },
17214
17215     remove : function(){
17216         this.destroy();
17217     },
17218
17219     // private
17220     beginUpdate : function(){
17221         this.updating = true;
17222     },
17223
17224     // private
17225     endUpdate : function(){
17226         this.updating = false;
17227         this.sync(true);
17228     },
17229
17230     // private
17231     hideUnders : function(negOffset){
17232         if(this.shadow){
17233             this.shadow.hide();
17234         }
17235         this.hideShim();
17236     },
17237
17238     // private
17239     constrainXY : function(){
17240         if(this.constrain){
17241             var vw = Roo.lib.Dom.getViewWidth(),
17242                 vh = Roo.lib.Dom.getViewHeight();
17243             var s = Roo.get(document).getScroll();
17244
17245             var xy = this.getXY();
17246             var x = xy[0], y = xy[1];   
17247             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17248             // only move it if it needs it
17249             var moved = false;
17250             // first validate right/bottom
17251             if((x + w) > vw+s.left){
17252                 x = vw - w - this.shadowOffset;
17253                 moved = true;
17254             }
17255             if((y + h) > vh+s.top){
17256                 y = vh - h - this.shadowOffset;
17257                 moved = true;
17258             }
17259             // then make sure top/left isn't negative
17260             if(x < s.left){
17261                 x = s.left;
17262                 moved = true;
17263             }
17264             if(y < s.top){
17265                 y = s.top;
17266                 moved = true;
17267             }
17268             if(moved){
17269                 if(this.avoidY){
17270                     var ay = this.avoidY;
17271                     if(y <= ay && (y+h) >= ay){
17272                         y = ay-h-5;   
17273                     }
17274                 }
17275                 xy = [x, y];
17276                 this.storeXY(xy);
17277                 supr.setXY.call(this, xy);
17278                 this.sync();
17279             }
17280         }
17281     },
17282
17283     isVisible : function(){
17284         return this.visible;    
17285     },
17286
17287     // private
17288     showAction : function(){
17289         this.visible = true; // track visibility to prevent getStyle calls
17290         if(this.useDisplay === true){
17291             this.setDisplayed("");
17292         }else if(this.lastXY){
17293             supr.setXY.call(this, this.lastXY);
17294         }else if(this.lastLT){
17295             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17296         }
17297     },
17298
17299     // private
17300     hideAction : function(){
17301         this.visible = false;
17302         if(this.useDisplay === true){
17303             this.setDisplayed(false);
17304         }else{
17305             this.setLeftTop(-10000,-10000);
17306         }
17307     },
17308
17309     // overridden Element method
17310     setVisible : function(v, a, d, c, e){
17311         if(v){
17312             this.showAction();
17313         }
17314         if(a && v){
17315             var cb = function(){
17316                 this.sync(true);
17317                 if(c){
17318                     c();
17319                 }
17320             }.createDelegate(this);
17321             supr.setVisible.call(this, true, true, d, cb, e);
17322         }else{
17323             if(!v){
17324                 this.hideUnders(true);
17325             }
17326             var cb = c;
17327             if(a){
17328                 cb = function(){
17329                     this.hideAction();
17330                     if(c){
17331                         c();
17332                     }
17333                 }.createDelegate(this);
17334             }
17335             supr.setVisible.call(this, v, a, d, cb, e);
17336             if(v){
17337                 this.sync(true);
17338             }else if(!a){
17339                 this.hideAction();
17340             }
17341         }
17342     },
17343
17344     storeXY : function(xy){
17345         delete this.lastLT;
17346         this.lastXY = xy;
17347     },
17348
17349     storeLeftTop : function(left, top){
17350         delete this.lastXY;
17351         this.lastLT = [left, top];
17352     },
17353
17354     // private
17355     beforeFx : function(){
17356         this.beforeAction();
17357         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17358     },
17359
17360     // private
17361     afterFx : function(){
17362         Roo.Layer.superclass.afterFx.apply(this, arguments);
17363         this.sync(this.isVisible());
17364     },
17365
17366     // private
17367     beforeAction : function(){
17368         if(!this.updating && this.shadow){
17369             this.shadow.hide();
17370         }
17371     },
17372
17373     // overridden Element method
17374     setLeft : function(left){
17375         this.storeLeftTop(left, this.getTop(true));
17376         supr.setLeft.apply(this, arguments);
17377         this.sync();
17378     },
17379
17380     setTop : function(top){
17381         this.storeLeftTop(this.getLeft(true), top);
17382         supr.setTop.apply(this, arguments);
17383         this.sync();
17384     },
17385
17386     setLeftTop : function(left, top){
17387         this.storeLeftTop(left, top);
17388         supr.setLeftTop.apply(this, arguments);
17389         this.sync();
17390     },
17391
17392     setXY : function(xy, a, d, c, e){
17393         this.fixDisplay();
17394         this.beforeAction();
17395         this.storeXY(xy);
17396         var cb = this.createCB(c);
17397         supr.setXY.call(this, xy, a, d, cb, e);
17398         if(!a){
17399             cb();
17400         }
17401     },
17402
17403     // private
17404     createCB : function(c){
17405         var el = this;
17406         return function(){
17407             el.constrainXY();
17408             el.sync(true);
17409             if(c){
17410                 c();
17411             }
17412         };
17413     },
17414
17415     // overridden Element method
17416     setX : function(x, a, d, c, e){
17417         this.setXY([x, this.getY()], a, d, c, e);
17418     },
17419
17420     // overridden Element method
17421     setY : function(y, a, d, c, e){
17422         this.setXY([this.getX(), y], a, d, c, e);
17423     },
17424
17425     // overridden Element method
17426     setSize : function(w, h, a, d, c, e){
17427         this.beforeAction();
17428         var cb = this.createCB(c);
17429         supr.setSize.call(this, w, h, a, d, cb, e);
17430         if(!a){
17431             cb();
17432         }
17433     },
17434
17435     // overridden Element method
17436     setWidth : function(w, a, d, c, e){
17437         this.beforeAction();
17438         var cb = this.createCB(c);
17439         supr.setWidth.call(this, w, a, d, cb, e);
17440         if(!a){
17441             cb();
17442         }
17443     },
17444
17445     // overridden Element method
17446     setHeight : function(h, a, d, c, e){
17447         this.beforeAction();
17448         var cb = this.createCB(c);
17449         supr.setHeight.call(this, h, a, d, cb, e);
17450         if(!a){
17451             cb();
17452         }
17453     },
17454
17455     // overridden Element method
17456     setBounds : function(x, y, w, h, a, d, c, e){
17457         this.beforeAction();
17458         var cb = this.createCB(c);
17459         if(!a){
17460             this.storeXY([x, y]);
17461             supr.setXY.call(this, [x, y]);
17462             supr.setSize.call(this, w, h, a, d, cb, e);
17463             cb();
17464         }else{
17465             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17466         }
17467         return this;
17468     },
17469     
17470     /**
17471      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17472      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17473      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17474      * @param {Number} zindex The new z-index to set
17475      * @return {this} The Layer
17476      */
17477     setZIndex : function(zindex){
17478         this.zindex = zindex;
17479         this.setStyle("z-index", zindex + 2);
17480         if(this.shadow){
17481             this.shadow.setZIndex(zindex + 1);
17482         }
17483         if(this.shim){
17484             this.shim.setStyle("z-index", zindex);
17485         }
17486     }
17487 });
17488 })();/*
17489  * Original code for Roojs - LGPL
17490  * <script type="text/javascript">
17491  */
17492  
17493 /**
17494  * @class Roo.XComponent
17495  * A delayed Element creator...
17496  * Or a way to group chunks of interface together.
17497  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17498  *  used in conjunction with XComponent.build() it will create an instance of each element,
17499  *  then call addxtype() to build the User interface.
17500  * 
17501  * Mypart.xyx = new Roo.XComponent({
17502
17503     parent : 'Mypart.xyz', // empty == document.element.!!
17504     order : '001',
17505     name : 'xxxx'
17506     region : 'xxxx'
17507     disabled : function() {} 
17508      
17509     tree : function() { // return an tree of xtype declared components
17510         var MODULE = this;
17511         return 
17512         {
17513             xtype : 'NestedLayoutPanel',
17514             // technicall
17515         }
17516      ]
17517  *})
17518  *
17519  *
17520  * It can be used to build a big heiracy, with parent etc.
17521  * or you can just use this to render a single compoent to a dom element
17522  * MYPART.render(Roo.Element | String(id) | dom_element )
17523  *
17524  *
17525  * Usage patterns.
17526  *
17527  * Classic Roo
17528  *
17529  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17530  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17531  *
17532  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17533  *
17534  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17535  * - if mulitple topModules exist, the last one is defined as the top module.
17536  *
17537  * Embeded Roo
17538  * 
17539  * When the top level or multiple modules are to embedded into a existing HTML page,
17540  * the parent element can container '#id' of the element where the module will be drawn.
17541  *
17542  * Bootstrap Roo
17543  *
17544  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17545  * it relies more on a include mechanism, where sub modules are included into an outer page.
17546  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17547  * 
17548  * Bootstrap Roo Included elements
17549  *
17550  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17551  * hence confusing the component builder as it thinks there are multiple top level elements. 
17552  *
17553  * String Over-ride & Translations
17554  *
17555  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17556  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17557  * are needed. @see Roo.XComponent.overlayString  
17558  * 
17559  * 
17560  * 
17561  * @extends Roo.util.Observable
17562  * @constructor
17563  * @param cfg {Object} configuration of component
17564  * 
17565  */
17566 Roo.XComponent = function(cfg) {
17567     Roo.apply(this, cfg);
17568     this.addEvents({ 
17569         /**
17570              * @event built
17571              * Fires when this the componnt is built
17572              * @param {Roo.XComponent} c the component
17573              */
17574         'built' : true
17575         
17576     });
17577     this.region = this.region || 'center'; // default..
17578     Roo.XComponent.register(this);
17579     this.modules = false;
17580     this.el = false; // where the layout goes..
17581     
17582     
17583 }
17584 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17585     /**
17586      * @property el
17587      * The created element (with Roo.factory())
17588      * @type {Roo.Layout}
17589      */
17590     el  : false,
17591     
17592     /**
17593      * @property el
17594      * for BC  - use el in new code
17595      * @type {Roo.Layout}
17596      */
17597     panel : false,
17598     
17599     /**
17600      * @property layout
17601      * for BC  - use el in new code
17602      * @type {Roo.Layout}
17603      */
17604     layout : false,
17605     
17606      /**
17607      * @cfg {Function|boolean} disabled
17608      * If this module is disabled by some rule, return true from the funtion
17609      */
17610     disabled : false,
17611     
17612     /**
17613      * @cfg {String} parent 
17614      * Name of parent element which it get xtype added to..
17615      */
17616     parent: false,
17617     
17618     /**
17619      * @cfg {String} order
17620      * Used to set the order in which elements are created (usefull for multiple tabs)
17621      */
17622     
17623     order : false,
17624     /**
17625      * @cfg {String} name
17626      * String to display while loading.
17627      */
17628     name : false,
17629     /**
17630      * @cfg {String} region
17631      * Region to render component to (defaults to center)
17632      */
17633     region : 'center',
17634     
17635     /**
17636      * @cfg {Array} items
17637      * A single item array - the first element is the root of the tree..
17638      * It's done this way to stay compatible with the Xtype system...
17639      */
17640     items : false,
17641     
17642     /**
17643      * @property _tree
17644      * The method that retuns the tree of parts that make up this compoennt 
17645      * @type {function}
17646      */
17647     _tree  : false,
17648     
17649      /**
17650      * render
17651      * render element to dom or tree
17652      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17653      */
17654     
17655     render : function(el)
17656     {
17657         
17658         el = el || false;
17659         var hp = this.parent ? 1 : 0;
17660         Roo.debug &&  Roo.log(this);
17661         
17662         var tree = this._tree ? this._tree() : this.tree();
17663
17664         
17665         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17666             // if parent is a '#.....' string, then let's use that..
17667             var ename = this.parent.substr(1);
17668             this.parent = false;
17669             Roo.debug && Roo.log(ename);
17670             switch (ename) {
17671                 case 'bootstrap-body':
17672                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17673                         // this is the BorderLayout standard?
17674                        this.parent = { el : true };
17675                        break;
17676                     }
17677                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17678                         // need to insert stuff...
17679                         this.parent =  {
17680                              el : new Roo.bootstrap.layout.Border({
17681                                  el : document.body, 
17682                      
17683                                  center: {
17684                                     titlebar: false,
17685                                     autoScroll:false,
17686                                     closeOnTab: true,
17687                                     tabPosition: 'top',
17688                                       //resizeTabs: true,
17689                                     alwaysShowTabs: true,
17690                                     hideTabs: false
17691                                      //minTabWidth: 140
17692                                  }
17693                              })
17694                         
17695                          };
17696                          break;
17697                     }
17698                          
17699                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17700                         this.parent = { el :  new  Roo.bootstrap.Body() };
17701                         Roo.debug && Roo.log("setting el to doc body");
17702                          
17703                     } else {
17704                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17705                     }
17706                     break;
17707                 case 'bootstrap':
17708                     this.parent = { el : true};
17709                     // fall through
17710                 default:
17711                     el = Roo.get(ename);
17712                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17713                         this.parent = { el : true};
17714                     }
17715                     
17716                     break;
17717             }
17718                 
17719             
17720             if (!el && !this.parent) {
17721                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17722                 return;
17723             }
17724         }
17725         
17726         Roo.debug && Roo.log("EL:");
17727         Roo.debug && Roo.log(el);
17728         Roo.debug && Roo.log("this.parent.el:");
17729         Roo.debug && Roo.log(this.parent.el);
17730         
17731
17732         // altertive root elements ??? - we need a better way to indicate these.
17733         var is_alt = Roo.XComponent.is_alt ||
17734                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17735                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17736                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17737         
17738         
17739         
17740         if (!this.parent && is_alt) {
17741             //el = Roo.get(document.body);
17742             this.parent = { el : true };
17743         }
17744             
17745             
17746         
17747         if (!this.parent) {
17748             
17749             Roo.debug && Roo.log("no parent - creating one");
17750             
17751             el = el ? Roo.get(el) : false;      
17752             
17753             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17754                 
17755                 this.parent =  {
17756                     el : new Roo.bootstrap.layout.Border({
17757                         el: el || document.body,
17758                     
17759                         center: {
17760                             titlebar: false,
17761                             autoScroll:false,
17762                             closeOnTab: true,
17763                             tabPosition: 'top',
17764                              //resizeTabs: true,
17765                             alwaysShowTabs: false,
17766                             hideTabs: true,
17767                             minTabWidth: 140,
17768                             overflow: 'visible'
17769                          }
17770                      })
17771                 };
17772             } else {
17773             
17774                 // it's a top level one..
17775                 this.parent =  {
17776                     el : new Roo.BorderLayout(el || document.body, {
17777                         center: {
17778                             titlebar: false,
17779                             autoScroll:false,
17780                             closeOnTab: true,
17781                             tabPosition: 'top',
17782                              //resizeTabs: true,
17783                             alwaysShowTabs: el && hp? false :  true,
17784                             hideTabs: el || !hp ? true :  false,
17785                             minTabWidth: 140
17786                          }
17787                     })
17788                 };
17789             }
17790         }
17791         
17792         if (!this.parent.el) {
17793                 // probably an old style ctor, which has been disabled.
17794                 return;
17795
17796         }
17797                 // The 'tree' method is  '_tree now' 
17798             
17799         tree.region = tree.region || this.region;
17800         var is_body = false;
17801         if (this.parent.el === true) {
17802             // bootstrap... - body..
17803             if (el) {
17804                 tree.el = el;
17805             }
17806             this.parent.el = Roo.factory(tree);
17807             is_body = true;
17808         }
17809         
17810         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17811         this.fireEvent('built', this);
17812         
17813         this.panel = this.el;
17814         this.layout = this.panel.layout;
17815         this.parentLayout = this.parent.layout  || false;  
17816          
17817     }
17818     
17819 });
17820
17821 Roo.apply(Roo.XComponent, {
17822     /**
17823      * @property  hideProgress
17824      * true to disable the building progress bar.. usefull on single page renders.
17825      * @type Boolean
17826      */
17827     hideProgress : false,
17828     /**
17829      * @property  buildCompleted
17830      * True when the builder has completed building the interface.
17831      * @type Boolean
17832      */
17833     buildCompleted : false,
17834      
17835     /**
17836      * @property  topModule
17837      * the upper most module - uses document.element as it's constructor.
17838      * @type Object
17839      */
17840      
17841     topModule  : false,
17842       
17843     /**
17844      * @property  modules
17845      * array of modules to be created by registration system.
17846      * @type {Array} of Roo.XComponent
17847      */
17848     
17849     modules : [],
17850     /**
17851      * @property  elmodules
17852      * array of modules to be created by which use #ID 
17853      * @type {Array} of Roo.XComponent
17854      */
17855      
17856     elmodules : [],
17857
17858      /**
17859      * @property  is_alt
17860      * Is an alternative Root - normally used by bootstrap or other systems,
17861      *    where the top element in the tree can wrap 'body' 
17862      * @type {boolean}  (default false)
17863      */
17864      
17865     is_alt : false,
17866     /**
17867      * @property  build_from_html
17868      * Build elements from html - used by bootstrap HTML stuff 
17869      *    - this is cleared after build is completed
17870      * @type {boolean}    (default false)
17871      */
17872      
17873     build_from_html : false,
17874     /**
17875      * Register components to be built later.
17876      *
17877      * This solves the following issues
17878      * - Building is not done on page load, but after an authentication process has occured.
17879      * - Interface elements are registered on page load
17880      * - Parent Interface elements may not be loaded before child, so this handles that..
17881      * 
17882      *
17883      * example:
17884      * 
17885      * MyApp.register({
17886           order : '000001',
17887           module : 'Pman.Tab.projectMgr',
17888           region : 'center',
17889           parent : 'Pman.layout',
17890           disabled : false,  // or use a function..
17891         })
17892      
17893      * * @param {Object} details about module
17894      */
17895     register : function(obj) {
17896                 
17897         Roo.XComponent.event.fireEvent('register', obj);
17898         switch(typeof(obj.disabled) ) {
17899                 
17900             case 'undefined':
17901                 break;
17902             
17903             case 'function':
17904                 if ( obj.disabled() ) {
17905                         return;
17906                 }
17907                 break;
17908             
17909             default:
17910                 if (obj.disabled || obj.region == '#disabled') {
17911                         return;
17912                 }
17913                 break;
17914         }
17915                 
17916         this.modules.push(obj);
17917          
17918     },
17919     /**
17920      * convert a string to an object..
17921      * eg. 'AAA.BBB' -> finds AAA.BBB
17922
17923      */
17924     
17925     toObject : function(str)
17926     {
17927         if (!str || typeof(str) == 'object') {
17928             return str;
17929         }
17930         if (str.substring(0,1) == '#') {
17931             return str;
17932         }
17933
17934         var ar = str.split('.');
17935         var rt, o;
17936         rt = ar.shift();
17937             /** eval:var:o */
17938         try {
17939             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17940         } catch (e) {
17941             throw "Module not found : " + str;
17942         }
17943         
17944         if (o === false) {
17945             throw "Module not found : " + str;
17946         }
17947         Roo.each(ar, function(e) {
17948             if (typeof(o[e]) == 'undefined') {
17949                 throw "Module not found : " + str;
17950             }
17951             o = o[e];
17952         });
17953         
17954         return o;
17955         
17956     },
17957     
17958     
17959     /**
17960      * move modules into their correct place in the tree..
17961      * 
17962      */
17963     preBuild : function ()
17964     {
17965         var _t = this;
17966         Roo.each(this.modules , function (obj)
17967         {
17968             Roo.XComponent.event.fireEvent('beforebuild', obj);
17969             
17970             var opar = obj.parent;
17971             try { 
17972                 obj.parent = this.toObject(opar);
17973             } catch(e) {
17974                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17975                 return;
17976             }
17977             
17978             if (!obj.parent) {
17979                 Roo.debug && Roo.log("GOT top level module");
17980                 Roo.debug && Roo.log(obj);
17981                 obj.modules = new Roo.util.MixedCollection(false, 
17982                     function(o) { return o.order + '' }
17983                 );
17984                 this.topModule = obj;
17985                 return;
17986             }
17987                         // parent is a string (usually a dom element name..)
17988             if (typeof(obj.parent) == 'string') {
17989                 this.elmodules.push(obj);
17990                 return;
17991             }
17992             if (obj.parent.constructor != Roo.XComponent) {
17993                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17994             }
17995             if (!obj.parent.modules) {
17996                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17997                     function(o) { return o.order + '' }
17998                 );
17999             }
18000             if (obj.parent.disabled) {
18001                 obj.disabled = true;
18002             }
18003             obj.parent.modules.add(obj);
18004         }, this);
18005     },
18006     
18007      /**
18008      * make a list of modules to build.
18009      * @return {Array} list of modules. 
18010      */ 
18011     
18012     buildOrder : function()
18013     {
18014         var _this = this;
18015         var cmp = function(a,b) {   
18016             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18017         };
18018         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18019             throw "No top level modules to build";
18020         }
18021         
18022         // make a flat list in order of modules to build.
18023         var mods = this.topModule ? [ this.topModule ] : [];
18024                 
18025         
18026         // elmodules (is a list of DOM based modules )
18027         Roo.each(this.elmodules, function(e) {
18028             mods.push(e);
18029             if (!this.topModule &&
18030                 typeof(e.parent) == 'string' &&
18031                 e.parent.substring(0,1) == '#' &&
18032                 Roo.get(e.parent.substr(1))
18033                ) {
18034                 
18035                 _this.topModule = e;
18036             }
18037             
18038         });
18039
18040         
18041         // add modules to their parents..
18042         var addMod = function(m) {
18043             Roo.debug && Roo.log("build Order: add: " + m.name);
18044                 
18045             mods.push(m);
18046             if (m.modules && !m.disabled) {
18047                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18048                 m.modules.keySort('ASC',  cmp );
18049                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18050     
18051                 m.modules.each(addMod);
18052             } else {
18053                 Roo.debug && Roo.log("build Order: no child modules");
18054             }
18055             // not sure if this is used any more..
18056             if (m.finalize) {
18057                 m.finalize.name = m.name + " (clean up) ";
18058                 mods.push(m.finalize);
18059             }
18060             
18061         }
18062         if (this.topModule && this.topModule.modules) { 
18063             this.topModule.modules.keySort('ASC',  cmp );
18064             this.topModule.modules.each(addMod);
18065         } 
18066         return mods;
18067     },
18068     
18069      /**
18070      * Build the registered modules.
18071      * @param {Object} parent element.
18072      * @param {Function} optional method to call after module has been added.
18073      * 
18074      */ 
18075    
18076     build : function(opts) 
18077     {
18078         
18079         if (typeof(opts) != 'undefined') {
18080             Roo.apply(this,opts);
18081         }
18082         
18083         this.preBuild();
18084         var mods = this.buildOrder();
18085       
18086         //this.allmods = mods;
18087         //Roo.debug && Roo.log(mods);
18088         //return;
18089         if (!mods.length) { // should not happen
18090             throw "NO modules!!!";
18091         }
18092         
18093         
18094         var msg = "Building Interface...";
18095         // flash it up as modal - so we store the mask!?
18096         if (!this.hideProgress && Roo.MessageBox) {
18097             Roo.MessageBox.show({ title: 'loading' });
18098             Roo.MessageBox.show({
18099                title: "Please wait...",
18100                msg: msg,
18101                width:450,
18102                progress:true,
18103                buttons : false,
18104                closable:false,
18105                modal: false
18106               
18107             });
18108         }
18109         var total = mods.length;
18110         
18111         var _this = this;
18112         var progressRun = function() {
18113             if (!mods.length) {
18114                 Roo.debug && Roo.log('hide?');
18115                 if (!this.hideProgress && Roo.MessageBox) {
18116                     Roo.MessageBox.hide();
18117                 }
18118                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18119                 
18120                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18121                 
18122                 // THE END...
18123                 return false;   
18124             }
18125             
18126             var m = mods.shift();
18127             
18128             
18129             Roo.debug && Roo.log(m);
18130             // not sure if this is supported any more.. - modules that are are just function
18131             if (typeof(m) == 'function') { 
18132                 m.call(this);
18133                 return progressRun.defer(10, _this);
18134             } 
18135             
18136             
18137             msg = "Building Interface " + (total  - mods.length) + 
18138                     " of " + total + 
18139                     (m.name ? (' - ' + m.name) : '');
18140                         Roo.debug && Roo.log(msg);
18141             if (!_this.hideProgress &&  Roo.MessageBox) { 
18142                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18143             }
18144             
18145          
18146             // is the module disabled?
18147             var disabled = (typeof(m.disabled) == 'function') ?
18148                 m.disabled.call(m.module.disabled) : m.disabled;    
18149             
18150             
18151             if (disabled) {
18152                 return progressRun(); // we do not update the display!
18153             }
18154             
18155             // now build 
18156             
18157                         
18158                         
18159             m.render();
18160             // it's 10 on top level, and 1 on others??? why...
18161             return progressRun.defer(10, _this);
18162              
18163         }
18164         progressRun.defer(1, _this);
18165      
18166         
18167         
18168     },
18169     /**
18170      * Overlay a set of modified strings onto a component
18171      * This is dependant on our builder exporting the strings and 'named strings' elements.
18172      * 
18173      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18174      * @param {Object} associative array of 'named' string and it's new value.
18175      * 
18176      */
18177         overlayStrings : function( component, strings )
18178     {
18179         if (typeof(component['_named_strings']) == 'undefined') {
18180             throw "ERROR: component does not have _named_strings";
18181         }
18182         for ( var k in strings ) {
18183             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18184             if (md !== false) {
18185                 component['_strings'][md] = strings[k];
18186             } else {
18187                 Roo.log('could not find named string: ' + k + ' in');
18188                 Roo.log(component);
18189             }
18190             
18191         }
18192         
18193     },
18194     
18195         
18196         /**
18197          * Event Object.
18198          *
18199          *
18200          */
18201         event: false, 
18202     /**
18203          * wrapper for event.on - aliased later..  
18204          * Typically use to register a event handler for register:
18205          *
18206          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18207          *
18208          */
18209     on : false
18210    
18211     
18212     
18213 });
18214
18215 Roo.XComponent.event = new Roo.util.Observable({
18216                 events : { 
18217                         /**
18218                          * @event register
18219                          * Fires when an Component is registered,
18220                          * set the disable property on the Component to stop registration.
18221                          * @param {Roo.XComponent} c the component being registerd.
18222                          * 
18223                          */
18224                         'register' : true,
18225             /**
18226                          * @event beforebuild
18227                          * Fires before each Component is built
18228                          * can be used to apply permissions.
18229                          * @param {Roo.XComponent} c the component being registerd.
18230                          * 
18231                          */
18232                         'beforebuild' : true,
18233                         /**
18234                          * @event buildcomplete
18235                          * Fires on the top level element when all elements have been built
18236                          * @param {Roo.XComponent} the top level component.
18237                          */
18238                         'buildcomplete' : true
18239                         
18240                 }
18241 });
18242
18243 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18244  //
18245  /**
18246  * marked - a markdown parser
18247  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18248  * https://github.com/chjj/marked
18249  */
18250
18251
18252 /**
18253  *
18254  * Roo.Markdown - is a very crude wrapper around marked..
18255  *
18256  * usage:
18257  * 
18258  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18259  * 
18260  * Note: move the sample code to the bottom of this
18261  * file before uncommenting it.
18262  *
18263  */
18264
18265 Roo.Markdown = {};
18266 Roo.Markdown.toHtml = function(text) {
18267     
18268     var c = new Roo.Markdown.marked.setOptions({
18269             renderer: new Roo.Markdown.marked.Renderer(),
18270             gfm: true,
18271             tables: true,
18272             breaks: false,
18273             pedantic: false,
18274             sanitize: false,
18275             smartLists: true,
18276             smartypants: false
18277           });
18278     // A FEW HACKS!!?
18279     
18280     text = text.replace(/\\\n/g,' ');
18281     return Roo.Markdown.marked(text);
18282 };
18283 //
18284 // converter
18285 //
18286 // Wraps all "globals" so that the only thing
18287 // exposed is makeHtml().
18288 //
18289 (function() {
18290     
18291      /**
18292          * eval:var:escape
18293          * eval:var:unescape
18294          * eval:var:replace
18295          */
18296       
18297     /**
18298      * Helpers
18299      */
18300     
18301     var escape = function (html, encode) {
18302       return html
18303         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18304         .replace(/</g, '&lt;')
18305         .replace(/>/g, '&gt;')
18306         .replace(/"/g, '&quot;')
18307         .replace(/'/g, '&#39;');
18308     }
18309     
18310     var unescape = function (html) {
18311         // explicitly match decimal, hex, and named HTML entities 
18312       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18313         n = n.toLowerCase();
18314         if (n === 'colon') { return ':'; }
18315         if (n.charAt(0) === '#') {
18316           return n.charAt(1) === 'x'
18317             ? String.fromCharCode(parseInt(n.substring(2), 16))
18318             : String.fromCharCode(+n.substring(1));
18319         }
18320         return '';
18321       });
18322     }
18323     
18324     var replace = function (regex, opt) {
18325       regex = regex.source;
18326       opt = opt || '';
18327       return function self(name, val) {
18328         if (!name) { return new RegExp(regex, opt); }
18329         val = val.source || val;
18330         val = val.replace(/(^|[^\[])\^/g, '$1');
18331         regex = regex.replace(name, val);
18332         return self;
18333       };
18334     }
18335
18336
18337          /**
18338          * eval:var:noop
18339     */
18340     var noop = function () {}
18341     noop.exec = noop;
18342     
18343          /**
18344          * eval:var:merge
18345     */
18346     var merge = function (obj) {
18347       var i = 1
18348         , target
18349         , key;
18350     
18351       for (; i < arguments.length; i++) {
18352         target = arguments[i];
18353         for (key in target) {
18354           if (Object.prototype.hasOwnProperty.call(target, key)) {
18355             obj[key] = target[key];
18356           }
18357         }
18358       }
18359     
18360       return obj;
18361     }
18362     
18363     
18364     /**
18365      * Block-Level Grammar
18366      */
18367     
18368     
18369     
18370     
18371     var block = {
18372       newline: /^\n+/,
18373       code: /^( {4}[^\n]+\n*)+/,
18374       fences: noop,
18375       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18376       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18377       nptable: noop,
18378       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18379       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18380       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18381       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18382       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18383       table: noop,
18384       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18385       text: /^[^\n]+/
18386     };
18387     
18388     block.bullet = /(?:[*+-]|\d+\.)/;
18389     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18390     block.item = replace(block.item, 'gm')
18391       (/bull/g, block.bullet)
18392       ();
18393     
18394     block.list = replace(block.list)
18395       (/bull/g, block.bullet)
18396       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18397       ('def', '\\n+(?=' + block.def.source + ')')
18398       ();
18399     
18400     block.blockquote = replace(block.blockquote)
18401       ('def', block.def)
18402       ();
18403     
18404     block._tag = '(?!(?:'
18405       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18406       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18407       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18408     
18409     block.html = replace(block.html)
18410       ('comment', /<!--[\s\S]*?-->/)
18411       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18412       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18413       (/tag/g, block._tag)
18414       ();
18415     
18416     block.paragraph = replace(block.paragraph)
18417       ('hr', block.hr)
18418       ('heading', block.heading)
18419       ('lheading', block.lheading)
18420       ('blockquote', block.blockquote)
18421       ('tag', '<' + block._tag)
18422       ('def', block.def)
18423       ();
18424     
18425     /**
18426      * Normal Block Grammar
18427      */
18428     
18429     block.normal = merge({}, block);
18430     
18431     /**
18432      * GFM Block Grammar
18433      */
18434     
18435     block.gfm = merge({}, block.normal, {
18436       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18437       paragraph: /^/,
18438       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18439     });
18440     
18441     block.gfm.paragraph = replace(block.paragraph)
18442       ('(?!', '(?!'
18443         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18444         + block.list.source.replace('\\1', '\\3') + '|')
18445       ();
18446     
18447     /**
18448      * GFM + Tables Block Grammar
18449      */
18450     
18451     block.tables = merge({}, block.gfm, {
18452       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18453       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18454     });
18455     
18456     /**
18457      * Block Lexer
18458      */
18459     
18460     var Lexer = function (options) {
18461       this.tokens = [];
18462       this.tokens.links = {};
18463       this.options = options || marked.defaults;
18464       this.rules = block.normal;
18465     
18466       if (this.options.gfm) {
18467         if (this.options.tables) {
18468           this.rules = block.tables;
18469         } else {
18470           this.rules = block.gfm;
18471         }
18472       }
18473     }
18474     
18475     /**
18476      * Expose Block Rules
18477      */
18478     
18479     Lexer.rules = block;
18480     
18481     /**
18482      * Static Lex Method
18483      */
18484     
18485     Lexer.lex = function(src, options) {
18486       var lexer = new Lexer(options);
18487       return lexer.lex(src);
18488     };
18489     
18490     /**
18491      * Preprocessing
18492      */
18493     
18494     Lexer.prototype.lex = function(src) {
18495       src = src
18496         .replace(/\r\n|\r/g, '\n')
18497         .replace(/\t/g, '    ')
18498         .replace(/\u00a0/g, ' ')
18499         .replace(/\u2424/g, '\n');
18500     
18501       return this.token(src, true);
18502     };
18503     
18504     /**
18505      * Lexing
18506      */
18507     
18508     Lexer.prototype.token = function(src, top, bq) {
18509       var src = src.replace(/^ +$/gm, '')
18510         , next
18511         , loose
18512         , cap
18513         , bull
18514         , b
18515         , item
18516         , space
18517         , i
18518         , l;
18519     
18520       while (src) {
18521         // newline
18522         if (cap = this.rules.newline.exec(src)) {
18523           src = src.substring(cap[0].length);
18524           if (cap[0].length > 1) {
18525             this.tokens.push({
18526               type: 'space'
18527             });
18528           }
18529         }
18530     
18531         // code
18532         if (cap = this.rules.code.exec(src)) {
18533           src = src.substring(cap[0].length);
18534           cap = cap[0].replace(/^ {4}/gm, '');
18535           this.tokens.push({
18536             type: 'code',
18537             text: !this.options.pedantic
18538               ? cap.replace(/\n+$/, '')
18539               : cap
18540           });
18541           continue;
18542         }
18543     
18544         // fences (gfm)
18545         if (cap = this.rules.fences.exec(src)) {
18546           src = src.substring(cap[0].length);
18547           this.tokens.push({
18548             type: 'code',
18549             lang: cap[2],
18550             text: cap[3] || ''
18551           });
18552           continue;
18553         }
18554     
18555         // heading
18556         if (cap = this.rules.heading.exec(src)) {
18557           src = src.substring(cap[0].length);
18558           this.tokens.push({
18559             type: 'heading',
18560             depth: cap[1].length,
18561             text: cap[2]
18562           });
18563           continue;
18564         }
18565     
18566         // table no leading pipe (gfm)
18567         if (top && (cap = this.rules.nptable.exec(src))) {
18568           src = src.substring(cap[0].length);
18569     
18570           item = {
18571             type: 'table',
18572             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18573             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18574             cells: cap[3].replace(/\n$/, '').split('\n')
18575           };
18576     
18577           for (i = 0; i < item.align.length; i++) {
18578             if (/^ *-+: *$/.test(item.align[i])) {
18579               item.align[i] = 'right';
18580             } else if (/^ *:-+: *$/.test(item.align[i])) {
18581               item.align[i] = 'center';
18582             } else if (/^ *:-+ *$/.test(item.align[i])) {
18583               item.align[i] = 'left';
18584             } else {
18585               item.align[i] = null;
18586             }
18587           }
18588     
18589           for (i = 0; i < item.cells.length; i++) {
18590             item.cells[i] = item.cells[i].split(/ *\| */);
18591           }
18592     
18593           this.tokens.push(item);
18594     
18595           continue;
18596         }
18597     
18598         // lheading
18599         if (cap = this.rules.lheading.exec(src)) {
18600           src = src.substring(cap[0].length);
18601           this.tokens.push({
18602             type: 'heading',
18603             depth: cap[2] === '=' ? 1 : 2,
18604             text: cap[1]
18605           });
18606           continue;
18607         }
18608     
18609         // hr
18610         if (cap = this.rules.hr.exec(src)) {
18611           src = src.substring(cap[0].length);
18612           this.tokens.push({
18613             type: 'hr'
18614           });
18615           continue;
18616         }
18617     
18618         // blockquote
18619         if (cap = this.rules.blockquote.exec(src)) {
18620           src = src.substring(cap[0].length);
18621     
18622           this.tokens.push({
18623             type: 'blockquote_start'
18624           });
18625     
18626           cap = cap[0].replace(/^ *> ?/gm, '');
18627     
18628           // Pass `top` to keep the current
18629           // "toplevel" state. This is exactly
18630           // how markdown.pl works.
18631           this.token(cap, top, true);
18632     
18633           this.tokens.push({
18634             type: 'blockquote_end'
18635           });
18636     
18637           continue;
18638         }
18639     
18640         // list
18641         if (cap = this.rules.list.exec(src)) {
18642           src = src.substring(cap[0].length);
18643           bull = cap[2];
18644     
18645           this.tokens.push({
18646             type: 'list_start',
18647             ordered: bull.length > 1
18648           });
18649     
18650           // Get each top-level item.
18651           cap = cap[0].match(this.rules.item);
18652     
18653           next = false;
18654           l = cap.length;
18655           i = 0;
18656     
18657           for (; i < l; i++) {
18658             item = cap[i];
18659     
18660             // Remove the list item's bullet
18661             // so it is seen as the next token.
18662             space = item.length;
18663             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18664     
18665             // Outdent whatever the
18666             // list item contains. Hacky.
18667             if (~item.indexOf('\n ')) {
18668               space -= item.length;
18669               item = !this.options.pedantic
18670                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18671                 : item.replace(/^ {1,4}/gm, '');
18672             }
18673     
18674             // Determine whether the next list item belongs here.
18675             // Backpedal if it does not belong in this list.
18676             if (this.options.smartLists && i !== l - 1) {
18677               b = block.bullet.exec(cap[i + 1])[0];
18678               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18679                 src = cap.slice(i + 1).join('\n') + src;
18680                 i = l - 1;
18681               }
18682             }
18683     
18684             // Determine whether item is loose or not.
18685             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18686             // for discount behavior.
18687             loose = next || /\n\n(?!\s*$)/.test(item);
18688             if (i !== l - 1) {
18689               next = item.charAt(item.length - 1) === '\n';
18690               if (!loose) { loose = next; }
18691             }
18692     
18693             this.tokens.push({
18694               type: loose
18695                 ? 'loose_item_start'
18696                 : 'list_item_start'
18697             });
18698     
18699             // Recurse.
18700             this.token(item, false, bq);
18701     
18702             this.tokens.push({
18703               type: 'list_item_end'
18704             });
18705           }
18706     
18707           this.tokens.push({
18708             type: 'list_end'
18709           });
18710     
18711           continue;
18712         }
18713     
18714         // html
18715         if (cap = this.rules.html.exec(src)) {
18716           src = src.substring(cap[0].length);
18717           this.tokens.push({
18718             type: this.options.sanitize
18719               ? 'paragraph'
18720               : 'html',
18721             pre: !this.options.sanitizer
18722               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18723             text: cap[0]
18724           });
18725           continue;
18726         }
18727     
18728         // def
18729         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18730           src = src.substring(cap[0].length);
18731           this.tokens.links[cap[1].toLowerCase()] = {
18732             href: cap[2],
18733             title: cap[3]
18734           };
18735           continue;
18736         }
18737     
18738         // table (gfm)
18739         if (top && (cap = this.rules.table.exec(src))) {
18740           src = src.substring(cap[0].length);
18741     
18742           item = {
18743             type: 'table',
18744             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18745             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18746             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18747           };
18748     
18749           for (i = 0; i < item.align.length; i++) {
18750             if (/^ *-+: *$/.test(item.align[i])) {
18751               item.align[i] = 'right';
18752             } else if (/^ *:-+: *$/.test(item.align[i])) {
18753               item.align[i] = 'center';
18754             } else if (/^ *:-+ *$/.test(item.align[i])) {
18755               item.align[i] = 'left';
18756             } else {
18757               item.align[i] = null;
18758             }
18759           }
18760     
18761           for (i = 0; i < item.cells.length; i++) {
18762             item.cells[i] = item.cells[i]
18763               .replace(/^ *\| *| *\| *$/g, '')
18764               .split(/ *\| */);
18765           }
18766     
18767           this.tokens.push(item);
18768     
18769           continue;
18770         }
18771     
18772         // top-level paragraph
18773         if (top && (cap = this.rules.paragraph.exec(src))) {
18774           src = src.substring(cap[0].length);
18775           this.tokens.push({
18776             type: 'paragraph',
18777             text: cap[1].charAt(cap[1].length - 1) === '\n'
18778               ? cap[1].slice(0, -1)
18779               : cap[1]
18780           });
18781           continue;
18782         }
18783     
18784         // text
18785         if (cap = this.rules.text.exec(src)) {
18786           // Top-level should never reach here.
18787           src = src.substring(cap[0].length);
18788           this.tokens.push({
18789             type: 'text',
18790             text: cap[0]
18791           });
18792           continue;
18793         }
18794     
18795         if (src) {
18796           throw new
18797             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18798         }
18799       }
18800     
18801       return this.tokens;
18802     };
18803     
18804     /**
18805      * Inline-Level Grammar
18806      */
18807     
18808     var inline = {
18809       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18810       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18811       url: noop,
18812       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18813       link: /^!?\[(inside)\]\(href\)/,
18814       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18815       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18816       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18817       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18818       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18819       br: /^ {2,}\n(?!\s*$)/,
18820       del: noop,
18821       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18822     };
18823     
18824     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18825     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18826     
18827     inline.link = replace(inline.link)
18828       ('inside', inline._inside)
18829       ('href', inline._href)
18830       ();
18831     
18832     inline.reflink = replace(inline.reflink)
18833       ('inside', inline._inside)
18834       ();
18835     
18836     /**
18837      * Normal Inline Grammar
18838      */
18839     
18840     inline.normal = merge({}, inline);
18841     
18842     /**
18843      * Pedantic Inline Grammar
18844      */
18845     
18846     inline.pedantic = merge({}, inline.normal, {
18847       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18848       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18849     });
18850     
18851     /**
18852      * GFM Inline Grammar
18853      */
18854     
18855     inline.gfm = merge({}, inline.normal, {
18856       escape: replace(inline.escape)('])', '~|])')(),
18857       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18858       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18859       text: replace(inline.text)
18860         (']|', '~]|')
18861         ('|', '|https?://|')
18862         ()
18863     });
18864     
18865     /**
18866      * GFM + Line Breaks Inline Grammar
18867      */
18868     
18869     inline.breaks = merge({}, inline.gfm, {
18870       br: replace(inline.br)('{2,}', '*')(),
18871       text: replace(inline.gfm.text)('{2,}', '*')()
18872     });
18873     
18874     /**
18875      * Inline Lexer & Compiler
18876      */
18877     
18878     var InlineLexer  = function (links, options) {
18879       this.options = options || marked.defaults;
18880       this.links = links;
18881       this.rules = inline.normal;
18882       this.renderer = this.options.renderer || new Renderer;
18883       this.renderer.options = this.options;
18884     
18885       if (!this.links) {
18886         throw new
18887           Error('Tokens array requires a `links` property.');
18888       }
18889     
18890       if (this.options.gfm) {
18891         if (this.options.breaks) {
18892           this.rules = inline.breaks;
18893         } else {
18894           this.rules = inline.gfm;
18895         }
18896       } else if (this.options.pedantic) {
18897         this.rules = inline.pedantic;
18898       }
18899     }
18900     
18901     /**
18902      * Expose Inline Rules
18903      */
18904     
18905     InlineLexer.rules = inline;
18906     
18907     /**
18908      * Static Lexing/Compiling Method
18909      */
18910     
18911     InlineLexer.output = function(src, links, options) {
18912       var inline = new InlineLexer(links, options);
18913       return inline.output(src);
18914     };
18915     
18916     /**
18917      * Lexing/Compiling
18918      */
18919     
18920     InlineLexer.prototype.output = function(src) {
18921       var out = ''
18922         , link
18923         , text
18924         , href
18925         , cap;
18926     
18927       while (src) {
18928         // escape
18929         if (cap = this.rules.escape.exec(src)) {
18930           src = src.substring(cap[0].length);
18931           out += cap[1];
18932           continue;
18933         }
18934     
18935         // autolink
18936         if (cap = this.rules.autolink.exec(src)) {
18937           src = src.substring(cap[0].length);
18938           if (cap[2] === '@') {
18939             text = cap[1].charAt(6) === ':'
18940               ? this.mangle(cap[1].substring(7))
18941               : this.mangle(cap[1]);
18942             href = this.mangle('mailto:') + text;
18943           } else {
18944             text = escape(cap[1]);
18945             href = text;
18946           }
18947           out += this.renderer.link(href, null, text);
18948           continue;
18949         }
18950     
18951         // url (gfm)
18952         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18953           src = src.substring(cap[0].length);
18954           text = escape(cap[1]);
18955           href = text;
18956           out += this.renderer.link(href, null, text);
18957           continue;
18958         }
18959     
18960         // tag
18961         if (cap = this.rules.tag.exec(src)) {
18962           if (!this.inLink && /^<a /i.test(cap[0])) {
18963             this.inLink = true;
18964           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18965             this.inLink = false;
18966           }
18967           src = src.substring(cap[0].length);
18968           out += this.options.sanitize
18969             ? this.options.sanitizer
18970               ? this.options.sanitizer(cap[0])
18971               : escape(cap[0])
18972             : cap[0];
18973           continue;
18974         }
18975     
18976         // link
18977         if (cap = this.rules.link.exec(src)) {
18978           src = src.substring(cap[0].length);
18979           this.inLink = true;
18980           out += this.outputLink(cap, {
18981             href: cap[2],
18982             title: cap[3]
18983           });
18984           this.inLink = false;
18985           continue;
18986         }
18987     
18988         // reflink, nolink
18989         if ((cap = this.rules.reflink.exec(src))
18990             || (cap = this.rules.nolink.exec(src))) {
18991           src = src.substring(cap[0].length);
18992           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18993           link = this.links[link.toLowerCase()];
18994           if (!link || !link.href) {
18995             out += cap[0].charAt(0);
18996             src = cap[0].substring(1) + src;
18997             continue;
18998           }
18999           this.inLink = true;
19000           out += this.outputLink(cap, link);
19001           this.inLink = false;
19002           continue;
19003         }
19004     
19005         // strong
19006         if (cap = this.rules.strong.exec(src)) {
19007           src = src.substring(cap[0].length);
19008           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19009           continue;
19010         }
19011     
19012         // em
19013         if (cap = this.rules.em.exec(src)) {
19014           src = src.substring(cap[0].length);
19015           out += this.renderer.em(this.output(cap[2] || cap[1]));
19016           continue;
19017         }
19018     
19019         // code
19020         if (cap = this.rules.code.exec(src)) {
19021           src = src.substring(cap[0].length);
19022           out += this.renderer.codespan(escape(cap[2], true));
19023           continue;
19024         }
19025     
19026         // br
19027         if (cap = this.rules.br.exec(src)) {
19028           src = src.substring(cap[0].length);
19029           out += this.renderer.br();
19030           continue;
19031         }
19032     
19033         // del (gfm)
19034         if (cap = this.rules.del.exec(src)) {
19035           src = src.substring(cap[0].length);
19036           out += this.renderer.del(this.output(cap[1]));
19037           continue;
19038         }
19039     
19040         // text
19041         if (cap = this.rules.text.exec(src)) {
19042           src = src.substring(cap[0].length);
19043           out += this.renderer.text(escape(this.smartypants(cap[0])));
19044           continue;
19045         }
19046     
19047         if (src) {
19048           throw new
19049             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19050         }
19051       }
19052     
19053       return out;
19054     };
19055     
19056     /**
19057      * Compile Link
19058      */
19059     
19060     InlineLexer.prototype.outputLink = function(cap, link) {
19061       var href = escape(link.href)
19062         , title = link.title ? escape(link.title) : null;
19063     
19064       return cap[0].charAt(0) !== '!'
19065         ? this.renderer.link(href, title, this.output(cap[1]))
19066         : this.renderer.image(href, title, escape(cap[1]));
19067     };
19068     
19069     /**
19070      * Smartypants Transformations
19071      */
19072     
19073     InlineLexer.prototype.smartypants = function(text) {
19074       if (!this.options.smartypants)  { return text; }
19075       return text
19076         // em-dashes
19077         .replace(/---/g, '\u2014')
19078         // en-dashes
19079         .replace(/--/g, '\u2013')
19080         // opening singles
19081         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19082         // closing singles & apostrophes
19083         .replace(/'/g, '\u2019')
19084         // opening doubles
19085         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19086         // closing doubles
19087         .replace(/"/g, '\u201d')
19088         // ellipses
19089         .replace(/\.{3}/g, '\u2026');
19090     };
19091     
19092     /**
19093      * Mangle Links
19094      */
19095     
19096     InlineLexer.prototype.mangle = function(text) {
19097       if (!this.options.mangle) { return text; }
19098       var out = ''
19099         , l = text.length
19100         , i = 0
19101         , ch;
19102     
19103       for (; i < l; i++) {
19104         ch = text.charCodeAt(i);
19105         if (Math.random() > 0.5) {
19106           ch = 'x' + ch.toString(16);
19107         }
19108         out += '&#' + ch + ';';
19109       }
19110     
19111       return out;
19112     };
19113     
19114     /**
19115      * Renderer
19116      */
19117     
19118      /**
19119          * eval:var:Renderer
19120     */
19121     
19122     var Renderer   = function (options) {
19123       this.options = options || {};
19124     }
19125     
19126     Renderer.prototype.code = function(code, lang, escaped) {
19127       if (this.options.highlight) {
19128         var out = this.options.highlight(code, lang);
19129         if (out != null && out !== code) {
19130           escaped = true;
19131           code = out;
19132         }
19133       } else {
19134             // hack!!! - it's already escapeD?
19135             escaped = true;
19136       }
19137     
19138       if (!lang) {
19139         return '<pre><code>'
19140           + (escaped ? code : escape(code, true))
19141           + '\n</code></pre>';
19142       }
19143     
19144       return '<pre><code class="'
19145         + this.options.langPrefix
19146         + escape(lang, true)
19147         + '">'
19148         + (escaped ? code : escape(code, true))
19149         + '\n</code></pre>\n';
19150     };
19151     
19152     Renderer.prototype.blockquote = function(quote) {
19153       return '<blockquote>\n' + quote + '</blockquote>\n';
19154     };
19155     
19156     Renderer.prototype.html = function(html) {
19157       return html;
19158     };
19159     
19160     Renderer.prototype.heading = function(text, level, raw) {
19161       return '<h'
19162         + level
19163         + ' id="'
19164         + this.options.headerPrefix
19165         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19166         + '">'
19167         + text
19168         + '</h'
19169         + level
19170         + '>\n';
19171     };
19172     
19173     Renderer.prototype.hr = function() {
19174       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19175     };
19176     
19177     Renderer.prototype.list = function(body, ordered) {
19178       var type = ordered ? 'ol' : 'ul';
19179       return '<' + type + '>\n' + body + '</' + type + '>\n';
19180     };
19181     
19182     Renderer.prototype.listitem = function(text) {
19183       return '<li>' + text + '</li>\n';
19184     };
19185     
19186     Renderer.prototype.paragraph = function(text) {
19187       return '<p>' + text + '</p>\n';
19188     };
19189     
19190     Renderer.prototype.table = function(header, body) {
19191       return '<table class="table table-striped">\n'
19192         + '<thead>\n'
19193         + header
19194         + '</thead>\n'
19195         + '<tbody>\n'
19196         + body
19197         + '</tbody>\n'
19198         + '</table>\n';
19199     };
19200     
19201     Renderer.prototype.tablerow = function(content) {
19202       return '<tr>\n' + content + '</tr>\n';
19203     };
19204     
19205     Renderer.prototype.tablecell = function(content, flags) {
19206       var type = flags.header ? 'th' : 'td';
19207       var tag = flags.align
19208         ? '<' + type + ' style="text-align:' + flags.align + '">'
19209         : '<' + type + '>';
19210       return tag + content + '</' + type + '>\n';
19211     };
19212     
19213     // span level renderer
19214     Renderer.prototype.strong = function(text) {
19215       return '<strong>' + text + '</strong>';
19216     };
19217     
19218     Renderer.prototype.em = function(text) {
19219       return '<em>' + text + '</em>';
19220     };
19221     
19222     Renderer.prototype.codespan = function(text) {
19223       return '<code>' + text + '</code>';
19224     };
19225     
19226     Renderer.prototype.br = function() {
19227       return this.options.xhtml ? '<br/>' : '<br>';
19228     };
19229     
19230     Renderer.prototype.del = function(text) {
19231       return '<del>' + text + '</del>';
19232     };
19233     
19234     Renderer.prototype.link = function(href, title, text) {
19235       if (this.options.sanitize) {
19236         try {
19237           var prot = decodeURIComponent(unescape(href))
19238             .replace(/[^\w:]/g, '')
19239             .toLowerCase();
19240         } catch (e) {
19241           return '';
19242         }
19243         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19244           return '';
19245         }
19246       }
19247       var out = '<a href="' + href + '"';
19248       if (title) {
19249         out += ' title="' + title + '"';
19250       }
19251       out += '>' + text + '</a>';
19252       return out;
19253     };
19254     
19255     Renderer.prototype.image = function(href, title, text) {
19256       var out = '<img src="' + href + '" alt="' + text + '"';
19257       if (title) {
19258         out += ' title="' + title + '"';
19259       }
19260       out += this.options.xhtml ? '/>' : '>';
19261       return out;
19262     };
19263     
19264     Renderer.prototype.text = function(text) {
19265       return text;
19266     };
19267     
19268     /**
19269      * Parsing & Compiling
19270      */
19271          /**
19272          * eval:var:Parser
19273     */
19274     
19275     var Parser= function (options) {
19276       this.tokens = [];
19277       this.token = null;
19278       this.options = options || marked.defaults;
19279       this.options.renderer = this.options.renderer || new Renderer;
19280       this.renderer = this.options.renderer;
19281       this.renderer.options = this.options;
19282     }
19283     
19284     /**
19285      * Static Parse Method
19286      */
19287     
19288     Parser.parse = function(src, options, renderer) {
19289       var parser = new Parser(options, renderer);
19290       return parser.parse(src);
19291     };
19292     
19293     /**
19294      * Parse Loop
19295      */
19296     
19297     Parser.prototype.parse = function(src) {
19298       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19299       this.tokens = src.reverse();
19300     
19301       var out = '';
19302       while (this.next()) {
19303         out += this.tok();
19304       }
19305     
19306       return out;
19307     };
19308     
19309     /**
19310      * Next Token
19311      */
19312     
19313     Parser.prototype.next = function() {
19314       return this.token = this.tokens.pop();
19315     };
19316     
19317     /**
19318      * Preview Next Token
19319      */
19320     
19321     Parser.prototype.peek = function() {
19322       return this.tokens[this.tokens.length - 1] || 0;
19323     };
19324     
19325     /**
19326      * Parse Text Tokens
19327      */
19328     
19329     Parser.prototype.parseText = function() {
19330       var body = this.token.text;
19331     
19332       while (this.peek().type === 'text') {
19333         body += '\n' + this.next().text;
19334       }
19335     
19336       return this.inline.output(body);
19337     };
19338     
19339     /**
19340      * Parse Current Token
19341      */
19342     
19343     Parser.prototype.tok = function() {
19344       switch (this.token.type) {
19345         case 'space': {
19346           return '';
19347         }
19348         case 'hr': {
19349           return this.renderer.hr();
19350         }
19351         case 'heading': {
19352           return this.renderer.heading(
19353             this.inline.output(this.token.text),
19354             this.token.depth,
19355             this.token.text);
19356         }
19357         case 'code': {
19358           return this.renderer.code(this.token.text,
19359             this.token.lang,
19360             this.token.escaped);
19361         }
19362         case 'table': {
19363           var header = ''
19364             , body = ''
19365             , i
19366             , row
19367             , cell
19368             , flags
19369             , j;
19370     
19371           // header
19372           cell = '';
19373           for (i = 0; i < this.token.header.length; i++) {
19374             flags = { header: true, align: this.token.align[i] };
19375             cell += this.renderer.tablecell(
19376               this.inline.output(this.token.header[i]),
19377               { header: true, align: this.token.align[i] }
19378             );
19379           }
19380           header += this.renderer.tablerow(cell);
19381     
19382           for (i = 0; i < this.token.cells.length; i++) {
19383             row = this.token.cells[i];
19384     
19385             cell = '';
19386             for (j = 0; j < row.length; j++) {
19387               cell += this.renderer.tablecell(
19388                 this.inline.output(row[j]),
19389                 { header: false, align: this.token.align[j] }
19390               );
19391             }
19392     
19393             body += this.renderer.tablerow(cell);
19394           }
19395           return this.renderer.table(header, body);
19396         }
19397         case 'blockquote_start': {
19398           var body = '';
19399     
19400           while (this.next().type !== 'blockquote_end') {
19401             body += this.tok();
19402           }
19403     
19404           return this.renderer.blockquote(body);
19405         }
19406         case 'list_start': {
19407           var body = ''
19408             , ordered = this.token.ordered;
19409     
19410           while (this.next().type !== 'list_end') {
19411             body += this.tok();
19412           }
19413     
19414           return this.renderer.list(body, ordered);
19415         }
19416         case 'list_item_start': {
19417           var body = '';
19418     
19419           while (this.next().type !== 'list_item_end') {
19420             body += this.token.type === 'text'
19421               ? this.parseText()
19422               : this.tok();
19423           }
19424     
19425           return this.renderer.listitem(body);
19426         }
19427         case 'loose_item_start': {
19428           var body = '';
19429     
19430           while (this.next().type !== 'list_item_end') {
19431             body += this.tok();
19432           }
19433     
19434           return this.renderer.listitem(body);
19435         }
19436         case 'html': {
19437           var html = !this.token.pre && !this.options.pedantic
19438             ? this.inline.output(this.token.text)
19439             : this.token.text;
19440           return this.renderer.html(html);
19441         }
19442         case 'paragraph': {
19443           return this.renderer.paragraph(this.inline.output(this.token.text));
19444         }
19445         case 'text': {
19446           return this.renderer.paragraph(this.parseText());
19447         }
19448       }
19449     };
19450   
19451     
19452     /**
19453      * Marked
19454      */
19455          /**
19456          * eval:var:marked
19457     */
19458     var marked = function (src, opt, callback) {
19459       if (callback || typeof opt === 'function') {
19460         if (!callback) {
19461           callback = opt;
19462           opt = null;
19463         }
19464     
19465         opt = merge({}, marked.defaults, opt || {});
19466     
19467         var highlight = opt.highlight
19468           , tokens
19469           , pending
19470           , i = 0;
19471     
19472         try {
19473           tokens = Lexer.lex(src, opt)
19474         } catch (e) {
19475           return callback(e);
19476         }
19477     
19478         pending = tokens.length;
19479          /**
19480          * eval:var:done
19481     */
19482         var done = function(err) {
19483           if (err) {
19484             opt.highlight = highlight;
19485             return callback(err);
19486           }
19487     
19488           var out;
19489     
19490           try {
19491             out = Parser.parse(tokens, opt);
19492           } catch (e) {
19493             err = e;
19494           }
19495     
19496           opt.highlight = highlight;
19497     
19498           return err
19499             ? callback(err)
19500             : callback(null, out);
19501         };
19502     
19503         if (!highlight || highlight.length < 3) {
19504           return done();
19505         }
19506     
19507         delete opt.highlight;
19508     
19509         if (!pending) { return done(); }
19510     
19511         for (; i < tokens.length; i++) {
19512           (function(token) {
19513             if (token.type !== 'code') {
19514               return --pending || done();
19515             }
19516             return highlight(token.text, token.lang, function(err, code) {
19517               if (err) { return done(err); }
19518               if (code == null || code === token.text) {
19519                 return --pending || done();
19520               }
19521               token.text = code;
19522               token.escaped = true;
19523               --pending || done();
19524             });
19525           })(tokens[i]);
19526         }
19527     
19528         return;
19529       }
19530       try {
19531         if (opt) { opt = merge({}, marked.defaults, opt); }
19532         return Parser.parse(Lexer.lex(src, opt), opt);
19533       } catch (e) {
19534         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19535         if ((opt || marked.defaults).silent) {
19536           return '<p>An error occured:</p><pre>'
19537             + escape(e.message + '', true)
19538             + '</pre>';
19539         }
19540         throw e;
19541       }
19542     }
19543     
19544     /**
19545      * Options
19546      */
19547     
19548     marked.options =
19549     marked.setOptions = function(opt) {
19550       merge(marked.defaults, opt);
19551       return marked;
19552     };
19553     
19554     marked.defaults = {
19555       gfm: true,
19556       tables: true,
19557       breaks: false,
19558       pedantic: false,
19559       sanitize: false,
19560       sanitizer: null,
19561       mangle: true,
19562       smartLists: false,
19563       silent: false,
19564       highlight: null,
19565       langPrefix: 'lang-',
19566       smartypants: false,
19567       headerPrefix: '',
19568       renderer: new Renderer,
19569       xhtml: false
19570     };
19571     
19572     /**
19573      * Expose
19574      */
19575     
19576     marked.Parser = Parser;
19577     marked.parser = Parser.parse;
19578     
19579     marked.Renderer = Renderer;
19580     
19581     marked.Lexer = Lexer;
19582     marked.lexer = Lexer.lex;
19583     
19584     marked.InlineLexer = InlineLexer;
19585     marked.inlineLexer = InlineLexer.output;
19586     
19587     marked.parse = marked;
19588     
19589     Roo.Markdown.marked = marked;
19590
19591 })();/*
19592  * Based on:
19593  * Ext JS Library 1.1.1
19594  * Copyright(c) 2006-2007, Ext JS, LLC.
19595  *
19596  * Originally Released Under LGPL - original licence link has changed is not relivant.
19597  *
19598  * Fork - LGPL
19599  * <script type="text/javascript">
19600  */
19601
19602
19603
19604 /*
19605  * These classes are derivatives of the similarly named classes in the YUI Library.
19606  * The original license:
19607  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19608  * Code licensed under the BSD License:
19609  * http://developer.yahoo.net/yui/license.txt
19610  */
19611
19612 (function() {
19613
19614 var Event=Roo.EventManager;
19615 var Dom=Roo.lib.Dom;
19616
19617 /**
19618  * @class Roo.dd.DragDrop
19619  * @extends Roo.util.Observable
19620  * Defines the interface and base operation of items that that can be
19621  * dragged or can be drop targets.  It was designed to be extended, overriding
19622  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19623  * Up to three html elements can be associated with a DragDrop instance:
19624  * <ul>
19625  * <li>linked element: the element that is passed into the constructor.
19626  * This is the element which defines the boundaries for interaction with
19627  * other DragDrop objects.</li>
19628  * <li>handle element(s): The drag operation only occurs if the element that
19629  * was clicked matches a handle element.  By default this is the linked
19630  * element, but there are times that you will want only a portion of the
19631  * linked element to initiate the drag operation, and the setHandleElId()
19632  * method provides a way to define this.</li>
19633  * <li>drag element: this represents the element that would be moved along
19634  * with the cursor during a drag operation.  By default, this is the linked
19635  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19636  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19637  * </li>
19638  * </ul>
19639  * This class should not be instantiated until the onload event to ensure that
19640  * the associated elements are available.
19641  * The following would define a DragDrop obj that would interact with any
19642  * other DragDrop obj in the "group1" group:
19643  * <pre>
19644  *  dd = new Roo.dd.DragDrop("div1", "group1");
19645  * </pre>
19646  * Since none of the event handlers have been implemented, nothing would
19647  * actually happen if you were to run the code above.  Normally you would
19648  * override this class or one of the default implementations, but you can
19649  * also override the methods you want on an instance of the class...
19650  * <pre>
19651  *  dd.onDragDrop = function(e, id) {
19652  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19653  *  }
19654  * </pre>
19655  * @constructor
19656  * @param {String} id of the element that is linked to this instance
19657  * @param {String} sGroup the group of related DragDrop objects
19658  * @param {object} config an object containing configurable attributes
19659  *                Valid properties for DragDrop:
19660  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19661  */
19662 Roo.dd.DragDrop = function(id, sGroup, config) {
19663     if (id) {
19664         this.init(id, sGroup, config);
19665     }
19666     
19667 };
19668
19669 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19670
19671     /**
19672      * The id of the element associated with this object.  This is what we
19673      * refer to as the "linked element" because the size and position of
19674      * this element is used to determine when the drag and drop objects have
19675      * interacted.
19676      * @property id
19677      * @type String
19678      */
19679     id: null,
19680
19681     /**
19682      * Configuration attributes passed into the constructor
19683      * @property config
19684      * @type object
19685      */
19686     config: null,
19687
19688     /**
19689      * The id of the element that will be dragged.  By default this is same
19690      * as the linked element , but could be changed to another element. Ex:
19691      * Roo.dd.DDProxy
19692      * @property dragElId
19693      * @type String
19694      * @private
19695      */
19696     dragElId: null,
19697
19698     /**
19699      * the id of the element that initiates the drag operation.  By default
19700      * this is the linked element, but could be changed to be a child of this
19701      * element.  This lets us do things like only starting the drag when the
19702      * header element within the linked html element is clicked.
19703      * @property handleElId
19704      * @type String
19705      * @private
19706      */
19707     handleElId: null,
19708
19709     /**
19710      * An associative array of HTML tags that will be ignored if clicked.
19711      * @property invalidHandleTypes
19712      * @type {string: string}
19713      */
19714     invalidHandleTypes: null,
19715
19716     /**
19717      * An associative array of ids for elements that will be ignored if clicked
19718      * @property invalidHandleIds
19719      * @type {string: string}
19720      */
19721     invalidHandleIds: null,
19722
19723     /**
19724      * An indexted array of css class names for elements that will be ignored
19725      * if clicked.
19726      * @property invalidHandleClasses
19727      * @type string[]
19728      */
19729     invalidHandleClasses: null,
19730
19731     /**
19732      * The linked element's absolute X position at the time the drag was
19733      * started
19734      * @property startPageX
19735      * @type int
19736      * @private
19737      */
19738     startPageX: 0,
19739
19740     /**
19741      * The linked element's absolute X position at the time the drag was
19742      * started
19743      * @property startPageY
19744      * @type int
19745      * @private
19746      */
19747     startPageY: 0,
19748
19749     /**
19750      * The group defines a logical collection of DragDrop objects that are
19751      * related.  Instances only get events when interacting with other
19752      * DragDrop object in the same group.  This lets us define multiple
19753      * groups using a single DragDrop subclass if we want.
19754      * @property groups
19755      * @type {string: string}
19756      */
19757     groups: null,
19758
19759     /**
19760      * Individual drag/drop instances can be locked.  This will prevent
19761      * onmousedown start drag.
19762      * @property locked
19763      * @type boolean
19764      * @private
19765      */
19766     locked: false,
19767
19768     /**
19769      * Lock this instance
19770      * @method lock
19771      */
19772     lock: function() { this.locked = true; },
19773
19774     /**
19775      * Unlock this instace
19776      * @method unlock
19777      */
19778     unlock: function() { this.locked = false; },
19779
19780     /**
19781      * By default, all insances can be a drop target.  This can be disabled by
19782      * setting isTarget to false.
19783      * @method isTarget
19784      * @type boolean
19785      */
19786     isTarget: true,
19787
19788     /**
19789      * The padding configured for this drag and drop object for calculating
19790      * the drop zone intersection with this object.
19791      * @method padding
19792      * @type int[]
19793      */
19794     padding: null,
19795
19796     /**
19797      * Cached reference to the linked element
19798      * @property _domRef
19799      * @private
19800      */
19801     _domRef: null,
19802
19803     /**
19804      * Internal typeof flag
19805      * @property __ygDragDrop
19806      * @private
19807      */
19808     __ygDragDrop: true,
19809
19810     /**
19811      * Set to true when horizontal contraints are applied
19812      * @property constrainX
19813      * @type boolean
19814      * @private
19815      */
19816     constrainX: false,
19817
19818     /**
19819      * Set to true when vertical contraints are applied
19820      * @property constrainY
19821      * @type boolean
19822      * @private
19823      */
19824     constrainY: false,
19825
19826     /**
19827      * The left constraint
19828      * @property minX
19829      * @type int
19830      * @private
19831      */
19832     minX: 0,
19833
19834     /**
19835      * The right constraint
19836      * @property maxX
19837      * @type int
19838      * @private
19839      */
19840     maxX: 0,
19841
19842     /**
19843      * The up constraint
19844      * @property minY
19845      * @type int
19846      * @type int
19847      * @private
19848      */
19849     minY: 0,
19850
19851     /**
19852      * The down constraint
19853      * @property maxY
19854      * @type int
19855      * @private
19856      */
19857     maxY: 0,
19858
19859     /**
19860      * Maintain offsets when we resetconstraints.  Set to true when you want
19861      * the position of the element relative to its parent to stay the same
19862      * when the page changes
19863      *
19864      * @property maintainOffset
19865      * @type boolean
19866      */
19867     maintainOffset: false,
19868
19869     /**
19870      * Array of pixel locations the element will snap to if we specified a
19871      * horizontal graduation/interval.  This array is generated automatically
19872      * when you define a tick interval.
19873      * @property xTicks
19874      * @type int[]
19875      */
19876     xTicks: null,
19877
19878     /**
19879      * Array of pixel locations the element will snap to if we specified a
19880      * vertical graduation/interval.  This array is generated automatically
19881      * when you define a tick interval.
19882      * @property yTicks
19883      * @type int[]
19884      */
19885     yTicks: null,
19886
19887     /**
19888      * By default the drag and drop instance will only respond to the primary
19889      * button click (left button for a right-handed mouse).  Set to true to
19890      * allow drag and drop to start with any mouse click that is propogated
19891      * by the browser
19892      * @property primaryButtonOnly
19893      * @type boolean
19894      */
19895     primaryButtonOnly: true,
19896
19897     /**
19898      * The availabe property is false until the linked dom element is accessible.
19899      * @property available
19900      * @type boolean
19901      */
19902     available: false,
19903
19904     /**
19905      * By default, drags can only be initiated if the mousedown occurs in the
19906      * region the linked element is.  This is done in part to work around a
19907      * bug in some browsers that mis-report the mousedown if the previous
19908      * mouseup happened outside of the window.  This property is set to true
19909      * if outer handles are defined.
19910      *
19911      * @property hasOuterHandles
19912      * @type boolean
19913      * @default false
19914      */
19915     hasOuterHandles: false,
19916
19917     /**
19918      * Code that executes immediately before the startDrag event
19919      * @method b4StartDrag
19920      * @private
19921      */
19922     b4StartDrag: function(x, y) { },
19923
19924     /**
19925      * Abstract method called after a drag/drop object is clicked
19926      * and the drag or mousedown time thresholds have beeen met.
19927      * @method startDrag
19928      * @param {int} X click location
19929      * @param {int} Y click location
19930      */
19931     startDrag: function(x, y) { /* override this */ },
19932
19933     /**
19934      * Code that executes immediately before the onDrag event
19935      * @method b4Drag
19936      * @private
19937      */
19938     b4Drag: function(e) { },
19939
19940     /**
19941      * Abstract method called during the onMouseMove event while dragging an
19942      * object.
19943      * @method onDrag
19944      * @param {Event} e the mousemove event
19945      */
19946     onDrag: function(e) { /* override this */ },
19947
19948     /**
19949      * Abstract method called when this element fist begins hovering over
19950      * another DragDrop obj
19951      * @method onDragEnter
19952      * @param {Event} e the mousemove event
19953      * @param {String|DragDrop[]} id In POINT mode, the element
19954      * id this is hovering over.  In INTERSECT mode, an array of one or more
19955      * dragdrop items being hovered over.
19956      */
19957     onDragEnter: function(e, id) { /* override this */ },
19958
19959     /**
19960      * Code that executes immediately before the onDragOver event
19961      * @method b4DragOver
19962      * @private
19963      */
19964     b4DragOver: function(e) { },
19965
19966     /**
19967      * Abstract method called when this element is hovering over another
19968      * DragDrop obj
19969      * @method onDragOver
19970      * @param {Event} e the mousemove event
19971      * @param {String|DragDrop[]} id In POINT mode, the element
19972      * id this is hovering over.  In INTERSECT mode, an array of dd items
19973      * being hovered over.
19974      */
19975     onDragOver: function(e, id) { /* override this */ },
19976
19977     /**
19978      * Code that executes immediately before the onDragOut event
19979      * @method b4DragOut
19980      * @private
19981      */
19982     b4DragOut: function(e) { },
19983
19984     /**
19985      * Abstract method called when we are no longer hovering over an element
19986      * @method onDragOut
19987      * @param {Event} e the mousemove event
19988      * @param {String|DragDrop[]} id In POINT mode, the element
19989      * id this was hovering over.  In INTERSECT mode, an array of dd items
19990      * that the mouse is no longer over.
19991      */
19992     onDragOut: function(e, id) { /* override this */ },
19993
19994     /**
19995      * Code that executes immediately before the onDragDrop event
19996      * @method b4DragDrop
19997      * @private
19998      */
19999     b4DragDrop: function(e) { },
20000
20001     /**
20002      * Abstract method called when this item is dropped on another DragDrop
20003      * obj
20004      * @method onDragDrop
20005      * @param {Event} e the mouseup event
20006      * @param {String|DragDrop[]} id In POINT mode, the element
20007      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20008      * was dropped on.
20009      */
20010     onDragDrop: function(e, id) { /* override this */ },
20011
20012     /**
20013      * Abstract method called when this item is dropped on an area with no
20014      * drop target
20015      * @method onInvalidDrop
20016      * @param {Event} e the mouseup event
20017      */
20018     onInvalidDrop: function(e) { /* override this */ },
20019
20020     /**
20021      * Code that executes immediately before the endDrag event
20022      * @method b4EndDrag
20023      * @private
20024      */
20025     b4EndDrag: function(e) { },
20026
20027     /**
20028      * Fired when we are done dragging the object
20029      * @method endDrag
20030      * @param {Event} e the mouseup event
20031      */
20032     endDrag: function(e) { /* override this */ },
20033
20034     /**
20035      * Code executed immediately before the onMouseDown event
20036      * @method b4MouseDown
20037      * @param {Event} e the mousedown event
20038      * @private
20039      */
20040     b4MouseDown: function(e) {  },
20041
20042     /**
20043      * Event handler that fires when a drag/drop obj gets a mousedown
20044      * @method onMouseDown
20045      * @param {Event} e the mousedown event
20046      */
20047     onMouseDown: function(e) { /* override this */ },
20048
20049     /**
20050      * Event handler that fires when a drag/drop obj gets a mouseup
20051      * @method onMouseUp
20052      * @param {Event} e the mouseup event
20053      */
20054     onMouseUp: function(e) { /* override this */ },
20055
20056     /**
20057      * Override the onAvailable method to do what is needed after the initial
20058      * position was determined.
20059      * @method onAvailable
20060      */
20061     onAvailable: function () {
20062     },
20063
20064     /*
20065      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20066      * @type Object
20067      */
20068     defaultPadding : {left:0, right:0, top:0, bottom:0},
20069
20070     /*
20071      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20072  *
20073  * Usage:
20074  <pre><code>
20075  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20076                 { dragElId: "existingProxyDiv" });
20077  dd.startDrag = function(){
20078      this.constrainTo("parent-id");
20079  };
20080  </code></pre>
20081  * Or you can initalize it using the {@link Roo.Element} object:
20082  <pre><code>
20083  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20084      startDrag : function(){
20085          this.constrainTo("parent-id");
20086      }
20087  });
20088  </code></pre>
20089      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20090      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20091      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20092      * an object containing the sides to pad. For example: {right:10, bottom:10}
20093      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20094      */
20095     constrainTo : function(constrainTo, pad, inContent){
20096         if(typeof pad == "number"){
20097             pad = {left: pad, right:pad, top:pad, bottom:pad};
20098         }
20099         pad = pad || this.defaultPadding;
20100         var b = Roo.get(this.getEl()).getBox();
20101         var ce = Roo.get(constrainTo);
20102         var s = ce.getScroll();
20103         var c, cd = ce.dom;
20104         if(cd == document.body){
20105             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20106         }else{
20107             xy = ce.getXY();
20108             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20109         }
20110
20111
20112         var topSpace = b.y - c.y;
20113         var leftSpace = b.x - c.x;
20114
20115         this.resetConstraints();
20116         this.setXConstraint(leftSpace - (pad.left||0), // left
20117                 c.width - leftSpace - b.width - (pad.right||0) //right
20118         );
20119         this.setYConstraint(topSpace - (pad.top||0), //top
20120                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20121         );
20122     },
20123
20124     /**
20125      * Returns a reference to the linked element
20126      * @method getEl
20127      * @return {HTMLElement} the html element
20128      */
20129     getEl: function() {
20130         if (!this._domRef) {
20131             this._domRef = Roo.getDom(this.id);
20132         }
20133
20134         return this._domRef;
20135     },
20136
20137     /**
20138      * Returns a reference to the actual element to drag.  By default this is
20139      * the same as the html element, but it can be assigned to another
20140      * element. An example of this can be found in Roo.dd.DDProxy
20141      * @method getDragEl
20142      * @return {HTMLElement} the html element
20143      */
20144     getDragEl: function() {
20145         return Roo.getDom(this.dragElId);
20146     },
20147
20148     /**
20149      * Sets up the DragDrop object.  Must be called in the constructor of any
20150      * Roo.dd.DragDrop subclass
20151      * @method init
20152      * @param id the id of the linked element
20153      * @param {String} sGroup the group of related items
20154      * @param {object} config configuration attributes
20155      */
20156     init: function(id, sGroup, config) {
20157         this.initTarget(id, sGroup, config);
20158         if (!Roo.isTouch) {
20159             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20160         }
20161         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20162         // Event.on(this.id, "selectstart", Event.preventDefault);
20163     },
20164
20165     /**
20166      * Initializes Targeting functionality only... the object does not
20167      * get a mousedown handler.
20168      * @method initTarget
20169      * @param id the id of the linked element
20170      * @param {String} sGroup the group of related items
20171      * @param {object} config configuration attributes
20172      */
20173     initTarget: function(id, sGroup, config) {
20174
20175         // configuration attributes
20176         this.config = config || {};
20177
20178         // create a local reference to the drag and drop manager
20179         this.DDM = Roo.dd.DDM;
20180         // initialize the groups array
20181         this.groups = {};
20182
20183         // assume that we have an element reference instead of an id if the
20184         // parameter is not a string
20185         if (typeof id !== "string") {
20186             id = Roo.id(id);
20187         }
20188
20189         // set the id
20190         this.id = id;
20191
20192         // add to an interaction group
20193         this.addToGroup((sGroup) ? sGroup : "default");
20194
20195         // We don't want to register this as the handle with the manager
20196         // so we just set the id rather than calling the setter.
20197         this.handleElId = id;
20198
20199         // the linked element is the element that gets dragged by default
20200         this.setDragElId(id);
20201
20202         // by default, clicked anchors will not start drag operations.
20203         this.invalidHandleTypes = { A: "A" };
20204         this.invalidHandleIds = {};
20205         this.invalidHandleClasses = [];
20206
20207         this.applyConfig();
20208
20209         this.handleOnAvailable();
20210     },
20211
20212     /**
20213      * Applies the configuration parameters that were passed into the constructor.
20214      * This is supposed to happen at each level through the inheritance chain.  So
20215      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20216      * DragDrop in order to get all of the parameters that are available in
20217      * each object.
20218      * @method applyConfig
20219      */
20220     applyConfig: function() {
20221
20222         // configurable properties:
20223         //    padding, isTarget, maintainOffset, primaryButtonOnly
20224         this.padding           = this.config.padding || [0, 0, 0, 0];
20225         this.isTarget          = (this.config.isTarget !== false);
20226         this.maintainOffset    = (this.config.maintainOffset);
20227         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20228
20229     },
20230
20231     /**
20232      * Executed when the linked element is available
20233      * @method handleOnAvailable
20234      * @private
20235      */
20236     handleOnAvailable: function() {
20237         this.available = true;
20238         this.resetConstraints();
20239         this.onAvailable();
20240     },
20241
20242      /**
20243      * Configures the padding for the target zone in px.  Effectively expands
20244      * (or reduces) the virtual object size for targeting calculations.
20245      * Supports css-style shorthand; if only one parameter is passed, all sides
20246      * will have that padding, and if only two are passed, the top and bottom
20247      * will have the first param, the left and right the second.
20248      * @method setPadding
20249      * @param {int} iTop    Top pad
20250      * @param {int} iRight  Right pad
20251      * @param {int} iBot    Bot pad
20252      * @param {int} iLeft   Left pad
20253      */
20254     setPadding: function(iTop, iRight, iBot, iLeft) {
20255         // this.padding = [iLeft, iRight, iTop, iBot];
20256         if (!iRight && 0 !== iRight) {
20257             this.padding = [iTop, iTop, iTop, iTop];
20258         } else if (!iBot && 0 !== iBot) {
20259             this.padding = [iTop, iRight, iTop, iRight];
20260         } else {
20261             this.padding = [iTop, iRight, iBot, iLeft];
20262         }
20263     },
20264
20265     /**
20266      * Stores the initial placement of the linked element.
20267      * @method setInitialPosition
20268      * @param {int} diffX   the X offset, default 0
20269      * @param {int} diffY   the Y offset, default 0
20270      */
20271     setInitPosition: function(diffX, diffY) {
20272         var el = this.getEl();
20273
20274         if (!this.DDM.verifyEl(el)) {
20275             return;
20276         }
20277
20278         var dx = diffX || 0;
20279         var dy = diffY || 0;
20280
20281         var p = Dom.getXY( el );
20282
20283         this.initPageX = p[0] - dx;
20284         this.initPageY = p[1] - dy;
20285
20286         this.lastPageX = p[0];
20287         this.lastPageY = p[1];
20288
20289
20290         this.setStartPosition(p);
20291     },
20292
20293     /**
20294      * Sets the start position of the element.  This is set when the obj
20295      * is initialized, the reset when a drag is started.
20296      * @method setStartPosition
20297      * @param pos current position (from previous lookup)
20298      * @private
20299      */
20300     setStartPosition: function(pos) {
20301         var p = pos || Dom.getXY( this.getEl() );
20302         this.deltaSetXY = null;
20303
20304         this.startPageX = p[0];
20305         this.startPageY = p[1];
20306     },
20307
20308     /**
20309      * Add this instance to a group of related drag/drop objects.  All
20310      * instances belong to at least one group, and can belong to as many
20311      * groups as needed.
20312      * @method addToGroup
20313      * @param sGroup {string} the name of the group
20314      */
20315     addToGroup: function(sGroup) {
20316         this.groups[sGroup] = true;
20317         this.DDM.regDragDrop(this, sGroup);
20318     },
20319
20320     /**
20321      * Remove's this instance from the supplied interaction group
20322      * @method removeFromGroup
20323      * @param {string}  sGroup  The group to drop
20324      */
20325     removeFromGroup: function(sGroup) {
20326         if (this.groups[sGroup]) {
20327             delete this.groups[sGroup];
20328         }
20329
20330         this.DDM.removeDDFromGroup(this, sGroup);
20331     },
20332
20333     /**
20334      * Allows you to specify that an element other than the linked element
20335      * will be moved with the cursor during a drag
20336      * @method setDragElId
20337      * @param id {string} the id of the element that will be used to initiate the drag
20338      */
20339     setDragElId: function(id) {
20340         this.dragElId = id;
20341     },
20342
20343     /**
20344      * Allows you to specify a child of the linked element that should be
20345      * used to initiate the drag operation.  An example of this would be if
20346      * you have a content div with text and links.  Clicking anywhere in the
20347      * content area would normally start the drag operation.  Use this method
20348      * to specify that an element inside of the content div is the element
20349      * that starts the drag operation.
20350      * @method setHandleElId
20351      * @param id {string} the id of the element that will be used to
20352      * initiate the drag.
20353      */
20354     setHandleElId: function(id) {
20355         if (typeof id !== "string") {
20356             id = Roo.id(id);
20357         }
20358         this.handleElId = id;
20359         this.DDM.regHandle(this.id, id);
20360     },
20361
20362     /**
20363      * Allows you to set an element outside of the linked element as a drag
20364      * handle
20365      * @method setOuterHandleElId
20366      * @param id the id of the element that will be used to initiate the drag
20367      */
20368     setOuterHandleElId: function(id) {
20369         if (typeof id !== "string") {
20370             id = Roo.id(id);
20371         }
20372         Event.on(id, "mousedown",
20373                 this.handleMouseDown, this);
20374         this.setHandleElId(id);
20375
20376         this.hasOuterHandles = true;
20377     },
20378
20379     /**
20380      * Remove all drag and drop hooks for this element
20381      * @method unreg
20382      */
20383     unreg: function() {
20384         Event.un(this.id, "mousedown",
20385                 this.handleMouseDown);
20386         Event.un(this.id, "touchstart",
20387                 this.handleMouseDown);
20388         this._domRef = null;
20389         this.DDM._remove(this);
20390     },
20391
20392     destroy : function(){
20393         this.unreg();
20394     },
20395
20396     /**
20397      * Returns true if this instance is locked, or the drag drop mgr is locked
20398      * (meaning that all drag/drop is disabled on the page.)
20399      * @method isLocked
20400      * @return {boolean} true if this obj or all drag/drop is locked, else
20401      * false
20402      */
20403     isLocked: function() {
20404         return (this.DDM.isLocked() || this.locked);
20405     },
20406
20407     /**
20408      * Fired when this object is clicked
20409      * @method handleMouseDown
20410      * @param {Event} e
20411      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20412      * @private
20413      */
20414     handleMouseDown: function(e, oDD){
20415      
20416         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20417             //Roo.log('not touch/ button !=0');
20418             return;
20419         }
20420         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20421             return; // double touch..
20422         }
20423         
20424
20425         if (this.isLocked()) {
20426             //Roo.log('locked');
20427             return;
20428         }
20429
20430         this.DDM.refreshCache(this.groups);
20431 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20432         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20433         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20434             //Roo.log('no outer handes or not over target');
20435                 // do nothing.
20436         } else {
20437 //            Roo.log('check validator');
20438             if (this.clickValidator(e)) {
20439 //                Roo.log('validate success');
20440                 // set the initial element position
20441                 this.setStartPosition();
20442
20443
20444                 this.b4MouseDown(e);
20445                 this.onMouseDown(e);
20446
20447                 this.DDM.handleMouseDown(e, this);
20448
20449                 this.DDM.stopEvent(e);
20450             } else {
20451
20452
20453             }
20454         }
20455     },
20456
20457     clickValidator: function(e) {
20458         var target = e.getTarget();
20459         return ( this.isValidHandleChild(target) &&
20460                     (this.id == this.handleElId ||
20461                         this.DDM.handleWasClicked(target, this.id)) );
20462     },
20463
20464     /**
20465      * Allows you to specify a tag name that should not start a drag operation
20466      * when clicked.  This is designed to facilitate embedding links within a
20467      * drag handle that do something other than start the drag.
20468      * @method addInvalidHandleType
20469      * @param {string} tagName the type of element to exclude
20470      */
20471     addInvalidHandleType: function(tagName) {
20472         var type = tagName.toUpperCase();
20473         this.invalidHandleTypes[type] = type;
20474     },
20475
20476     /**
20477      * Lets you to specify an element id for a child of a drag handle
20478      * that should not initiate a drag
20479      * @method addInvalidHandleId
20480      * @param {string} id the element id of the element you wish to ignore
20481      */
20482     addInvalidHandleId: function(id) {
20483         if (typeof id !== "string") {
20484             id = Roo.id(id);
20485         }
20486         this.invalidHandleIds[id] = id;
20487     },
20488
20489     /**
20490      * Lets you specify a css class of elements that will not initiate a drag
20491      * @method addInvalidHandleClass
20492      * @param {string} cssClass the class of the elements you wish to ignore
20493      */
20494     addInvalidHandleClass: function(cssClass) {
20495         this.invalidHandleClasses.push(cssClass);
20496     },
20497
20498     /**
20499      * Unsets an excluded tag name set by addInvalidHandleType
20500      * @method removeInvalidHandleType
20501      * @param {string} tagName the type of element to unexclude
20502      */
20503     removeInvalidHandleType: function(tagName) {
20504         var type = tagName.toUpperCase();
20505         // this.invalidHandleTypes[type] = null;
20506         delete this.invalidHandleTypes[type];
20507     },
20508
20509     /**
20510      * Unsets an invalid handle id
20511      * @method removeInvalidHandleId
20512      * @param {string} id the id of the element to re-enable
20513      */
20514     removeInvalidHandleId: function(id) {
20515         if (typeof id !== "string") {
20516             id = Roo.id(id);
20517         }
20518         delete this.invalidHandleIds[id];
20519     },
20520
20521     /**
20522      * Unsets an invalid css class
20523      * @method removeInvalidHandleClass
20524      * @param {string} cssClass the class of the element(s) you wish to
20525      * re-enable
20526      */
20527     removeInvalidHandleClass: function(cssClass) {
20528         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20529             if (this.invalidHandleClasses[i] == cssClass) {
20530                 delete this.invalidHandleClasses[i];
20531             }
20532         }
20533     },
20534
20535     /**
20536      * Checks the tag exclusion list to see if this click should be ignored
20537      * @method isValidHandleChild
20538      * @param {HTMLElement} node the HTMLElement to evaluate
20539      * @return {boolean} true if this is a valid tag type, false if not
20540      */
20541     isValidHandleChild: function(node) {
20542
20543         var valid = true;
20544         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20545         var nodeName;
20546         try {
20547             nodeName = node.nodeName.toUpperCase();
20548         } catch(e) {
20549             nodeName = node.nodeName;
20550         }
20551         valid = valid && !this.invalidHandleTypes[nodeName];
20552         valid = valid && !this.invalidHandleIds[node.id];
20553
20554         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20555             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20556         }
20557
20558
20559         return valid;
20560
20561     },
20562
20563     /**
20564      * Create the array of horizontal tick marks if an interval was specified
20565      * in setXConstraint().
20566      * @method setXTicks
20567      * @private
20568      */
20569     setXTicks: function(iStartX, iTickSize) {
20570         this.xTicks = [];
20571         this.xTickSize = iTickSize;
20572
20573         var tickMap = {};
20574
20575         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20576             if (!tickMap[i]) {
20577                 this.xTicks[this.xTicks.length] = i;
20578                 tickMap[i] = true;
20579             }
20580         }
20581
20582         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20583             if (!tickMap[i]) {
20584                 this.xTicks[this.xTicks.length] = i;
20585                 tickMap[i] = true;
20586             }
20587         }
20588
20589         this.xTicks.sort(this.DDM.numericSort) ;
20590     },
20591
20592     /**
20593      * Create the array of vertical tick marks if an interval was specified in
20594      * setYConstraint().
20595      * @method setYTicks
20596      * @private
20597      */
20598     setYTicks: function(iStartY, iTickSize) {
20599         this.yTicks = [];
20600         this.yTickSize = iTickSize;
20601
20602         var tickMap = {};
20603
20604         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20605             if (!tickMap[i]) {
20606                 this.yTicks[this.yTicks.length] = i;
20607                 tickMap[i] = true;
20608             }
20609         }
20610
20611         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20612             if (!tickMap[i]) {
20613                 this.yTicks[this.yTicks.length] = i;
20614                 tickMap[i] = true;
20615             }
20616         }
20617
20618         this.yTicks.sort(this.DDM.numericSort) ;
20619     },
20620
20621     /**
20622      * By default, the element can be dragged any place on the screen.  Use
20623      * this method to limit the horizontal travel of the element.  Pass in
20624      * 0,0 for the parameters if you want to lock the drag to the y axis.
20625      * @method setXConstraint
20626      * @param {int} iLeft the number of pixels the element can move to the left
20627      * @param {int} iRight the number of pixels the element can move to the
20628      * right
20629      * @param {int} iTickSize optional parameter for specifying that the
20630      * element
20631      * should move iTickSize pixels at a time.
20632      */
20633     setXConstraint: function(iLeft, iRight, iTickSize) {
20634         this.leftConstraint = iLeft;
20635         this.rightConstraint = iRight;
20636
20637         this.minX = this.initPageX - iLeft;
20638         this.maxX = this.initPageX + iRight;
20639         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20640
20641         this.constrainX = true;
20642     },
20643
20644     /**
20645      * Clears any constraints applied to this instance.  Also clears ticks
20646      * since they can't exist independent of a constraint at this time.
20647      * @method clearConstraints
20648      */
20649     clearConstraints: function() {
20650         this.constrainX = false;
20651         this.constrainY = false;
20652         this.clearTicks();
20653     },
20654
20655     /**
20656      * Clears any tick interval defined for this instance
20657      * @method clearTicks
20658      */
20659     clearTicks: function() {
20660         this.xTicks = null;
20661         this.yTicks = null;
20662         this.xTickSize = 0;
20663         this.yTickSize = 0;
20664     },
20665
20666     /**
20667      * By default, the element can be dragged any place on the screen.  Set
20668      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20669      * parameters if you want to lock the drag to the x axis.
20670      * @method setYConstraint
20671      * @param {int} iUp the number of pixels the element can move up
20672      * @param {int} iDown the number of pixels the element can move down
20673      * @param {int} iTickSize optional parameter for specifying that the
20674      * element should move iTickSize pixels at a time.
20675      */
20676     setYConstraint: function(iUp, iDown, iTickSize) {
20677         this.topConstraint = iUp;
20678         this.bottomConstraint = iDown;
20679
20680         this.minY = this.initPageY - iUp;
20681         this.maxY = this.initPageY + iDown;
20682         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20683
20684         this.constrainY = true;
20685
20686     },
20687
20688     /**
20689      * resetConstraints must be called if you manually reposition a dd element.
20690      * @method resetConstraints
20691      * @param {boolean} maintainOffset
20692      */
20693     resetConstraints: function() {
20694
20695
20696         // Maintain offsets if necessary
20697         if (this.initPageX || this.initPageX === 0) {
20698             // figure out how much this thing has moved
20699             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20700             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20701
20702             this.setInitPosition(dx, dy);
20703
20704         // This is the first time we have detected the element's position
20705         } else {
20706             this.setInitPosition();
20707         }
20708
20709         if (this.constrainX) {
20710             this.setXConstraint( this.leftConstraint,
20711                                  this.rightConstraint,
20712                                  this.xTickSize        );
20713         }
20714
20715         if (this.constrainY) {
20716             this.setYConstraint( this.topConstraint,
20717                                  this.bottomConstraint,
20718                                  this.yTickSize         );
20719         }
20720     },
20721
20722     /**
20723      * Normally the drag element is moved pixel by pixel, but we can specify
20724      * that it move a number of pixels at a time.  This method resolves the
20725      * location when we have it set up like this.
20726      * @method getTick
20727      * @param {int} val where we want to place the object
20728      * @param {int[]} tickArray sorted array of valid points
20729      * @return {int} the closest tick
20730      * @private
20731      */
20732     getTick: function(val, tickArray) {
20733
20734         if (!tickArray) {
20735             // If tick interval is not defined, it is effectively 1 pixel,
20736             // so we return the value passed to us.
20737             return val;
20738         } else if (tickArray[0] >= val) {
20739             // The value is lower than the first tick, so we return the first
20740             // tick.
20741             return tickArray[0];
20742         } else {
20743             for (var i=0, len=tickArray.length; i<len; ++i) {
20744                 var next = i + 1;
20745                 if (tickArray[next] && tickArray[next] >= val) {
20746                     var diff1 = val - tickArray[i];
20747                     var diff2 = tickArray[next] - val;
20748                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20749                 }
20750             }
20751
20752             // The value is larger than the last tick, so we return the last
20753             // tick.
20754             return tickArray[tickArray.length - 1];
20755         }
20756     },
20757
20758     /**
20759      * toString method
20760      * @method toString
20761      * @return {string} string representation of the dd obj
20762      */
20763     toString: function() {
20764         return ("DragDrop " + this.id);
20765     }
20766
20767 });
20768
20769 })();
20770 /*
20771  * Based on:
20772  * Ext JS Library 1.1.1
20773  * Copyright(c) 2006-2007, Ext JS, LLC.
20774  *
20775  * Originally Released Under LGPL - original licence link has changed is not relivant.
20776  *
20777  * Fork - LGPL
20778  * <script type="text/javascript">
20779  */
20780
20781
20782 /**
20783  * The drag and drop utility provides a framework for building drag and drop
20784  * applications.  In addition to enabling drag and drop for specific elements,
20785  * the drag and drop elements are tracked by the manager class, and the
20786  * interactions between the various elements are tracked during the drag and
20787  * the implementing code is notified about these important moments.
20788  */
20789
20790 // Only load the library once.  Rewriting the manager class would orphan
20791 // existing drag and drop instances.
20792 if (!Roo.dd.DragDropMgr) {
20793
20794 /**
20795  * @class Roo.dd.DragDropMgr
20796  * DragDropMgr is a singleton that tracks the element interaction for
20797  * all DragDrop items in the window.  Generally, you will not call
20798  * this class directly, but it does have helper methods that could
20799  * be useful in your DragDrop implementations.
20800  * @static
20801  */
20802 Roo.dd.DragDropMgr = function() {
20803
20804     var Event = Roo.EventManager;
20805
20806     return {
20807
20808         /**
20809          * Two dimensional Array of registered DragDrop objects.  The first
20810          * dimension is the DragDrop item group, the second the DragDrop
20811          * object.
20812          * @property ids
20813          * @type {string: string}
20814          * @private
20815          * @static
20816          */
20817         ids: {},
20818
20819         /**
20820          * Array of element ids defined as drag handles.  Used to determine
20821          * if the element that generated the mousedown event is actually the
20822          * handle and not the html element itself.
20823          * @property handleIds
20824          * @type {string: string}
20825          * @private
20826          * @static
20827          */
20828         handleIds: {},
20829
20830         /**
20831          * the DragDrop object that is currently being dragged
20832          * @property dragCurrent
20833          * @type DragDrop
20834          * @private
20835          * @static
20836          **/
20837         dragCurrent: null,
20838
20839         /**
20840          * the DragDrop object(s) that are being hovered over
20841          * @property dragOvers
20842          * @type Array
20843          * @private
20844          * @static
20845          */
20846         dragOvers: {},
20847
20848         /**
20849          * the X distance between the cursor and the object being dragged
20850          * @property deltaX
20851          * @type int
20852          * @private
20853          * @static
20854          */
20855         deltaX: 0,
20856
20857         /**
20858          * the Y distance between the cursor and the object being dragged
20859          * @property deltaY
20860          * @type int
20861          * @private
20862          * @static
20863          */
20864         deltaY: 0,
20865
20866         /**
20867          * Flag to determine if we should prevent the default behavior of the
20868          * events we define. By default this is true, but this can be set to
20869          * false if you need the default behavior (not recommended)
20870          * @property preventDefault
20871          * @type boolean
20872          * @static
20873          */
20874         preventDefault: true,
20875
20876         /**
20877          * Flag to determine if we should stop the propagation of the events
20878          * we generate. This is true by default but you may want to set it to
20879          * false if the html element contains other features that require the
20880          * mouse click.
20881          * @property stopPropagation
20882          * @type boolean
20883          * @static
20884          */
20885         stopPropagation: true,
20886
20887         /**
20888          * Internal flag that is set to true when drag and drop has been
20889          * intialized
20890          * @property initialized
20891          * @private
20892          * @static
20893          */
20894         initalized: false,
20895
20896         /**
20897          * All drag and drop can be disabled.
20898          * @property locked
20899          * @private
20900          * @static
20901          */
20902         locked: false,
20903
20904         /**
20905          * Called the first time an element is registered.
20906          * @method init
20907          * @private
20908          * @static
20909          */
20910         init: function() {
20911             this.initialized = true;
20912         },
20913
20914         /**
20915          * In point mode, drag and drop interaction is defined by the
20916          * location of the cursor during the drag/drop
20917          * @property POINT
20918          * @type int
20919          * @static
20920          */
20921         POINT: 0,
20922
20923         /**
20924          * In intersect mode, drag and drop interactio nis defined by the
20925          * overlap of two or more drag and drop objects.
20926          * @property INTERSECT
20927          * @type int
20928          * @static
20929          */
20930         INTERSECT: 1,
20931
20932         /**
20933          * The current drag and drop mode.  Default: POINT
20934          * @property mode
20935          * @type int
20936          * @static
20937          */
20938         mode: 0,
20939
20940         /**
20941          * Runs method on all drag and drop objects
20942          * @method _execOnAll
20943          * @private
20944          * @static
20945          */
20946         _execOnAll: function(sMethod, args) {
20947             for (var i in this.ids) {
20948                 for (var j in this.ids[i]) {
20949                     var oDD = this.ids[i][j];
20950                     if (! this.isTypeOfDD(oDD)) {
20951                         continue;
20952                     }
20953                     oDD[sMethod].apply(oDD, args);
20954                 }
20955             }
20956         },
20957
20958         /**
20959          * Drag and drop initialization.  Sets up the global event handlers
20960          * @method _onLoad
20961          * @private
20962          * @static
20963          */
20964         _onLoad: function() {
20965
20966             this.init();
20967
20968             if (!Roo.isTouch) {
20969                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20970                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20971             }
20972             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20973             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20974             
20975             Event.on(window,   "unload",    this._onUnload, this, true);
20976             Event.on(window,   "resize",    this._onResize, this, true);
20977             // Event.on(window,   "mouseout",    this._test);
20978
20979         },
20980
20981         /**
20982          * Reset constraints on all drag and drop objs
20983          * @method _onResize
20984          * @private
20985          * @static
20986          */
20987         _onResize: function(e) {
20988             this._execOnAll("resetConstraints", []);
20989         },
20990
20991         /**
20992          * Lock all drag and drop functionality
20993          * @method lock
20994          * @static
20995          */
20996         lock: function() { this.locked = true; },
20997
20998         /**
20999          * Unlock all drag and drop functionality
21000          * @method unlock
21001          * @static
21002          */
21003         unlock: function() { this.locked = false; },
21004
21005         /**
21006          * Is drag and drop locked?
21007          * @method isLocked
21008          * @return {boolean} True if drag and drop is locked, false otherwise.
21009          * @static
21010          */
21011         isLocked: function() { return this.locked; },
21012
21013         /**
21014          * Location cache that is set for all drag drop objects when a drag is
21015          * initiated, cleared when the drag is finished.
21016          * @property locationCache
21017          * @private
21018          * @static
21019          */
21020         locationCache: {},
21021
21022         /**
21023          * Set useCache to false if you want to force object the lookup of each
21024          * drag and drop linked element constantly during a drag.
21025          * @property useCache
21026          * @type boolean
21027          * @static
21028          */
21029         useCache: true,
21030
21031         /**
21032          * The number of pixels that the mouse needs to move after the
21033          * mousedown before the drag is initiated.  Default=3;
21034          * @property clickPixelThresh
21035          * @type int
21036          * @static
21037          */
21038         clickPixelThresh: 3,
21039
21040         /**
21041          * The number of milliseconds after the mousedown event to initiate the
21042          * drag if we don't get a mouseup event. Default=1000
21043          * @property clickTimeThresh
21044          * @type int
21045          * @static
21046          */
21047         clickTimeThresh: 350,
21048
21049         /**
21050          * Flag that indicates that either the drag pixel threshold or the
21051          * mousdown time threshold has been met
21052          * @property dragThreshMet
21053          * @type boolean
21054          * @private
21055          * @static
21056          */
21057         dragThreshMet: false,
21058
21059         /**
21060          * Timeout used for the click time threshold
21061          * @property clickTimeout
21062          * @type Object
21063          * @private
21064          * @static
21065          */
21066         clickTimeout: null,
21067
21068         /**
21069          * The X position of the mousedown event stored for later use when a
21070          * drag threshold is met.
21071          * @property startX
21072          * @type int
21073          * @private
21074          * @static
21075          */
21076         startX: 0,
21077
21078         /**
21079          * The Y position of the mousedown event stored for later use when a
21080          * drag threshold is met.
21081          * @property startY
21082          * @type int
21083          * @private
21084          * @static
21085          */
21086         startY: 0,
21087
21088         /**
21089          * Each DragDrop instance must be registered with the DragDropMgr.
21090          * This is executed in DragDrop.init()
21091          * @method regDragDrop
21092          * @param {DragDrop} oDD the DragDrop object to register
21093          * @param {String} sGroup the name of the group this element belongs to
21094          * @static
21095          */
21096         regDragDrop: function(oDD, sGroup) {
21097             if (!this.initialized) { this.init(); }
21098
21099             if (!this.ids[sGroup]) {
21100                 this.ids[sGroup] = {};
21101             }
21102             this.ids[sGroup][oDD.id] = oDD;
21103         },
21104
21105         /**
21106          * Removes the supplied dd instance from the supplied group. Executed
21107          * by DragDrop.removeFromGroup, so don't call this function directly.
21108          * @method removeDDFromGroup
21109          * @private
21110          * @static
21111          */
21112         removeDDFromGroup: function(oDD, sGroup) {
21113             if (!this.ids[sGroup]) {
21114                 this.ids[sGroup] = {};
21115             }
21116
21117             var obj = this.ids[sGroup];
21118             if (obj && obj[oDD.id]) {
21119                 delete obj[oDD.id];
21120             }
21121         },
21122
21123         /**
21124          * Unregisters a drag and drop item.  This is executed in
21125          * DragDrop.unreg, use that method instead of calling this directly.
21126          * @method _remove
21127          * @private
21128          * @static
21129          */
21130         _remove: function(oDD) {
21131             for (var g in oDD.groups) {
21132                 if (g && this.ids[g][oDD.id]) {
21133                     delete this.ids[g][oDD.id];
21134                 }
21135             }
21136             delete this.handleIds[oDD.id];
21137         },
21138
21139         /**
21140          * Each DragDrop handle element must be registered.  This is done
21141          * automatically when executing DragDrop.setHandleElId()
21142          * @method regHandle
21143          * @param {String} sDDId the DragDrop id this element is a handle for
21144          * @param {String} sHandleId the id of the element that is the drag
21145          * handle
21146          * @static
21147          */
21148         regHandle: function(sDDId, sHandleId) {
21149             if (!this.handleIds[sDDId]) {
21150                 this.handleIds[sDDId] = {};
21151             }
21152             this.handleIds[sDDId][sHandleId] = sHandleId;
21153         },
21154
21155         /**
21156          * Utility function to determine if a given element has been
21157          * registered as a drag drop item.
21158          * @method isDragDrop
21159          * @param {String} id the element id to check
21160          * @return {boolean} true if this element is a DragDrop item,
21161          * false otherwise
21162          * @static
21163          */
21164         isDragDrop: function(id) {
21165             return ( this.getDDById(id) ) ? true : false;
21166         },
21167
21168         /**
21169          * Returns the drag and drop instances that are in all groups the
21170          * passed in instance belongs to.
21171          * @method getRelated
21172          * @param {DragDrop} p_oDD the obj to get related data for
21173          * @param {boolean} bTargetsOnly if true, only return targetable objs
21174          * @return {DragDrop[]} the related instances
21175          * @static
21176          */
21177         getRelated: function(p_oDD, bTargetsOnly) {
21178             var oDDs = [];
21179             for (var i in p_oDD.groups) {
21180                 for (j in this.ids[i]) {
21181                     var dd = this.ids[i][j];
21182                     if (! this.isTypeOfDD(dd)) {
21183                         continue;
21184                     }
21185                     if (!bTargetsOnly || dd.isTarget) {
21186                         oDDs[oDDs.length] = dd;
21187                     }
21188                 }
21189             }
21190
21191             return oDDs;
21192         },
21193
21194         /**
21195          * Returns true if the specified dd target is a legal target for
21196          * the specifice drag obj
21197          * @method isLegalTarget
21198          * @param {DragDrop} the drag obj
21199          * @param {DragDrop} the target
21200          * @return {boolean} true if the target is a legal target for the
21201          * dd obj
21202          * @static
21203          */
21204         isLegalTarget: function (oDD, oTargetDD) {
21205             var targets = this.getRelated(oDD, true);
21206             for (var i=0, len=targets.length;i<len;++i) {
21207                 if (targets[i].id == oTargetDD.id) {
21208                     return true;
21209                 }
21210             }
21211
21212             return false;
21213         },
21214
21215         /**
21216          * My goal is to be able to transparently determine if an object is
21217          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21218          * returns "object", oDD.constructor.toString() always returns
21219          * "DragDrop" and not the name of the subclass.  So for now it just
21220          * evaluates a well-known variable in DragDrop.
21221          * @method isTypeOfDD
21222          * @param {Object} the object to evaluate
21223          * @return {boolean} true if typeof oDD = DragDrop
21224          * @static
21225          */
21226         isTypeOfDD: function (oDD) {
21227             return (oDD && oDD.__ygDragDrop);
21228         },
21229
21230         /**
21231          * Utility function to determine if a given element has been
21232          * registered as a drag drop handle for the given Drag Drop object.
21233          * @method isHandle
21234          * @param {String} id the element id to check
21235          * @return {boolean} true if this element is a DragDrop handle, false
21236          * otherwise
21237          * @static
21238          */
21239         isHandle: function(sDDId, sHandleId) {
21240             return ( this.handleIds[sDDId] &&
21241                             this.handleIds[sDDId][sHandleId] );
21242         },
21243
21244         /**
21245          * Returns the DragDrop instance for a given id
21246          * @method getDDById
21247          * @param {String} id the id of the DragDrop object
21248          * @return {DragDrop} the drag drop object, null if it is not found
21249          * @static
21250          */
21251         getDDById: function(id) {
21252             for (var i in this.ids) {
21253                 if (this.ids[i][id]) {
21254                     return this.ids[i][id];
21255                 }
21256             }
21257             return null;
21258         },
21259
21260         /**
21261          * Fired after a registered DragDrop object gets the mousedown event.
21262          * Sets up the events required to track the object being dragged
21263          * @method handleMouseDown
21264          * @param {Event} e the event
21265          * @param oDD the DragDrop object being dragged
21266          * @private
21267          * @static
21268          */
21269         handleMouseDown: function(e, oDD) {
21270             if(Roo.QuickTips){
21271                 Roo.QuickTips.disable();
21272             }
21273             this.currentTarget = e.getTarget();
21274
21275             this.dragCurrent = oDD;
21276
21277             var el = oDD.getEl();
21278
21279             // track start position
21280             this.startX = e.getPageX();
21281             this.startY = e.getPageY();
21282
21283             this.deltaX = this.startX - el.offsetLeft;
21284             this.deltaY = this.startY - el.offsetTop;
21285
21286             this.dragThreshMet = false;
21287
21288             this.clickTimeout = setTimeout(
21289                     function() {
21290                         var DDM = Roo.dd.DDM;
21291                         DDM.startDrag(DDM.startX, DDM.startY);
21292                     },
21293                     this.clickTimeThresh );
21294         },
21295
21296         /**
21297          * Fired when either the drag pixel threshol or the mousedown hold
21298          * time threshold has been met.
21299          * @method startDrag
21300          * @param x {int} the X position of the original mousedown
21301          * @param y {int} the Y position of the original mousedown
21302          * @static
21303          */
21304         startDrag: function(x, y) {
21305             clearTimeout(this.clickTimeout);
21306             if (this.dragCurrent) {
21307                 this.dragCurrent.b4StartDrag(x, y);
21308                 this.dragCurrent.startDrag(x, y);
21309             }
21310             this.dragThreshMet = true;
21311         },
21312
21313         /**
21314          * Internal function to handle the mouseup event.  Will be invoked
21315          * from the context of the document.
21316          * @method handleMouseUp
21317          * @param {Event} e the event
21318          * @private
21319          * @static
21320          */
21321         handleMouseUp: function(e) {
21322
21323             if(Roo.QuickTips){
21324                 Roo.QuickTips.enable();
21325             }
21326             if (! this.dragCurrent) {
21327                 return;
21328             }
21329
21330             clearTimeout(this.clickTimeout);
21331
21332             if (this.dragThreshMet) {
21333                 this.fireEvents(e, true);
21334             } else {
21335             }
21336
21337             this.stopDrag(e);
21338
21339             this.stopEvent(e);
21340         },
21341
21342         /**
21343          * Utility to stop event propagation and event default, if these
21344          * features are turned on.
21345          * @method stopEvent
21346          * @param {Event} e the event as returned by this.getEvent()
21347          * @static
21348          */
21349         stopEvent: function(e){
21350             if(this.stopPropagation) {
21351                 e.stopPropagation();
21352             }
21353
21354             if (this.preventDefault) {
21355                 e.preventDefault();
21356             }
21357         },
21358
21359         /**
21360          * Internal function to clean up event handlers after the drag
21361          * operation is complete
21362          * @method stopDrag
21363          * @param {Event} e the event
21364          * @private
21365          * @static
21366          */
21367         stopDrag: function(e) {
21368             // Fire the drag end event for the item that was dragged
21369             if (this.dragCurrent) {
21370                 if (this.dragThreshMet) {
21371                     this.dragCurrent.b4EndDrag(e);
21372                     this.dragCurrent.endDrag(e);
21373                 }
21374
21375                 this.dragCurrent.onMouseUp(e);
21376             }
21377
21378             this.dragCurrent = null;
21379             this.dragOvers = {};
21380         },
21381
21382         /**
21383          * Internal function to handle the mousemove event.  Will be invoked
21384          * from the context of the html element.
21385          *
21386          * @TODO figure out what we can do about mouse events lost when the
21387          * user drags objects beyond the window boundary.  Currently we can
21388          * detect this in internet explorer by verifying that the mouse is
21389          * down during the mousemove event.  Firefox doesn't give us the
21390          * button state on the mousemove event.
21391          * @method handleMouseMove
21392          * @param {Event} e the event
21393          * @private
21394          * @static
21395          */
21396         handleMouseMove: function(e) {
21397             if (! this.dragCurrent) {
21398                 return true;
21399             }
21400
21401             // var button = e.which || e.button;
21402
21403             // check for IE mouseup outside of page boundary
21404             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21405                 this.stopEvent(e);
21406                 return this.handleMouseUp(e);
21407             }
21408
21409             if (!this.dragThreshMet) {
21410                 var diffX = Math.abs(this.startX - e.getPageX());
21411                 var diffY = Math.abs(this.startY - e.getPageY());
21412                 if (diffX > this.clickPixelThresh ||
21413                             diffY > this.clickPixelThresh) {
21414                     this.startDrag(this.startX, this.startY);
21415                 }
21416             }
21417
21418             if (this.dragThreshMet) {
21419                 this.dragCurrent.b4Drag(e);
21420                 this.dragCurrent.onDrag(e);
21421                 if(!this.dragCurrent.moveOnly){
21422                     this.fireEvents(e, false);
21423                 }
21424             }
21425
21426             this.stopEvent(e);
21427
21428             return true;
21429         },
21430
21431         /**
21432          * Iterates over all of the DragDrop elements to find ones we are
21433          * hovering over or dropping on
21434          * @method fireEvents
21435          * @param {Event} e the event
21436          * @param {boolean} isDrop is this a drop op or a mouseover op?
21437          * @private
21438          * @static
21439          */
21440         fireEvents: function(e, isDrop) {
21441             var dc = this.dragCurrent;
21442
21443             // If the user did the mouse up outside of the window, we could
21444             // get here even though we have ended the drag.
21445             if (!dc || dc.isLocked()) {
21446                 return;
21447             }
21448
21449             var pt = e.getPoint();
21450
21451             // cache the previous dragOver array
21452             var oldOvers = [];
21453
21454             var outEvts   = [];
21455             var overEvts  = [];
21456             var dropEvts  = [];
21457             var enterEvts = [];
21458
21459             // Check to see if the object(s) we were hovering over is no longer
21460             // being hovered over so we can fire the onDragOut event
21461             for (var i in this.dragOvers) {
21462
21463                 var ddo = this.dragOvers[i];
21464
21465                 if (! this.isTypeOfDD(ddo)) {
21466                     continue;
21467                 }
21468
21469                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21470                     outEvts.push( ddo );
21471                 }
21472
21473                 oldOvers[i] = true;
21474                 delete this.dragOvers[i];
21475             }
21476
21477             for (var sGroup in dc.groups) {
21478
21479                 if ("string" != typeof sGroup) {
21480                     continue;
21481                 }
21482
21483                 for (i in this.ids[sGroup]) {
21484                     var oDD = this.ids[sGroup][i];
21485                     if (! this.isTypeOfDD(oDD)) {
21486                         continue;
21487                     }
21488
21489                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21490                         if (this.isOverTarget(pt, oDD, this.mode)) {
21491                             // look for drop interactions
21492                             if (isDrop) {
21493                                 dropEvts.push( oDD );
21494                             // look for drag enter and drag over interactions
21495                             } else {
21496
21497                                 // initial drag over: dragEnter fires
21498                                 if (!oldOvers[oDD.id]) {
21499                                     enterEvts.push( oDD );
21500                                 // subsequent drag overs: dragOver fires
21501                                 } else {
21502                                     overEvts.push( oDD );
21503                                 }
21504
21505                                 this.dragOvers[oDD.id] = oDD;
21506                             }
21507                         }
21508                     }
21509                 }
21510             }
21511
21512             if (this.mode) {
21513                 if (outEvts.length) {
21514                     dc.b4DragOut(e, outEvts);
21515                     dc.onDragOut(e, outEvts);
21516                 }
21517
21518                 if (enterEvts.length) {
21519                     dc.onDragEnter(e, enterEvts);
21520                 }
21521
21522                 if (overEvts.length) {
21523                     dc.b4DragOver(e, overEvts);
21524                     dc.onDragOver(e, overEvts);
21525                 }
21526
21527                 if (dropEvts.length) {
21528                     dc.b4DragDrop(e, dropEvts);
21529                     dc.onDragDrop(e, dropEvts);
21530                 }
21531
21532             } else {
21533                 // fire dragout events
21534                 var len = 0;
21535                 for (i=0, len=outEvts.length; i<len; ++i) {
21536                     dc.b4DragOut(e, outEvts[i].id);
21537                     dc.onDragOut(e, outEvts[i].id);
21538                 }
21539
21540                 // fire enter events
21541                 for (i=0,len=enterEvts.length; i<len; ++i) {
21542                     // dc.b4DragEnter(e, oDD.id);
21543                     dc.onDragEnter(e, enterEvts[i].id);
21544                 }
21545
21546                 // fire over events
21547                 for (i=0,len=overEvts.length; i<len; ++i) {
21548                     dc.b4DragOver(e, overEvts[i].id);
21549                     dc.onDragOver(e, overEvts[i].id);
21550                 }
21551
21552                 // fire drop events
21553                 for (i=0, len=dropEvts.length; i<len; ++i) {
21554                     dc.b4DragDrop(e, dropEvts[i].id);
21555                     dc.onDragDrop(e, dropEvts[i].id);
21556                 }
21557
21558             }
21559
21560             // notify about a drop that did not find a target
21561             if (isDrop && !dropEvts.length) {
21562                 dc.onInvalidDrop(e);
21563             }
21564
21565         },
21566
21567         /**
21568          * Helper function for getting the best match from the list of drag
21569          * and drop objects returned by the drag and drop events when we are
21570          * in INTERSECT mode.  It returns either the first object that the
21571          * cursor is over, or the object that has the greatest overlap with
21572          * the dragged element.
21573          * @method getBestMatch
21574          * @param  {DragDrop[]} dds The array of drag and drop objects
21575          * targeted
21576          * @return {DragDrop}       The best single match
21577          * @static
21578          */
21579         getBestMatch: function(dds) {
21580             var winner = null;
21581             // Return null if the input is not what we expect
21582             //if (!dds || !dds.length || dds.length == 0) {
21583                // winner = null;
21584             // If there is only one item, it wins
21585             //} else if (dds.length == 1) {
21586
21587             var len = dds.length;
21588
21589             if (len == 1) {
21590                 winner = dds[0];
21591             } else {
21592                 // Loop through the targeted items
21593                 for (var i=0; i<len; ++i) {
21594                     var dd = dds[i];
21595                     // If the cursor is over the object, it wins.  If the
21596                     // cursor is over multiple matches, the first one we come
21597                     // to wins.
21598                     if (dd.cursorIsOver) {
21599                         winner = dd;
21600                         break;
21601                     // Otherwise the object with the most overlap wins
21602                     } else {
21603                         if (!winner ||
21604                             winner.overlap.getArea() < dd.overlap.getArea()) {
21605                             winner = dd;
21606                         }
21607                     }
21608                 }
21609             }
21610
21611             return winner;
21612         },
21613
21614         /**
21615          * Refreshes the cache of the top-left and bottom-right points of the
21616          * drag and drop objects in the specified group(s).  This is in the
21617          * format that is stored in the drag and drop instance, so typical
21618          * usage is:
21619          * <code>
21620          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21621          * </code>
21622          * Alternatively:
21623          * <code>
21624          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21625          * </code>
21626          * @TODO this really should be an indexed array.  Alternatively this
21627          * method could accept both.
21628          * @method refreshCache
21629          * @param {Object} groups an associative array of groups to refresh
21630          * @static
21631          */
21632         refreshCache: function(groups) {
21633             for (var sGroup in groups) {
21634                 if ("string" != typeof sGroup) {
21635                     continue;
21636                 }
21637                 for (var i in this.ids[sGroup]) {
21638                     var oDD = this.ids[sGroup][i];
21639
21640                     if (this.isTypeOfDD(oDD)) {
21641                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21642                         var loc = this.getLocation(oDD);
21643                         if (loc) {
21644                             this.locationCache[oDD.id] = loc;
21645                         } else {
21646                             delete this.locationCache[oDD.id];
21647                             // this will unregister the drag and drop object if
21648                             // the element is not in a usable state
21649                             // oDD.unreg();
21650                         }
21651                     }
21652                 }
21653             }
21654         },
21655
21656         /**
21657          * This checks to make sure an element exists and is in the DOM.  The
21658          * main purpose is to handle cases where innerHTML is used to remove
21659          * drag and drop objects from the DOM.  IE provides an 'unspecified
21660          * error' when trying to access the offsetParent of such an element
21661          * @method verifyEl
21662          * @param {HTMLElement} el the element to check
21663          * @return {boolean} true if the element looks usable
21664          * @static
21665          */
21666         verifyEl: function(el) {
21667             if (el) {
21668                 var parent;
21669                 if(Roo.isIE){
21670                     try{
21671                         parent = el.offsetParent;
21672                     }catch(e){}
21673                 }else{
21674                     parent = el.offsetParent;
21675                 }
21676                 if (parent) {
21677                     return true;
21678                 }
21679             }
21680
21681             return false;
21682         },
21683
21684         /**
21685          * Returns a Region object containing the drag and drop element's position
21686          * and size, including the padding configured for it
21687          * @method getLocation
21688          * @param {DragDrop} oDD the drag and drop object to get the
21689          *                       location for
21690          * @return {Roo.lib.Region} a Region object representing the total area
21691          *                             the element occupies, including any padding
21692          *                             the instance is configured for.
21693          * @static
21694          */
21695         getLocation: function(oDD) {
21696             if (! this.isTypeOfDD(oDD)) {
21697                 return null;
21698             }
21699
21700             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21701
21702             try {
21703                 pos= Roo.lib.Dom.getXY(el);
21704             } catch (e) { }
21705
21706             if (!pos) {
21707                 return null;
21708             }
21709
21710             x1 = pos[0];
21711             x2 = x1 + el.offsetWidth;
21712             y1 = pos[1];
21713             y2 = y1 + el.offsetHeight;
21714
21715             t = y1 - oDD.padding[0];
21716             r = x2 + oDD.padding[1];
21717             b = y2 + oDD.padding[2];
21718             l = x1 - oDD.padding[3];
21719
21720             return new Roo.lib.Region( t, r, b, l );
21721         },
21722
21723         /**
21724          * Checks the cursor location to see if it over the target
21725          * @method isOverTarget
21726          * @param {Roo.lib.Point} pt The point to evaluate
21727          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21728          * @return {boolean} true if the mouse is over the target
21729          * @private
21730          * @static
21731          */
21732         isOverTarget: function(pt, oTarget, intersect) {
21733             // use cache if available
21734             var loc = this.locationCache[oTarget.id];
21735             if (!loc || !this.useCache) {
21736                 loc = this.getLocation(oTarget);
21737                 this.locationCache[oTarget.id] = loc;
21738
21739             }
21740
21741             if (!loc) {
21742                 return false;
21743             }
21744
21745             oTarget.cursorIsOver = loc.contains( pt );
21746
21747             // DragDrop is using this as a sanity check for the initial mousedown
21748             // in this case we are done.  In POINT mode, if the drag obj has no
21749             // contraints, we are also done. Otherwise we need to evaluate the
21750             // location of the target as related to the actual location of the
21751             // dragged element.
21752             var dc = this.dragCurrent;
21753             if (!dc || !dc.getTargetCoord ||
21754                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21755                 return oTarget.cursorIsOver;
21756             }
21757
21758             oTarget.overlap = null;
21759
21760             // Get the current location of the drag element, this is the
21761             // location of the mouse event less the delta that represents
21762             // where the original mousedown happened on the element.  We
21763             // need to consider constraints and ticks as well.
21764             var pos = dc.getTargetCoord(pt.x, pt.y);
21765
21766             var el = dc.getDragEl();
21767             var curRegion = new Roo.lib.Region( pos.y,
21768                                                    pos.x + el.offsetWidth,
21769                                                    pos.y + el.offsetHeight,
21770                                                    pos.x );
21771
21772             var overlap = curRegion.intersect(loc);
21773
21774             if (overlap) {
21775                 oTarget.overlap = overlap;
21776                 return (intersect) ? true : oTarget.cursorIsOver;
21777             } else {
21778                 return false;
21779             }
21780         },
21781
21782         /**
21783          * unload event handler
21784          * @method _onUnload
21785          * @private
21786          * @static
21787          */
21788         _onUnload: function(e, me) {
21789             Roo.dd.DragDropMgr.unregAll();
21790         },
21791
21792         /**
21793          * Cleans up the drag and drop events and objects.
21794          * @method unregAll
21795          * @private
21796          * @static
21797          */
21798         unregAll: function() {
21799
21800             if (this.dragCurrent) {
21801                 this.stopDrag();
21802                 this.dragCurrent = null;
21803             }
21804
21805             this._execOnAll("unreg", []);
21806
21807             for (i in this.elementCache) {
21808                 delete this.elementCache[i];
21809             }
21810
21811             this.elementCache = {};
21812             this.ids = {};
21813         },
21814
21815         /**
21816          * A cache of DOM elements
21817          * @property elementCache
21818          * @private
21819          * @static
21820          */
21821         elementCache: {},
21822
21823         /**
21824          * Get the wrapper for the DOM element specified
21825          * @method getElWrapper
21826          * @param {String} id the id of the element to get
21827          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21828          * @private
21829          * @deprecated This wrapper isn't that useful
21830          * @static
21831          */
21832         getElWrapper: function(id) {
21833             var oWrapper = this.elementCache[id];
21834             if (!oWrapper || !oWrapper.el) {
21835                 oWrapper = this.elementCache[id] =
21836                     new this.ElementWrapper(Roo.getDom(id));
21837             }
21838             return oWrapper;
21839         },
21840
21841         /**
21842          * Returns the actual DOM element
21843          * @method getElement
21844          * @param {String} id the id of the elment to get
21845          * @return {Object} The element
21846          * @deprecated use Roo.getDom instead
21847          * @static
21848          */
21849         getElement: function(id) {
21850             return Roo.getDom(id);
21851         },
21852
21853         /**
21854          * Returns the style property for the DOM element (i.e.,
21855          * document.getElById(id).style)
21856          * @method getCss
21857          * @param {String} id the id of the elment to get
21858          * @return {Object} The style property of the element
21859          * @deprecated use Roo.getDom instead
21860          * @static
21861          */
21862         getCss: function(id) {
21863             var el = Roo.getDom(id);
21864             return (el) ? el.style : null;
21865         },
21866
21867         /**
21868          * Inner class for cached elements
21869          * @class DragDropMgr.ElementWrapper
21870          * @for DragDropMgr
21871          * @private
21872          * @deprecated
21873          */
21874         ElementWrapper: function(el) {
21875                 /**
21876                  * The element
21877                  * @property el
21878                  */
21879                 this.el = el || null;
21880                 /**
21881                  * The element id
21882                  * @property id
21883                  */
21884                 this.id = this.el && el.id;
21885                 /**
21886                  * A reference to the style property
21887                  * @property css
21888                  */
21889                 this.css = this.el && el.style;
21890             },
21891
21892         /**
21893          * Returns the X position of an html element
21894          * @method getPosX
21895          * @param el the element for which to get the position
21896          * @return {int} the X coordinate
21897          * @for DragDropMgr
21898          * @deprecated use Roo.lib.Dom.getX instead
21899          * @static
21900          */
21901         getPosX: function(el) {
21902             return Roo.lib.Dom.getX(el);
21903         },
21904
21905         /**
21906          * Returns the Y position of an html element
21907          * @method getPosY
21908          * @param el the element for which to get the position
21909          * @return {int} the Y coordinate
21910          * @deprecated use Roo.lib.Dom.getY instead
21911          * @static
21912          */
21913         getPosY: function(el) {
21914             return Roo.lib.Dom.getY(el);
21915         },
21916
21917         /**
21918          * Swap two nodes.  In IE, we use the native method, for others we
21919          * emulate the IE behavior
21920          * @method swapNode
21921          * @param n1 the first node to swap
21922          * @param n2 the other node to swap
21923          * @static
21924          */
21925         swapNode: function(n1, n2) {
21926             if (n1.swapNode) {
21927                 n1.swapNode(n2);
21928             } else {
21929                 var p = n2.parentNode;
21930                 var s = n2.nextSibling;
21931
21932                 if (s == n1) {
21933                     p.insertBefore(n1, n2);
21934                 } else if (n2 == n1.nextSibling) {
21935                     p.insertBefore(n2, n1);
21936                 } else {
21937                     n1.parentNode.replaceChild(n2, n1);
21938                     p.insertBefore(n1, s);
21939                 }
21940             }
21941         },
21942
21943         /**
21944          * Returns the current scroll position
21945          * @method getScroll
21946          * @private
21947          * @static
21948          */
21949         getScroll: function () {
21950             var t, l, dde=document.documentElement, db=document.body;
21951             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21952                 t = dde.scrollTop;
21953                 l = dde.scrollLeft;
21954             } else if (db) {
21955                 t = db.scrollTop;
21956                 l = db.scrollLeft;
21957             } else {
21958
21959             }
21960             return { top: t, left: l };
21961         },
21962
21963         /**
21964          * Returns the specified element style property
21965          * @method getStyle
21966          * @param {HTMLElement} el          the element
21967          * @param {string}      styleProp   the style property
21968          * @return {string} The value of the style property
21969          * @deprecated use Roo.lib.Dom.getStyle
21970          * @static
21971          */
21972         getStyle: function(el, styleProp) {
21973             return Roo.fly(el).getStyle(styleProp);
21974         },
21975
21976         /**
21977          * Gets the scrollTop
21978          * @method getScrollTop
21979          * @return {int} the document's scrollTop
21980          * @static
21981          */
21982         getScrollTop: function () { return this.getScroll().top; },
21983
21984         /**
21985          * Gets the scrollLeft
21986          * @method getScrollLeft
21987          * @return {int} the document's scrollTop
21988          * @static
21989          */
21990         getScrollLeft: function () { return this.getScroll().left; },
21991
21992         /**
21993          * Sets the x/y position of an element to the location of the
21994          * target element.
21995          * @method moveToEl
21996          * @param {HTMLElement} moveEl      The element to move
21997          * @param {HTMLElement} targetEl    The position reference element
21998          * @static
21999          */
22000         moveToEl: function (moveEl, targetEl) {
22001             var aCoord = Roo.lib.Dom.getXY(targetEl);
22002             Roo.lib.Dom.setXY(moveEl, aCoord);
22003         },
22004
22005         /**
22006          * Numeric array sort function
22007          * @method numericSort
22008          * @static
22009          */
22010         numericSort: function(a, b) { return (a - b); },
22011
22012         /**
22013          * Internal counter
22014          * @property _timeoutCount
22015          * @private
22016          * @static
22017          */
22018         _timeoutCount: 0,
22019
22020         /**
22021          * Trying to make the load order less important.  Without this we get
22022          * an error if this file is loaded before the Event Utility.
22023          * @method _addListeners
22024          * @private
22025          * @static
22026          */
22027         _addListeners: function() {
22028             var DDM = Roo.dd.DDM;
22029             if ( Roo.lib.Event && document ) {
22030                 DDM._onLoad();
22031             } else {
22032                 if (DDM._timeoutCount > 2000) {
22033                 } else {
22034                     setTimeout(DDM._addListeners, 10);
22035                     if (document && document.body) {
22036                         DDM._timeoutCount += 1;
22037                     }
22038                 }
22039             }
22040         },
22041
22042         /**
22043          * Recursively searches the immediate parent and all child nodes for
22044          * the handle element in order to determine wheter or not it was
22045          * clicked.
22046          * @method handleWasClicked
22047          * @param node the html element to inspect
22048          * @static
22049          */
22050         handleWasClicked: function(node, id) {
22051             if (this.isHandle(id, node.id)) {
22052                 return true;
22053             } else {
22054                 // check to see if this is a text node child of the one we want
22055                 var p = node.parentNode;
22056
22057                 while (p) {
22058                     if (this.isHandle(id, p.id)) {
22059                         return true;
22060                     } else {
22061                         p = p.parentNode;
22062                     }
22063                 }
22064             }
22065
22066             return false;
22067         }
22068
22069     };
22070
22071 }();
22072
22073 // shorter alias, save a few bytes
22074 Roo.dd.DDM = Roo.dd.DragDropMgr;
22075 Roo.dd.DDM._addListeners();
22076
22077 }/*
22078  * Based on:
22079  * Ext JS Library 1.1.1
22080  * Copyright(c) 2006-2007, Ext JS, LLC.
22081  *
22082  * Originally Released Under LGPL - original licence link has changed is not relivant.
22083  *
22084  * Fork - LGPL
22085  * <script type="text/javascript">
22086  */
22087
22088 /**
22089  * @class Roo.dd.DD
22090  * A DragDrop implementation where the linked element follows the
22091  * mouse cursor during a drag.
22092  * @extends Roo.dd.DragDrop
22093  * @constructor
22094  * @param {String} id the id of the linked element
22095  * @param {String} sGroup the group of related DragDrop items
22096  * @param {object} config an object containing configurable attributes
22097  *                Valid properties for DD:
22098  *                    scroll
22099  */
22100 Roo.dd.DD = function(id, sGroup, config) {
22101     if (id) {
22102         this.init(id, sGroup, config);
22103     }
22104 };
22105
22106 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22107
22108     /**
22109      * When set to true, the utility automatically tries to scroll the browser
22110      * window wehn a drag and drop element is dragged near the viewport boundary.
22111      * Defaults to true.
22112      * @property scroll
22113      * @type boolean
22114      */
22115     scroll: true,
22116
22117     /**
22118      * Sets the pointer offset to the distance between the linked element's top
22119      * left corner and the location the element was clicked
22120      * @method autoOffset
22121      * @param {int} iPageX the X coordinate of the click
22122      * @param {int} iPageY the Y coordinate of the click
22123      */
22124     autoOffset: function(iPageX, iPageY) {
22125         var x = iPageX - this.startPageX;
22126         var y = iPageY - this.startPageY;
22127         this.setDelta(x, y);
22128     },
22129
22130     /**
22131      * Sets the pointer offset.  You can call this directly to force the
22132      * offset to be in a particular location (e.g., pass in 0,0 to set it
22133      * to the center of the object)
22134      * @method setDelta
22135      * @param {int} iDeltaX the distance from the left
22136      * @param {int} iDeltaY the distance from the top
22137      */
22138     setDelta: function(iDeltaX, iDeltaY) {
22139         this.deltaX = iDeltaX;
22140         this.deltaY = iDeltaY;
22141     },
22142
22143     /**
22144      * Sets the drag element to the location of the mousedown or click event,
22145      * maintaining the cursor location relative to the location on the element
22146      * that was clicked.  Override this if you want to place the element in a
22147      * location other than where the cursor is.
22148      * @method setDragElPos
22149      * @param {int} iPageX the X coordinate of the mousedown or drag event
22150      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22151      */
22152     setDragElPos: function(iPageX, iPageY) {
22153         // the first time we do this, we are going to check to make sure
22154         // the element has css positioning
22155
22156         var el = this.getDragEl();
22157         this.alignElWithMouse(el, iPageX, iPageY);
22158     },
22159
22160     /**
22161      * Sets the element to the location of the mousedown or click event,
22162      * maintaining the cursor location relative to the location on the element
22163      * that was clicked.  Override this if you want to place the element in a
22164      * location other than where the cursor is.
22165      * @method alignElWithMouse
22166      * @param {HTMLElement} el the element to move
22167      * @param {int} iPageX the X coordinate of the mousedown or drag event
22168      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22169      */
22170     alignElWithMouse: function(el, iPageX, iPageY) {
22171         var oCoord = this.getTargetCoord(iPageX, iPageY);
22172         var fly = el.dom ? el : Roo.fly(el);
22173         if (!this.deltaSetXY) {
22174             var aCoord = [oCoord.x, oCoord.y];
22175             fly.setXY(aCoord);
22176             var newLeft = fly.getLeft(true);
22177             var newTop  = fly.getTop(true);
22178             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22179         } else {
22180             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22181         }
22182
22183         this.cachePosition(oCoord.x, oCoord.y);
22184         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22185         return oCoord;
22186     },
22187
22188     /**
22189      * Saves the most recent position so that we can reset the constraints and
22190      * tick marks on-demand.  We need to know this so that we can calculate the
22191      * number of pixels the element is offset from its original position.
22192      * @method cachePosition
22193      * @param iPageX the current x position (optional, this just makes it so we
22194      * don't have to look it up again)
22195      * @param iPageY the current y position (optional, this just makes it so we
22196      * don't have to look it up again)
22197      */
22198     cachePosition: function(iPageX, iPageY) {
22199         if (iPageX) {
22200             this.lastPageX = iPageX;
22201             this.lastPageY = iPageY;
22202         } else {
22203             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22204             this.lastPageX = aCoord[0];
22205             this.lastPageY = aCoord[1];
22206         }
22207     },
22208
22209     /**
22210      * Auto-scroll the window if the dragged object has been moved beyond the
22211      * visible window boundary.
22212      * @method autoScroll
22213      * @param {int} x the drag element's x position
22214      * @param {int} y the drag element's y position
22215      * @param {int} h the height of the drag element
22216      * @param {int} w the width of the drag element
22217      * @private
22218      */
22219     autoScroll: function(x, y, h, w) {
22220
22221         if (this.scroll) {
22222             // The client height
22223             var clientH = Roo.lib.Dom.getViewWidth();
22224
22225             // The client width
22226             var clientW = Roo.lib.Dom.getViewHeight();
22227
22228             // The amt scrolled down
22229             var st = this.DDM.getScrollTop();
22230
22231             // The amt scrolled right
22232             var sl = this.DDM.getScrollLeft();
22233
22234             // Location of the bottom of the element
22235             var bot = h + y;
22236
22237             // Location of the right of the element
22238             var right = w + x;
22239
22240             // The distance from the cursor to the bottom of the visible area,
22241             // adjusted so that we don't scroll if the cursor is beyond the
22242             // element drag constraints
22243             var toBot = (clientH + st - y - this.deltaY);
22244
22245             // The distance from the cursor to the right of the visible area
22246             var toRight = (clientW + sl - x - this.deltaX);
22247
22248
22249             // How close to the edge the cursor must be before we scroll
22250             // var thresh = (document.all) ? 100 : 40;
22251             var thresh = 40;
22252
22253             // How many pixels to scroll per autoscroll op.  This helps to reduce
22254             // clunky scrolling. IE is more sensitive about this ... it needs this
22255             // value to be higher.
22256             var scrAmt = (document.all) ? 80 : 30;
22257
22258             // Scroll down if we are near the bottom of the visible page and the
22259             // obj extends below the crease
22260             if ( bot > clientH && toBot < thresh ) {
22261                 window.scrollTo(sl, st + scrAmt);
22262             }
22263
22264             // Scroll up if the window is scrolled down and the top of the object
22265             // goes above the top border
22266             if ( y < st && st > 0 && y - st < thresh ) {
22267                 window.scrollTo(sl, st - scrAmt);
22268             }
22269
22270             // Scroll right if the obj is beyond the right border and the cursor is
22271             // near the border.
22272             if ( right > clientW && toRight < thresh ) {
22273                 window.scrollTo(sl + scrAmt, st);
22274             }
22275
22276             // Scroll left if the window has been scrolled to the right and the obj
22277             // extends past the left border
22278             if ( x < sl && sl > 0 && x - sl < thresh ) {
22279                 window.scrollTo(sl - scrAmt, st);
22280             }
22281         }
22282     },
22283
22284     /**
22285      * Finds the location the element should be placed if we want to move
22286      * it to where the mouse location less the click offset would place us.
22287      * @method getTargetCoord
22288      * @param {int} iPageX the X coordinate of the click
22289      * @param {int} iPageY the Y coordinate of the click
22290      * @return an object that contains the coordinates (Object.x and Object.y)
22291      * @private
22292      */
22293     getTargetCoord: function(iPageX, iPageY) {
22294
22295
22296         var x = iPageX - this.deltaX;
22297         var y = iPageY - this.deltaY;
22298
22299         if (this.constrainX) {
22300             if (x < this.minX) { x = this.minX; }
22301             if (x > this.maxX) { x = this.maxX; }
22302         }
22303
22304         if (this.constrainY) {
22305             if (y < this.minY) { y = this.minY; }
22306             if (y > this.maxY) { y = this.maxY; }
22307         }
22308
22309         x = this.getTick(x, this.xTicks);
22310         y = this.getTick(y, this.yTicks);
22311
22312
22313         return {x:x, y:y};
22314     },
22315
22316     /*
22317      * Sets up config options specific to this class. Overrides
22318      * Roo.dd.DragDrop, but all versions of this method through the
22319      * inheritance chain are called
22320      */
22321     applyConfig: function() {
22322         Roo.dd.DD.superclass.applyConfig.call(this);
22323         this.scroll = (this.config.scroll !== false);
22324     },
22325
22326     /*
22327      * Event that fires prior to the onMouseDown event.  Overrides
22328      * Roo.dd.DragDrop.
22329      */
22330     b4MouseDown: function(e) {
22331         // this.resetConstraints();
22332         this.autoOffset(e.getPageX(),
22333                             e.getPageY());
22334     },
22335
22336     /*
22337      * Event that fires prior to the onDrag event.  Overrides
22338      * Roo.dd.DragDrop.
22339      */
22340     b4Drag: function(e) {
22341         this.setDragElPos(e.getPageX(),
22342                             e.getPageY());
22343     },
22344
22345     toString: function() {
22346         return ("DD " + this.id);
22347     }
22348
22349     //////////////////////////////////////////////////////////////////////////
22350     // Debugging ygDragDrop events that can be overridden
22351     //////////////////////////////////////////////////////////////////////////
22352     /*
22353     startDrag: function(x, y) {
22354     },
22355
22356     onDrag: function(e) {
22357     },
22358
22359     onDragEnter: function(e, id) {
22360     },
22361
22362     onDragOver: function(e, id) {
22363     },
22364
22365     onDragOut: function(e, id) {
22366     },
22367
22368     onDragDrop: function(e, id) {
22369     },
22370
22371     endDrag: function(e) {
22372     }
22373
22374     */
22375
22376 });/*
22377  * Based on:
22378  * Ext JS Library 1.1.1
22379  * Copyright(c) 2006-2007, Ext JS, LLC.
22380  *
22381  * Originally Released Under LGPL - original licence link has changed is not relivant.
22382  *
22383  * Fork - LGPL
22384  * <script type="text/javascript">
22385  */
22386
22387 /**
22388  * @class Roo.dd.DDProxy
22389  * A DragDrop implementation that inserts an empty, bordered div into
22390  * the document that follows the cursor during drag operations.  At the time of
22391  * the click, the frame div is resized to the dimensions of the linked html
22392  * element, and moved to the exact location of the linked element.
22393  *
22394  * References to the "frame" element refer to the single proxy element that
22395  * was created to be dragged in place of all DDProxy elements on the
22396  * page.
22397  *
22398  * @extends Roo.dd.DD
22399  * @constructor
22400  * @param {String} id the id of the linked html element
22401  * @param {String} sGroup the group of related DragDrop objects
22402  * @param {object} config an object containing configurable attributes
22403  *                Valid properties for DDProxy in addition to those in DragDrop:
22404  *                   resizeFrame, centerFrame, dragElId
22405  */
22406 Roo.dd.DDProxy = function(id, sGroup, config) {
22407     if (id) {
22408         this.init(id, sGroup, config);
22409         this.initFrame();
22410     }
22411 };
22412
22413 /**
22414  * The default drag frame div id
22415  * @property Roo.dd.DDProxy.dragElId
22416  * @type String
22417  * @static
22418  */
22419 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22420
22421 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22422
22423     /**
22424      * By default we resize the drag frame to be the same size as the element
22425      * we want to drag (this is to get the frame effect).  We can turn it off
22426      * if we want a different behavior.
22427      * @property resizeFrame
22428      * @type boolean
22429      */
22430     resizeFrame: true,
22431
22432     /**
22433      * By default the frame is positioned exactly where the drag element is, so
22434      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22435      * you do not have constraints on the obj is to have the drag frame centered
22436      * around the cursor.  Set centerFrame to true for this effect.
22437      * @property centerFrame
22438      * @type boolean
22439      */
22440     centerFrame: false,
22441
22442     /**
22443      * Creates the proxy element if it does not yet exist
22444      * @method createFrame
22445      */
22446     createFrame: function() {
22447         var self = this;
22448         var body = document.body;
22449
22450         if (!body || !body.firstChild) {
22451             setTimeout( function() { self.createFrame(); }, 50 );
22452             return;
22453         }
22454
22455         var div = this.getDragEl();
22456
22457         if (!div) {
22458             div    = document.createElement("div");
22459             div.id = this.dragElId;
22460             var s  = div.style;
22461
22462             s.position   = "absolute";
22463             s.visibility = "hidden";
22464             s.cursor     = "move";
22465             s.border     = "2px solid #aaa";
22466             s.zIndex     = 999;
22467
22468             // appendChild can blow up IE if invoked prior to the window load event
22469             // while rendering a table.  It is possible there are other scenarios
22470             // that would cause this to happen as well.
22471             body.insertBefore(div, body.firstChild);
22472         }
22473     },
22474
22475     /**
22476      * Initialization for the drag frame element.  Must be called in the
22477      * constructor of all subclasses
22478      * @method initFrame
22479      */
22480     initFrame: function() {
22481         this.createFrame();
22482     },
22483
22484     applyConfig: function() {
22485         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22486
22487         this.resizeFrame = (this.config.resizeFrame !== false);
22488         this.centerFrame = (this.config.centerFrame);
22489         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22490     },
22491
22492     /**
22493      * Resizes the drag frame to the dimensions of the clicked object, positions
22494      * it over the object, and finally displays it
22495      * @method showFrame
22496      * @param {int} iPageX X click position
22497      * @param {int} iPageY Y click position
22498      * @private
22499      */
22500     showFrame: function(iPageX, iPageY) {
22501         var el = this.getEl();
22502         var dragEl = this.getDragEl();
22503         var s = dragEl.style;
22504
22505         this._resizeProxy();
22506
22507         if (this.centerFrame) {
22508             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22509                            Math.round(parseInt(s.height, 10)/2) );
22510         }
22511
22512         this.setDragElPos(iPageX, iPageY);
22513
22514         Roo.fly(dragEl).show();
22515     },
22516
22517     /**
22518      * The proxy is automatically resized to the dimensions of the linked
22519      * element when a drag is initiated, unless resizeFrame is set to false
22520      * @method _resizeProxy
22521      * @private
22522      */
22523     _resizeProxy: function() {
22524         if (this.resizeFrame) {
22525             var el = this.getEl();
22526             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22527         }
22528     },
22529
22530     // overrides Roo.dd.DragDrop
22531     b4MouseDown: function(e) {
22532         var x = e.getPageX();
22533         var y = e.getPageY();
22534         this.autoOffset(x, y);
22535         this.setDragElPos(x, y);
22536     },
22537
22538     // overrides Roo.dd.DragDrop
22539     b4StartDrag: function(x, y) {
22540         // show the drag frame
22541         this.showFrame(x, y);
22542     },
22543
22544     // overrides Roo.dd.DragDrop
22545     b4EndDrag: function(e) {
22546         Roo.fly(this.getDragEl()).hide();
22547     },
22548
22549     // overrides Roo.dd.DragDrop
22550     // By default we try to move the element to the last location of the frame.
22551     // This is so that the default behavior mirrors that of Roo.dd.DD.
22552     endDrag: function(e) {
22553
22554         var lel = this.getEl();
22555         var del = this.getDragEl();
22556
22557         // Show the drag frame briefly so we can get its position
22558         del.style.visibility = "";
22559
22560         this.beforeMove();
22561         // Hide the linked element before the move to get around a Safari
22562         // rendering bug.
22563         lel.style.visibility = "hidden";
22564         Roo.dd.DDM.moveToEl(lel, del);
22565         del.style.visibility = "hidden";
22566         lel.style.visibility = "";
22567
22568         this.afterDrag();
22569     },
22570
22571     beforeMove : function(){
22572
22573     },
22574
22575     afterDrag : function(){
22576
22577     },
22578
22579     toString: function() {
22580         return ("DDProxy " + this.id);
22581     }
22582
22583 });
22584 /*
22585  * Based on:
22586  * Ext JS Library 1.1.1
22587  * Copyright(c) 2006-2007, Ext JS, LLC.
22588  *
22589  * Originally Released Under LGPL - original licence link has changed is not relivant.
22590  *
22591  * Fork - LGPL
22592  * <script type="text/javascript">
22593  */
22594
22595  /**
22596  * @class Roo.dd.DDTarget
22597  * A DragDrop implementation that does not move, but can be a drop
22598  * target.  You would get the same result by simply omitting implementation
22599  * for the event callbacks, but this way we reduce the processing cost of the
22600  * event listener and the callbacks.
22601  * @extends Roo.dd.DragDrop
22602  * @constructor
22603  * @param {String} id the id of the element that is a drop target
22604  * @param {String} sGroup the group of related DragDrop objects
22605  * @param {object} config an object containing configurable attributes
22606  *                 Valid properties for DDTarget in addition to those in
22607  *                 DragDrop:
22608  *                    none
22609  */
22610 Roo.dd.DDTarget = function(id, sGroup, config) {
22611     if (id) {
22612         this.initTarget(id, sGroup, config);
22613     }
22614     if (config && (config.listeners || config.events)) { 
22615         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22616             listeners : config.listeners || {}, 
22617             events : config.events || {} 
22618         });    
22619     }
22620 };
22621
22622 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22623 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22624     toString: function() {
22625         return ("DDTarget " + this.id);
22626     }
22627 });
22628 /*
22629  * Based on:
22630  * Ext JS Library 1.1.1
22631  * Copyright(c) 2006-2007, Ext JS, LLC.
22632  *
22633  * Originally Released Under LGPL - original licence link has changed is not relivant.
22634  *
22635  * Fork - LGPL
22636  * <script type="text/javascript">
22637  */
22638  
22639
22640 /**
22641  * @class Roo.dd.ScrollManager
22642  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22643  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22644  * @static
22645  */
22646 Roo.dd.ScrollManager = function(){
22647     var ddm = Roo.dd.DragDropMgr;
22648     var els = {};
22649     var dragEl = null;
22650     var proc = {};
22651     
22652     
22653     
22654     var onStop = function(e){
22655         dragEl = null;
22656         clearProc();
22657     };
22658     
22659     var triggerRefresh = function(){
22660         if(ddm.dragCurrent){
22661              ddm.refreshCache(ddm.dragCurrent.groups);
22662         }
22663     };
22664     
22665     var doScroll = function(){
22666         if(ddm.dragCurrent){
22667             var dds = Roo.dd.ScrollManager;
22668             if(!dds.animate){
22669                 if(proc.el.scroll(proc.dir, dds.increment)){
22670                     triggerRefresh();
22671                 }
22672             }else{
22673                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22674             }
22675         }
22676     };
22677     
22678     var clearProc = function(){
22679         if(proc.id){
22680             clearInterval(proc.id);
22681         }
22682         proc.id = 0;
22683         proc.el = null;
22684         proc.dir = "";
22685     };
22686     
22687     var startProc = function(el, dir){
22688          Roo.log('scroll startproc');
22689         clearProc();
22690         proc.el = el;
22691         proc.dir = dir;
22692         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22693     };
22694     
22695     var onFire = function(e, isDrop){
22696        
22697         if(isDrop || !ddm.dragCurrent){ return; }
22698         var dds = Roo.dd.ScrollManager;
22699         if(!dragEl || dragEl != ddm.dragCurrent){
22700             dragEl = ddm.dragCurrent;
22701             // refresh regions on drag start
22702             dds.refreshCache();
22703         }
22704         
22705         var xy = Roo.lib.Event.getXY(e);
22706         var pt = new Roo.lib.Point(xy[0], xy[1]);
22707         for(var id in els){
22708             var el = els[id], r = el._region;
22709             if(r && r.contains(pt) && el.isScrollable()){
22710                 if(r.bottom - pt.y <= dds.thresh){
22711                     if(proc.el != el){
22712                         startProc(el, "down");
22713                     }
22714                     return;
22715                 }else if(r.right - pt.x <= dds.thresh){
22716                     if(proc.el != el){
22717                         startProc(el, "left");
22718                     }
22719                     return;
22720                 }else if(pt.y - r.top <= dds.thresh){
22721                     if(proc.el != el){
22722                         startProc(el, "up");
22723                     }
22724                     return;
22725                 }else if(pt.x - r.left <= dds.thresh){
22726                     if(proc.el != el){
22727                         startProc(el, "right");
22728                     }
22729                     return;
22730                 }
22731             }
22732         }
22733         clearProc();
22734     };
22735     
22736     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22737     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22738     
22739     return {
22740         /**
22741          * Registers new overflow element(s) to auto scroll
22742          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22743          */
22744         register : function(el){
22745             if(el instanceof Array){
22746                 for(var i = 0, len = el.length; i < len; i++) {
22747                         this.register(el[i]);
22748                 }
22749             }else{
22750                 el = Roo.get(el);
22751                 els[el.id] = el;
22752             }
22753             Roo.dd.ScrollManager.els = els;
22754         },
22755         
22756         /**
22757          * Unregisters overflow element(s) so they are no longer scrolled
22758          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22759          */
22760         unregister : function(el){
22761             if(el instanceof Array){
22762                 for(var i = 0, len = el.length; i < len; i++) {
22763                         this.unregister(el[i]);
22764                 }
22765             }else{
22766                 el = Roo.get(el);
22767                 delete els[el.id];
22768             }
22769         },
22770         
22771         /**
22772          * The number of pixels from the edge of a container the pointer needs to be to 
22773          * trigger scrolling (defaults to 25)
22774          * @type Number
22775          */
22776         thresh : 25,
22777         
22778         /**
22779          * The number of pixels to scroll in each scroll increment (defaults to 50)
22780          * @type Number
22781          */
22782         increment : 100,
22783         
22784         /**
22785          * The frequency of scrolls in milliseconds (defaults to 500)
22786          * @type Number
22787          */
22788         frequency : 500,
22789         
22790         /**
22791          * True to animate the scroll (defaults to true)
22792          * @type Boolean
22793          */
22794         animate: true,
22795         
22796         /**
22797          * The animation duration in seconds - 
22798          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22799          * @type Number
22800          */
22801         animDuration: .4,
22802         
22803         /**
22804          * Manually trigger a cache refresh.
22805          */
22806         refreshCache : function(){
22807             for(var id in els){
22808                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22809                     els[id]._region = els[id].getRegion();
22810                 }
22811             }
22812         }
22813     };
22814 }();/*
22815  * Based on:
22816  * Ext JS Library 1.1.1
22817  * Copyright(c) 2006-2007, Ext JS, LLC.
22818  *
22819  * Originally Released Under LGPL - original licence link has changed is not relivant.
22820  *
22821  * Fork - LGPL
22822  * <script type="text/javascript">
22823  */
22824  
22825
22826 /**
22827  * @class Roo.dd.Registry
22828  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22829  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22830  * @static
22831  */
22832 Roo.dd.Registry = function(){
22833     var elements = {}; 
22834     var handles = {}; 
22835     var autoIdSeed = 0;
22836
22837     var getId = function(el, autogen){
22838         if(typeof el == "string"){
22839             return el;
22840         }
22841         var id = el.id;
22842         if(!id && autogen !== false){
22843             id = "roodd-" + (++autoIdSeed);
22844             el.id = id;
22845         }
22846         return id;
22847     };
22848     
22849     return {
22850     /**
22851      * Register a drag drop element
22852      * @param {String|HTMLElement} element The id or DOM node to register
22853      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22854      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22855      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22856      * populated in the data object (if applicable):
22857      * <pre>
22858 Value      Description<br />
22859 ---------  ------------------------------------------<br />
22860 handles    Array of DOM nodes that trigger dragging<br />
22861            for the element being registered<br />
22862 isHandle   True if the element passed in triggers<br />
22863            dragging itself, else false
22864 </pre>
22865      */
22866         register : function(el, data){
22867             data = data || {};
22868             if(typeof el == "string"){
22869                 el = document.getElementById(el);
22870             }
22871             data.ddel = el;
22872             elements[getId(el)] = data;
22873             if(data.isHandle !== false){
22874                 handles[data.ddel.id] = data;
22875             }
22876             if(data.handles){
22877                 var hs = data.handles;
22878                 for(var i = 0, len = hs.length; i < len; i++){
22879                         handles[getId(hs[i])] = data;
22880                 }
22881             }
22882         },
22883
22884     /**
22885      * Unregister a drag drop element
22886      * @param {String|HTMLElement}  element The id or DOM node to unregister
22887      */
22888         unregister : function(el){
22889             var id = getId(el, false);
22890             var data = elements[id];
22891             if(data){
22892                 delete elements[id];
22893                 if(data.handles){
22894                     var hs = data.handles;
22895                     for(var i = 0, len = hs.length; i < len; i++){
22896                         delete handles[getId(hs[i], false)];
22897                     }
22898                 }
22899             }
22900         },
22901
22902     /**
22903      * Returns the handle registered for a DOM Node by id
22904      * @param {String|HTMLElement} id The DOM node or id to look up
22905      * @return {Object} handle The custom handle data
22906      */
22907         getHandle : function(id){
22908             if(typeof id != "string"){ // must be element?
22909                 id = id.id;
22910             }
22911             return handles[id];
22912         },
22913
22914     /**
22915      * Returns the handle that is registered for the DOM node that is the target of the event
22916      * @param {Event} e The event
22917      * @return {Object} handle The custom handle data
22918      */
22919         getHandleFromEvent : function(e){
22920             var t = Roo.lib.Event.getTarget(e);
22921             return t ? handles[t.id] : null;
22922         },
22923
22924     /**
22925      * Returns a custom data object that is registered for a DOM node by id
22926      * @param {String|HTMLElement} id The DOM node or id to look up
22927      * @return {Object} data The custom data
22928      */
22929         getTarget : function(id){
22930             if(typeof id != "string"){ // must be element?
22931                 id = id.id;
22932             }
22933             return elements[id];
22934         },
22935
22936     /**
22937      * Returns a custom data object that is registered for the DOM node that is the target of the event
22938      * @param {Event} e The event
22939      * @return {Object} data The custom data
22940      */
22941         getTargetFromEvent : function(e){
22942             var t = Roo.lib.Event.getTarget(e);
22943             return t ? elements[t.id] || handles[t.id] : null;
22944         }
22945     };
22946 }();/*
22947  * Based on:
22948  * Ext JS Library 1.1.1
22949  * Copyright(c) 2006-2007, Ext JS, LLC.
22950  *
22951  * Originally Released Under LGPL - original licence link has changed is not relivant.
22952  *
22953  * Fork - LGPL
22954  * <script type="text/javascript">
22955  */
22956  
22957
22958 /**
22959  * @class Roo.dd.StatusProxy
22960  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22961  * default drag proxy used by all Roo.dd components.
22962  * @constructor
22963  * @param {Object} config
22964  */
22965 Roo.dd.StatusProxy = function(config){
22966     Roo.apply(this, config);
22967     this.id = this.id || Roo.id();
22968     this.el = new Roo.Layer({
22969         dh: {
22970             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22971                 {tag: "div", cls: "x-dd-drop-icon"},
22972                 {tag: "div", cls: "x-dd-drag-ghost"}
22973             ]
22974         }, 
22975         shadow: !config || config.shadow !== false
22976     });
22977     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22978     this.dropStatus = this.dropNotAllowed;
22979 };
22980
22981 Roo.dd.StatusProxy.prototype = {
22982     /**
22983      * @cfg {String} dropAllowed
22984      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22985      */
22986     dropAllowed : "x-dd-drop-ok",
22987     /**
22988      * @cfg {String} dropNotAllowed
22989      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22990      */
22991     dropNotAllowed : "x-dd-drop-nodrop",
22992
22993     /**
22994      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22995      * over the current target element.
22996      * @param {String} cssClass The css class for the new drop status indicator image
22997      */
22998     setStatus : function(cssClass){
22999         cssClass = cssClass || this.dropNotAllowed;
23000         if(this.dropStatus != cssClass){
23001             this.el.replaceClass(this.dropStatus, cssClass);
23002             this.dropStatus = cssClass;
23003         }
23004     },
23005
23006     /**
23007      * Resets the status indicator to the default dropNotAllowed value
23008      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23009      */
23010     reset : function(clearGhost){
23011         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23012         this.dropStatus = this.dropNotAllowed;
23013         if(clearGhost){
23014             this.ghost.update("");
23015         }
23016     },
23017
23018     /**
23019      * Updates the contents of the ghost element
23020      * @param {String} html The html that will replace the current innerHTML of the ghost element
23021      */
23022     update : function(html){
23023         if(typeof html == "string"){
23024             this.ghost.update(html);
23025         }else{
23026             this.ghost.update("");
23027             html.style.margin = "0";
23028             this.ghost.dom.appendChild(html);
23029         }
23030         // ensure float = none set?? cant remember why though.
23031         var el = this.ghost.dom.firstChild;
23032                 if(el){
23033                         Roo.fly(el).setStyle('float', 'none');
23034                 }
23035     },
23036     
23037     /**
23038      * Returns the underlying proxy {@link Roo.Layer}
23039      * @return {Roo.Layer} el
23040     */
23041     getEl : function(){
23042         return this.el;
23043     },
23044
23045     /**
23046      * Returns the ghost element
23047      * @return {Roo.Element} el
23048      */
23049     getGhost : function(){
23050         return this.ghost;
23051     },
23052
23053     /**
23054      * Hides the proxy
23055      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23056      */
23057     hide : function(clear){
23058         this.el.hide();
23059         if(clear){
23060             this.reset(true);
23061         }
23062     },
23063
23064     /**
23065      * Stops the repair animation if it's currently running
23066      */
23067     stop : function(){
23068         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23069             this.anim.stop();
23070         }
23071     },
23072
23073     /**
23074      * Displays this proxy
23075      */
23076     show : function(){
23077         this.el.show();
23078     },
23079
23080     /**
23081      * Force the Layer to sync its shadow and shim positions to the element
23082      */
23083     sync : function(){
23084         this.el.sync();
23085     },
23086
23087     /**
23088      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23089      * invalid drop operation by the item being dragged.
23090      * @param {Array} xy The XY position of the element ([x, y])
23091      * @param {Function} callback The function to call after the repair is complete
23092      * @param {Object} scope The scope in which to execute the callback
23093      */
23094     repair : function(xy, callback, scope){
23095         this.callback = callback;
23096         this.scope = scope;
23097         if(xy && this.animRepair !== false){
23098             this.el.addClass("x-dd-drag-repair");
23099             this.el.hideUnders(true);
23100             this.anim = this.el.shift({
23101                 duration: this.repairDuration || .5,
23102                 easing: 'easeOut',
23103                 xy: xy,
23104                 stopFx: true,
23105                 callback: this.afterRepair,
23106                 scope: this
23107             });
23108         }else{
23109             this.afterRepair();
23110         }
23111     },
23112
23113     // private
23114     afterRepair : function(){
23115         this.hide(true);
23116         if(typeof this.callback == "function"){
23117             this.callback.call(this.scope || this);
23118         }
23119         this.callback = null;
23120         this.scope = null;
23121     }
23122 };/*
23123  * Based on:
23124  * Ext JS Library 1.1.1
23125  * Copyright(c) 2006-2007, Ext JS, LLC.
23126  *
23127  * Originally Released Under LGPL - original licence link has changed is not relivant.
23128  *
23129  * Fork - LGPL
23130  * <script type="text/javascript">
23131  */
23132
23133 /**
23134  * @class Roo.dd.DragSource
23135  * @extends Roo.dd.DDProxy
23136  * A simple class that provides the basic implementation needed to make any element draggable.
23137  * @constructor
23138  * @param {String/HTMLElement/Element} el The container element
23139  * @param {Object} config
23140  */
23141 Roo.dd.DragSource = function(el, config){
23142     this.el = Roo.get(el);
23143     this.dragData = {};
23144     
23145     Roo.apply(this, config);
23146     
23147     if(!this.proxy){
23148         this.proxy = new Roo.dd.StatusProxy();
23149     }
23150
23151     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23152           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23153     
23154     this.dragging = false;
23155 };
23156
23157 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23158     /**
23159      * @cfg {String} dropAllowed
23160      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23161      */
23162     dropAllowed : "x-dd-drop-ok",
23163     /**
23164      * @cfg {String} dropNotAllowed
23165      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23166      */
23167     dropNotAllowed : "x-dd-drop-nodrop",
23168
23169     /**
23170      * Returns the data object associated with this drag source
23171      * @return {Object} data An object containing arbitrary data
23172      */
23173     getDragData : function(e){
23174         return this.dragData;
23175     },
23176
23177     // private
23178     onDragEnter : function(e, id){
23179         var target = Roo.dd.DragDropMgr.getDDById(id);
23180         this.cachedTarget = target;
23181         if(this.beforeDragEnter(target, e, id) !== false){
23182             if(target.isNotifyTarget){
23183                 var status = target.notifyEnter(this, e, this.dragData);
23184                 this.proxy.setStatus(status);
23185             }else{
23186                 this.proxy.setStatus(this.dropAllowed);
23187             }
23188             
23189             if(this.afterDragEnter){
23190                 /**
23191                  * An empty function by default, but provided so that you can perform a custom action
23192                  * when the dragged item enters the drop target by providing an implementation.
23193                  * @param {Roo.dd.DragDrop} target The drop target
23194                  * @param {Event} e The event object
23195                  * @param {String} id The id of the dragged element
23196                  * @method afterDragEnter
23197                  */
23198                 this.afterDragEnter(target, e, id);
23199             }
23200         }
23201     },
23202
23203     /**
23204      * An empty function by default, but provided so that you can perform a custom action
23205      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23206      * @param {Roo.dd.DragDrop} target The drop target
23207      * @param {Event} e The event object
23208      * @param {String} id The id of the dragged element
23209      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23210      */
23211     beforeDragEnter : function(target, e, id){
23212         return true;
23213     },
23214
23215     // private
23216     alignElWithMouse: function() {
23217         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23218         this.proxy.sync();
23219     },
23220
23221     // private
23222     onDragOver : function(e, id){
23223         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23224         if(this.beforeDragOver(target, e, id) !== false){
23225             if(target.isNotifyTarget){
23226                 var status = target.notifyOver(this, e, this.dragData);
23227                 this.proxy.setStatus(status);
23228             }
23229
23230             if(this.afterDragOver){
23231                 /**
23232                  * An empty function by default, but provided so that you can perform a custom action
23233                  * while the dragged item is over the drop target by providing an implementation.
23234                  * @param {Roo.dd.DragDrop} target The drop target
23235                  * @param {Event} e The event object
23236                  * @param {String} id The id of the dragged element
23237                  * @method afterDragOver
23238                  */
23239                 this.afterDragOver(target, e, id);
23240             }
23241         }
23242     },
23243
23244     /**
23245      * An empty function by default, but provided so that you can perform a custom action
23246      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23247      * @param {Roo.dd.DragDrop} target The drop target
23248      * @param {Event} e The event object
23249      * @param {String} id The id of the dragged element
23250      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23251      */
23252     beforeDragOver : function(target, e, id){
23253         return true;
23254     },
23255
23256     // private
23257     onDragOut : function(e, id){
23258         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23259         if(this.beforeDragOut(target, e, id) !== false){
23260             if(target.isNotifyTarget){
23261                 target.notifyOut(this, e, this.dragData);
23262             }
23263             this.proxy.reset();
23264             if(this.afterDragOut){
23265                 /**
23266                  * An empty function by default, but provided so that you can perform a custom action
23267                  * after the dragged item is dragged out of the target without dropping.
23268                  * @param {Roo.dd.DragDrop} target The drop target
23269                  * @param {Event} e The event object
23270                  * @param {String} id The id of the dragged element
23271                  * @method afterDragOut
23272                  */
23273                 this.afterDragOut(target, e, id);
23274             }
23275         }
23276         this.cachedTarget = null;
23277     },
23278
23279     /**
23280      * An empty function by default, but provided so that you can perform a custom action before the dragged
23281      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23282      * @param {Roo.dd.DragDrop} target The drop target
23283      * @param {Event} e The event object
23284      * @param {String} id The id of the dragged element
23285      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23286      */
23287     beforeDragOut : function(target, e, id){
23288         return true;
23289     },
23290     
23291     // private
23292     onDragDrop : function(e, id){
23293         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23294         if(this.beforeDragDrop(target, e, id) !== false){
23295             if(target.isNotifyTarget){
23296                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23297                     this.onValidDrop(target, e, id);
23298                 }else{
23299                     this.onInvalidDrop(target, e, id);
23300                 }
23301             }else{
23302                 this.onValidDrop(target, e, id);
23303             }
23304             
23305             if(this.afterDragDrop){
23306                 /**
23307                  * An empty function by default, but provided so that you can perform a custom action
23308                  * after a valid drag drop has occurred by providing an implementation.
23309                  * @param {Roo.dd.DragDrop} target The drop target
23310                  * @param {Event} e The event object
23311                  * @param {String} id The id of the dropped element
23312                  * @method afterDragDrop
23313                  */
23314                 this.afterDragDrop(target, e, id);
23315             }
23316         }
23317         delete this.cachedTarget;
23318     },
23319
23320     /**
23321      * An empty function by default, but provided so that you can perform a custom action before the dragged
23322      * item is dropped onto the target and optionally cancel the onDragDrop.
23323      * @param {Roo.dd.DragDrop} target The drop target
23324      * @param {Event} e The event object
23325      * @param {String} id The id of the dragged element
23326      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23327      */
23328     beforeDragDrop : function(target, e, id){
23329         return true;
23330     },
23331
23332     // private
23333     onValidDrop : function(target, e, id){
23334         this.hideProxy();
23335         if(this.afterValidDrop){
23336             /**
23337              * An empty function by default, but provided so that you can perform a custom action
23338              * after a valid drop has occurred by providing an implementation.
23339              * @param {Object} target The target DD 
23340              * @param {Event} e The event object
23341              * @param {String} id The id of the dropped element
23342              * @method afterInvalidDrop
23343              */
23344             this.afterValidDrop(target, e, id);
23345         }
23346     },
23347
23348     // private
23349     getRepairXY : function(e, data){
23350         return this.el.getXY();  
23351     },
23352
23353     // private
23354     onInvalidDrop : function(target, e, id){
23355         this.beforeInvalidDrop(target, e, id);
23356         if(this.cachedTarget){
23357             if(this.cachedTarget.isNotifyTarget){
23358                 this.cachedTarget.notifyOut(this, e, this.dragData);
23359             }
23360             this.cacheTarget = null;
23361         }
23362         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23363
23364         if(this.afterInvalidDrop){
23365             /**
23366              * An empty function by default, but provided so that you can perform a custom action
23367              * after an invalid drop has occurred by providing an implementation.
23368              * @param {Event} e The event object
23369              * @param {String} id The id of the dropped element
23370              * @method afterInvalidDrop
23371              */
23372             this.afterInvalidDrop(e, id);
23373         }
23374     },
23375
23376     // private
23377     afterRepair : function(){
23378         if(Roo.enableFx){
23379             this.el.highlight(this.hlColor || "c3daf9");
23380         }
23381         this.dragging = false;
23382     },
23383
23384     /**
23385      * An empty function by default, but provided so that you can perform a custom action after an invalid
23386      * drop has occurred.
23387      * @param {Roo.dd.DragDrop} target The drop target
23388      * @param {Event} e The event object
23389      * @param {String} id The id of the dragged element
23390      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23391      */
23392     beforeInvalidDrop : function(target, e, id){
23393         return true;
23394     },
23395
23396     // private
23397     handleMouseDown : function(e){
23398         if(this.dragging) {
23399             return;
23400         }
23401         var data = this.getDragData(e);
23402         if(data && this.onBeforeDrag(data, e) !== false){
23403             this.dragData = data;
23404             this.proxy.stop();
23405             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23406         } 
23407     },
23408
23409     /**
23410      * An empty function by default, but provided so that you can perform a custom action before the initial
23411      * drag event begins and optionally cancel it.
23412      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23413      * @param {Event} e The event object
23414      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23415      */
23416     onBeforeDrag : function(data, e){
23417         return true;
23418     },
23419
23420     /**
23421      * An empty function by default, but provided so that you can perform a custom action once the initial
23422      * drag event has begun.  The drag cannot be canceled from this function.
23423      * @param {Number} x The x position of the click on the dragged object
23424      * @param {Number} y The y position of the click on the dragged object
23425      */
23426     onStartDrag : Roo.emptyFn,
23427
23428     // private - YUI override
23429     startDrag : function(x, y){
23430         this.proxy.reset();
23431         this.dragging = true;
23432         this.proxy.update("");
23433         this.onInitDrag(x, y);
23434         this.proxy.show();
23435     },
23436
23437     // private
23438     onInitDrag : function(x, y){
23439         var clone = this.el.dom.cloneNode(true);
23440         clone.id = Roo.id(); // prevent duplicate ids
23441         this.proxy.update(clone);
23442         this.onStartDrag(x, y);
23443         return true;
23444     },
23445
23446     /**
23447      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23448      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23449      */
23450     getProxy : function(){
23451         return this.proxy;  
23452     },
23453
23454     /**
23455      * Hides the drag source's {@link Roo.dd.StatusProxy}
23456      */
23457     hideProxy : function(){
23458         this.proxy.hide();  
23459         this.proxy.reset(true);
23460         this.dragging = false;
23461     },
23462
23463     // private
23464     triggerCacheRefresh : function(){
23465         Roo.dd.DDM.refreshCache(this.groups);
23466     },
23467
23468     // private - override to prevent hiding
23469     b4EndDrag: function(e) {
23470     },
23471
23472     // private - override to prevent moving
23473     endDrag : function(e){
23474         this.onEndDrag(this.dragData, e);
23475     },
23476
23477     // private
23478     onEndDrag : function(data, e){
23479     },
23480     
23481     // private - pin to cursor
23482     autoOffset : function(x, y) {
23483         this.setDelta(-12, -20);
23484     }    
23485 });/*
23486  * Based on:
23487  * Ext JS Library 1.1.1
23488  * Copyright(c) 2006-2007, Ext JS, LLC.
23489  *
23490  * Originally Released Under LGPL - original licence link has changed is not relivant.
23491  *
23492  * Fork - LGPL
23493  * <script type="text/javascript">
23494  */
23495
23496
23497 /**
23498  * @class Roo.dd.DropTarget
23499  * @extends Roo.dd.DDTarget
23500  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23501  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23502  * @constructor
23503  * @param {String/HTMLElement/Element} el The container element
23504  * @param {Object} config
23505  */
23506 Roo.dd.DropTarget = function(el, config){
23507     this.el = Roo.get(el);
23508     
23509     var listeners = false; ;
23510     if (config && config.listeners) {
23511         listeners= config.listeners;
23512         delete config.listeners;
23513     }
23514     Roo.apply(this, config);
23515     
23516     if(this.containerScroll){
23517         Roo.dd.ScrollManager.register(this.el);
23518     }
23519     this.addEvents( {
23520          /**
23521          * @scope Roo.dd.DropTarget
23522          */
23523          
23524          /**
23525          * @event enter
23526          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23527          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23528          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23529          * 
23530          * IMPORTANT : it should set  this.valid to true|false
23531          * 
23532          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23533          * @param {Event} e The event
23534          * @param {Object} data An object containing arbitrary data supplied by the drag source
23535          */
23536         "enter" : true,
23537         
23538          /**
23539          * @event over
23540          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23541          * This method will be called on every mouse movement while the drag source is over the drop target.
23542          * This default implementation simply returns the dropAllowed config value.
23543          * 
23544          * IMPORTANT : it should set  this.valid to true|false
23545          * 
23546          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23547          * @param {Event} e The event
23548          * @param {Object} data An object containing arbitrary data supplied by the drag source
23549          
23550          */
23551         "over" : true,
23552         /**
23553          * @event out
23554          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23555          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23556          * overClass (if any) from the drop element.
23557          * 
23558          * 
23559          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23560          * @param {Event} e The event
23561          * @param {Object} data An object containing arbitrary data supplied by the drag source
23562          */
23563          "out" : true,
23564          
23565         /**
23566          * @event drop
23567          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23568          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23569          * implementation that does something to process the drop event and returns true so that the drag source's
23570          * repair action does not run.
23571          * 
23572          * IMPORTANT : it should set this.success
23573          * 
23574          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23575          * @param {Event} e The event
23576          * @param {Object} data An object containing arbitrary data supplied by the drag source
23577         */
23578          "drop" : true
23579     });
23580             
23581      
23582     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23583         this.el.dom, 
23584         this.ddGroup || this.group,
23585         {
23586             isTarget: true,
23587             listeners : listeners || {} 
23588            
23589         
23590         }
23591     );
23592
23593 };
23594
23595 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23596     /**
23597      * @cfg {String} overClass
23598      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23599      */
23600      /**
23601      * @cfg {String} ddGroup
23602      * The drag drop group to handle drop events for
23603      */
23604      
23605     /**
23606      * @cfg {String} dropAllowed
23607      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23608      */
23609     dropAllowed : "x-dd-drop-ok",
23610     /**
23611      * @cfg {String} dropNotAllowed
23612      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23613      */
23614     dropNotAllowed : "x-dd-drop-nodrop",
23615     /**
23616      * @cfg {boolean} success
23617      * set this after drop listener.. 
23618      */
23619     success : false,
23620     /**
23621      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23622      * if the drop point is valid for over/enter..
23623      */
23624     valid : false,
23625     // private
23626     isTarget : true,
23627
23628     // private
23629     isNotifyTarget : true,
23630     
23631     /**
23632      * @hide
23633      */
23634     notifyEnter : function(dd, e, data)
23635     {
23636         this.valid = true;
23637         this.fireEvent('enter', dd, e, data);
23638         if(this.overClass){
23639             this.el.addClass(this.overClass);
23640         }
23641         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23642             this.valid ? this.dropAllowed : this.dropNotAllowed
23643         );
23644     },
23645
23646     /**
23647      * @hide
23648      */
23649     notifyOver : function(dd, e, data)
23650     {
23651         this.valid = true;
23652         this.fireEvent('over', dd, e, data);
23653         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23654             this.valid ? this.dropAllowed : this.dropNotAllowed
23655         );
23656     },
23657
23658     /**
23659      * @hide
23660      */
23661     notifyOut : function(dd, e, data)
23662     {
23663         this.fireEvent('out', dd, e, data);
23664         if(this.overClass){
23665             this.el.removeClass(this.overClass);
23666         }
23667     },
23668
23669     /**
23670      * @hide
23671      */
23672     notifyDrop : function(dd, e, data)
23673     {
23674         this.success = false;
23675         this.fireEvent('drop', dd, e, data);
23676         return this.success;
23677     }
23678 });/*
23679  * Based on:
23680  * Ext JS Library 1.1.1
23681  * Copyright(c) 2006-2007, Ext JS, LLC.
23682  *
23683  * Originally Released Under LGPL - original licence link has changed is not relivant.
23684  *
23685  * Fork - LGPL
23686  * <script type="text/javascript">
23687  */
23688
23689
23690 /**
23691  * @class Roo.dd.DragZone
23692  * @extends Roo.dd.DragSource
23693  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23694  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23695  * @constructor
23696  * @param {String/HTMLElement/Element} el The container element
23697  * @param {Object} config
23698  */
23699 Roo.dd.DragZone = function(el, config){
23700     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23701     if(this.containerScroll){
23702         Roo.dd.ScrollManager.register(this.el);
23703     }
23704 };
23705
23706 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23707     /**
23708      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23709      * for auto scrolling during drag operations.
23710      */
23711     /**
23712      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23713      * method after a failed drop (defaults to "c3daf9" - light blue)
23714      */
23715
23716     /**
23717      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23718      * for a valid target to drag based on the mouse down. Override this method
23719      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23720      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23721      * @param {EventObject} e The mouse down event
23722      * @return {Object} The dragData
23723      */
23724     getDragData : function(e){
23725         return Roo.dd.Registry.getHandleFromEvent(e);
23726     },
23727     
23728     /**
23729      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23730      * this.dragData.ddel
23731      * @param {Number} x The x position of the click on the dragged object
23732      * @param {Number} y The y position of the click on the dragged object
23733      * @return {Boolean} true to continue the drag, false to cancel
23734      */
23735     onInitDrag : function(x, y){
23736         this.proxy.update(this.dragData.ddel.cloneNode(true));
23737         this.onStartDrag(x, y);
23738         return true;
23739     },
23740     
23741     /**
23742      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23743      */
23744     afterRepair : function(){
23745         if(Roo.enableFx){
23746             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23747         }
23748         this.dragging = false;
23749     },
23750
23751     /**
23752      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23753      * the XY of this.dragData.ddel
23754      * @param {EventObject} e The mouse up event
23755      * @return {Array} The xy location (e.g. [100, 200])
23756      */
23757     getRepairXY : function(e){
23758         return Roo.Element.fly(this.dragData.ddel).getXY();  
23759     }
23760 });/*
23761  * Based on:
23762  * Ext JS Library 1.1.1
23763  * Copyright(c) 2006-2007, Ext JS, LLC.
23764  *
23765  * Originally Released Under LGPL - original licence link has changed is not relivant.
23766  *
23767  * Fork - LGPL
23768  * <script type="text/javascript">
23769  */
23770 /**
23771  * @class Roo.dd.DropZone
23772  * @extends Roo.dd.DropTarget
23773  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23774  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23775  * @constructor
23776  * @param {String/HTMLElement/Element} el The container element
23777  * @param {Object} config
23778  */
23779 Roo.dd.DropZone = function(el, config){
23780     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23781 };
23782
23783 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23784     /**
23785      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23786      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23787      * provide your own custom lookup.
23788      * @param {Event} e The event
23789      * @return {Object} data The custom data
23790      */
23791     getTargetFromEvent : function(e){
23792         return Roo.dd.Registry.getTargetFromEvent(e);
23793     },
23794
23795     /**
23796      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23797      * that it has registered.  This method has no default implementation and should be overridden to provide
23798      * node-specific processing if necessary.
23799      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23800      * {@link #getTargetFromEvent} for this node)
23801      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23802      * @param {Event} e The event
23803      * @param {Object} data An object containing arbitrary data supplied by the drag source
23804      */
23805     onNodeEnter : function(n, dd, e, data){
23806         
23807     },
23808
23809     /**
23810      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23811      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23812      * overridden to provide the proper feedback.
23813      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23814      * {@link #getTargetFromEvent} for this node)
23815      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23816      * @param {Event} e The event
23817      * @param {Object} data An object containing arbitrary data supplied by the drag source
23818      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23819      * underlying {@link Roo.dd.StatusProxy} can be updated
23820      */
23821     onNodeOver : function(n, dd, e, data){
23822         return this.dropAllowed;
23823     },
23824
23825     /**
23826      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23827      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23828      * node-specific processing if necessary.
23829      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23830      * {@link #getTargetFromEvent} for this node)
23831      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23832      * @param {Event} e The event
23833      * @param {Object} data An object containing arbitrary data supplied by the drag source
23834      */
23835     onNodeOut : function(n, dd, e, data){
23836         
23837     },
23838
23839     /**
23840      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23841      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23842      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23843      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23844      * {@link #getTargetFromEvent} for this node)
23845      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23846      * @param {Event} e The event
23847      * @param {Object} data An object containing arbitrary data supplied by the drag source
23848      * @return {Boolean} True if the drop was valid, else false
23849      */
23850     onNodeDrop : function(n, dd, e, data){
23851         return false;
23852     },
23853
23854     /**
23855      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23856      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23857      * it should be overridden to provide the proper feedback if necessary.
23858      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23859      * @param {Event} e The event
23860      * @param {Object} data An object containing arbitrary data supplied by the drag source
23861      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23862      * underlying {@link Roo.dd.StatusProxy} can be updated
23863      */
23864     onContainerOver : function(dd, e, data){
23865         return this.dropNotAllowed;
23866     },
23867
23868     /**
23869      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23870      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23871      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23872      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23873      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23874      * @param {Event} e The event
23875      * @param {Object} data An object containing arbitrary data supplied by the drag source
23876      * @return {Boolean} True if the drop was valid, else false
23877      */
23878     onContainerDrop : function(dd, e, data){
23879         return false;
23880     },
23881
23882     /**
23883      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23884      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23885      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23886      * you should override this method and provide a custom implementation.
23887      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23888      * @param {Event} e The event
23889      * @param {Object} data An object containing arbitrary data supplied by the drag source
23890      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23891      * underlying {@link Roo.dd.StatusProxy} can be updated
23892      */
23893     notifyEnter : function(dd, e, data){
23894         return this.dropNotAllowed;
23895     },
23896
23897     /**
23898      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23899      * This method will be called on every mouse movement while the drag source is over the drop zone.
23900      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23901      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23902      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23903      * registered node, it will call {@link #onContainerOver}.
23904      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23905      * @param {Event} e The event
23906      * @param {Object} data An object containing arbitrary data supplied by the drag source
23907      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23908      * underlying {@link Roo.dd.StatusProxy} can be updated
23909      */
23910     notifyOver : function(dd, e, data){
23911         var n = this.getTargetFromEvent(e);
23912         if(!n){ // not over valid drop target
23913             if(this.lastOverNode){
23914                 this.onNodeOut(this.lastOverNode, dd, e, data);
23915                 this.lastOverNode = null;
23916             }
23917             return this.onContainerOver(dd, e, data);
23918         }
23919         if(this.lastOverNode != n){
23920             if(this.lastOverNode){
23921                 this.onNodeOut(this.lastOverNode, dd, e, data);
23922             }
23923             this.onNodeEnter(n, dd, e, data);
23924             this.lastOverNode = n;
23925         }
23926         return this.onNodeOver(n, dd, e, data);
23927     },
23928
23929     /**
23930      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23931      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23932      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23933      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23934      * @param {Event} e The event
23935      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23936      */
23937     notifyOut : function(dd, e, data){
23938         if(this.lastOverNode){
23939             this.onNodeOut(this.lastOverNode, dd, e, data);
23940             this.lastOverNode = null;
23941         }
23942     },
23943
23944     /**
23945      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23946      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23947      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23948      * otherwise it will call {@link #onContainerDrop}.
23949      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23950      * @param {Event} e The event
23951      * @param {Object} data An object containing arbitrary data supplied by the drag source
23952      * @return {Boolean} True if the drop was valid, else false
23953      */
23954     notifyDrop : function(dd, e, data){
23955         if(this.lastOverNode){
23956             this.onNodeOut(this.lastOverNode, dd, e, data);
23957             this.lastOverNode = null;
23958         }
23959         var n = this.getTargetFromEvent(e);
23960         return n ?
23961             this.onNodeDrop(n, dd, e, data) :
23962             this.onContainerDrop(dd, e, data);
23963     },
23964
23965     // private
23966     triggerCacheRefresh : function(){
23967         Roo.dd.DDM.refreshCache(this.groups);
23968     }  
23969 });