Roo/util/Observable.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 } 
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957
958 /**
959   * Make the first letter of a string uppercase
960   *
961   * @return {String} The new string.
962   */
963 String.prototype.toUpperCaseFirst = function () {
964     return this.charAt(0).toUpperCase() + this.slice(1);
965 };  
966   
967 /*
968  * Based on:
969  * Ext JS Library 1.1.1
970  * Copyright(c) 2006-2007, Ext JS, LLC.
971  *
972  * Originally Released Under LGPL - original licence link has changed is not relivant.
973  *
974  * Fork - LGPL
975  * <script type="text/javascript">
976  */
977
978  /**
979  * @class Number
980  */
981 Roo.applyIf(Number.prototype, {
982     /**
983      * Checks whether or not the current number is within a desired range.  If the number is already within the
984      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985      * exceeded.  Note that this method returns the constrained value but does not change the current number.
986      * @param {Number} min The minimum number in the range
987      * @param {Number} max The maximum number in the range
988      * @return {Number} The constrained value if outside the range, otherwise the current value
989      */
990     constrain : function(min, max){
991         return Math.min(Math.max(this, min), max);
992     }
993 });/*
994  * Based on:
995  * Ext JS Library 1.1.1
996  * Copyright(c) 2006-2007, Ext JS, LLC.
997  *
998  * Originally Released Under LGPL - original licence link has changed is not relivant.
999  *
1000  * Fork - LGPL
1001  * <script type="text/javascript">
1002  */
1003  /**
1004  * @class Array
1005  */
1006 Roo.applyIf(Array.prototype, {
1007     /**
1008      * 
1009      * Checks whether or not the specified object exists in the array.
1010      * @param {Object} o The object to check for
1011      * @return {Number} The index of o in the array (or -1 if it is not found)
1012      */
1013     indexOf : function(o){
1014        for (var i = 0, len = this.length; i < len; i++){
1015               if(this[i] == o) { return i; }
1016        }
1017            return -1;
1018     },
1019
1020     /**
1021      * Removes the specified object from the array.  If the object is not found nothing happens.
1022      * @param {Object} o The object to remove
1023      */
1024     remove : function(o){
1025        var index = this.indexOf(o);
1026        if(index != -1){
1027            this.splice(index, 1);
1028        }
1029     },
1030     /**
1031      * Map (JS 1.6 compatibility)
1032      * @param {Function} function  to call
1033      */
1034     map : function(fun )
1035     {
1036         var len = this.length >>> 0;
1037         if (typeof fun != "function") {
1038             throw new TypeError();
1039         }
1040         var res = new Array(len);
1041         var thisp = arguments[1];
1042         for (var i = 0; i < len; i++)
1043         {
1044             if (i in this) {
1045                 res[i] = fun.call(thisp, this[i], i, this);
1046             }
1047         }
1048
1049         return res;
1050     },
1051     /**
1052      * equals
1053      * @param {Array} o The array to compare to
1054      * @returns {Boolean} true if the same
1055      */
1056     equals : function(b)
1057     {
1058             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1059         if (this === b) {
1060             return true;
1061         }
1062         if (b == null) {
1063             return false;
1064         }
1065         if (this.length !== b.length) {
1066             return false;
1067         }
1068           
1069         // sort?? a.sort().equals(b.sort());
1070           
1071         for (var i = 0; i < this.length; ++i) {
1072             if (this[i] !== b[i]) {
1073             return false;
1074             }
1075         }
1076         return true;
1077     } 
1078     
1079     
1080     
1081     
1082 });
1083
1084 Roo.applyIf(Array, {
1085  /**
1086      * from
1087      * @static
1088      * @param {Array} o Or Array like object (eg. nodelist)
1089      * @returns {Array} 
1090      */
1091     from : function(o)
1092     {
1093         var ret= [];
1094     
1095         for (var i =0; i < o.length; i++) { 
1096             ret[i] = o[i];
1097         }
1098         return ret;
1099       
1100     }
1101 });
1102 /*
1103  * Based on:
1104  * Ext JS Library 1.1.1
1105  * Copyright(c) 2006-2007, Ext JS, LLC.
1106  *
1107  * Originally Released Under LGPL - original licence link has changed is not relivant.
1108  *
1109  * Fork - LGPL
1110  * <script type="text/javascript">
1111  */
1112
1113 /**
1114  * @class Date
1115  *
1116  * The date parsing and format syntax is a subset of
1117  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118  * supported will provide results equivalent to their PHP versions.
1119  *
1120  * Following is the list of all currently supported formats:
1121  *<pre>
1122 Sample date:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1124
1125 Format  Output      Description
1126 ------  ----------  --------------------------------------------------------------
1127   d      10         Day of the month, 2 digits with leading zeros
1128   D      Wed        A textual representation of a day, three letters
1129   j      10         Day of the month without leading zeros
1130   l      Wednesday  A full textual representation of the day of the week
1131   S      th         English ordinal day of month suffix, 2 chars (use with j)
1132   w      3          Numeric representation of the day of the week
1133   z      9          The julian date, or day of the year (0-365)
1134   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135   F      January    A full textual representation of the month
1136   m      01         Numeric representation of a month, with leading zeros
1137   M      Jan        Month name abbreviation, three letters
1138   n      1          Numeric representation of a month, without leading zeros
1139   t      31         Number of days in the given month
1140   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1141   Y      2007       A full numeric representation of a year, 4 digits
1142   y      07         A two digit representation of a year
1143   a      pm         Lowercase Ante meridiem and Post meridiem
1144   A      PM         Uppercase Ante meridiem and Post meridiem
1145   g      3          12-hour format of an hour without leading zeros
1146   G      15         24-hour format of an hour without leading zeros
1147   h      03         12-hour format of an hour with leading zeros
1148   H      15         24-hour format of an hour with leading zeros
1149   i      05         Minutes with leading zeros
1150   s      01         Seconds, with leading zeros
1151   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1153   T      CST        Timezone setting of the machine running the code
1154   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1155 </pre>
1156  *
1157  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1158  * <pre><code>
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d'));                         //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1162 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1163  </code></pre>
1164  *
1165  * Here are some standard date/time patterns that you might find helpful.  They
1166  * are not part of the source of Date.js, but to use them you can simply copy this
1167  * block of code into any script that is included after Date.js and they will also become
1168  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1169  * <pre><code>
1170 Date.patterns = {
1171     ISO8601Long:"Y-m-d H:i:s",
1172     ISO8601Short:"Y-m-d",
1173     ShortDate: "n/j/Y",
1174     LongDate: "l, F d, Y",
1175     FullDateTime: "l, F d, Y g:i:s A",
1176     MonthDay: "F d",
1177     ShortTime: "g:i A",
1178     LongTime: "g:i:s A",
1179     SortableDateTime: "Y-m-d\\TH:i:s",
1180     UniversalSortableDateTime: "Y-m-d H:i:sO",
1181     YearMonth: "F, Y"
1182 };
1183 </code></pre>
1184  *
1185  * Example usage:
1186  * <pre><code>
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1189  </code></pre>
1190  */
1191
1192 /*
1193  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194  * They generate precompiled functions from date formats instead of parsing and
1195  * processing the pattern every time you format a date.  These functions are available
1196  * on every Date object (any javascript function).
1197  *
1198  * The original article and download are here:
1199  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1200  *
1201  */
1202  
1203  
1204  // was in core
1205 /**
1206  Returns the number of milliseconds between this date and date
1207  @param {Date} date (optional) Defaults to now
1208  @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY) 
1209  @return {Number} The diff in milliseconds or units of interval
1210  @member Date getElapsed
1211  */
1212 Date.prototype.getElapsed = function(date, interval)
1213 {
1214     date = date ||  new Date();
1215     var ret = Math.abs(date.getTime()-this.getTime());
1216     switch (interval) {
1217        
1218         case  Date.SECOND:
1219             return Math.floor(ret / (1000));
1220         case  Date.MINUTE:
1221             return Math.floor(ret / (1000*60));
1222         case  Date.HOUR:
1223             return Math.floor(ret / (1000*60*60));
1224         case  Date.DAY:
1225             return Math.floor(ret / (1000*60*60*24));
1226         case  Date.MONTH: // this does not give exact number...??
1227             return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1228         case  Date.YEAR: // this does not give exact number...??
1229             return (date.format("Y") - this.format("Y"));
1230        
1231         case  Date.MILLI:
1232         default:
1233             return ret;
1234     }
1235 };
1236  
1237 // was in date file..
1238
1239
1240 // private
1241 Date.parseFunctions = {count:0};
1242 // private
1243 Date.parseRegexes = [];
1244 // private
1245 Date.formatFunctions = {count:0};
1246
1247 // private
1248 Date.prototype.dateFormat = function(format) {
1249     if (Date.formatFunctions[format] == null) {
1250         Date.createNewFormat(format);
1251     }
1252     var func = Date.formatFunctions[format];
1253     return this[func]();
1254 };
1255
1256
1257 /**
1258  * Formats a date given the supplied format string
1259  * @param {String} format The format string
1260  * @return {String} The formatted date
1261  * @method
1262  */
1263 Date.prototype.format = Date.prototype.dateFormat;
1264
1265 // private
1266 Date.createNewFormat = function(format) {
1267     var funcName = "format" + Date.formatFunctions.count++;
1268     Date.formatFunctions[format] = funcName;
1269     var code = "Date.prototype." + funcName + " = function(){return ";
1270     var special = false;
1271     var ch = '';
1272     for (var i = 0; i < format.length; ++i) {
1273         ch = format.charAt(i);
1274         if (!special && ch == "\\") {
1275             special = true;
1276         }
1277         else if (special) {
1278             special = false;
1279             code += "'" + String.escape(ch) + "' + ";
1280         }
1281         else {
1282             code += Date.getFormatCode(ch);
1283         }
1284     }
1285     /** eval:var:zzzzzzzzzzzzz */
1286     eval(code.substring(0, code.length - 3) + ";}");
1287 };
1288
1289 // private
1290 Date.getFormatCode = function(character) {
1291     switch (character) {
1292     case "d":
1293         return "String.leftPad(this.getDate(), 2, '0') + ";
1294     case "D":
1295         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1296     case "j":
1297         return "this.getDate() + ";
1298     case "l":
1299         return "Date.dayNames[this.getDay()] + ";
1300     case "S":
1301         return "this.getSuffix() + ";
1302     case "w":
1303         return "this.getDay() + ";
1304     case "z":
1305         return "this.getDayOfYear() + ";
1306     case "W":
1307         return "this.getWeekOfYear() + ";
1308     case "F":
1309         return "Date.monthNames[this.getMonth()] + ";
1310     case "m":
1311         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1312     case "M":
1313         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1314     case "n":
1315         return "(this.getMonth() + 1) + ";
1316     case "t":
1317         return "this.getDaysInMonth() + ";
1318     case "L":
1319         return "(this.isLeapYear() ? 1 : 0) + ";
1320     case "Y":
1321         return "this.getFullYear() + ";
1322     case "y":
1323         return "('' + this.getFullYear()).substring(2, 4) + ";
1324     case "a":
1325         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1326     case "A":
1327         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1328     case "g":
1329         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1330     case "G":
1331         return "this.getHours() + ";
1332     case "h":
1333         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1334     case "H":
1335         return "String.leftPad(this.getHours(), 2, '0') + ";
1336     case "i":
1337         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1338     case "s":
1339         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1340     case "O":
1341         return "this.getGMTOffset() + ";
1342     case "P":
1343         return "this.getGMTColonOffset() + ";
1344     case "T":
1345         return "this.getTimezone() + ";
1346     case "Z":
1347         return "(this.getTimezoneOffset() * -60) + ";
1348     default:
1349         return "'" + String.escape(character) + "' + ";
1350     }
1351 };
1352
1353 /**
1354  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1355  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1356  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1357  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1358  * string or the parse operation will fail.
1359  * Example Usage:
1360 <pre><code>
1361 //dt = Fri May 25 2007 (current date)
1362 var dt = new Date();
1363
1364 //dt = Thu May 25 2006 (today's month/day in 2006)
1365 dt = Date.parseDate("2006", "Y");
1366
1367 //dt = Sun Jan 15 2006 (all date parts specified)
1368 dt = Date.parseDate("2006-1-15", "Y-m-d");
1369
1370 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1371 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1372 </code></pre>
1373  * @param {String} input The unparsed date as a string
1374  * @param {String} format The format the date is in
1375  * @return {Date} The parsed date
1376  * @static
1377  */
1378 Date.parseDate = function(input, format) {
1379     if (Date.parseFunctions[format] == null) {
1380         Date.createParser(format);
1381     }
1382     var func = Date.parseFunctions[format];
1383     return Date[func](input);
1384 };
1385 /**
1386  * @private
1387  */
1388
1389 Date.createParser = function(format) {
1390     var funcName = "parse" + Date.parseFunctions.count++;
1391     var regexNum = Date.parseRegexes.length;
1392     var currentGroup = 1;
1393     Date.parseFunctions[format] = funcName;
1394
1395     var code = "Date." + funcName + " = function(input){\n"
1396         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1397         + "var d = new Date();\n"
1398         + "y = d.getFullYear();\n"
1399         + "m = d.getMonth();\n"
1400         + "d = d.getDate();\n"
1401         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1402         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1403         + "if (results && results.length > 0) {";
1404     var regex = "";
1405
1406     var special = false;
1407     var ch = '';
1408     for (var i = 0; i < format.length; ++i) {
1409         ch = format.charAt(i);
1410         if (!special && ch == "\\") {
1411             special = true;
1412         }
1413         else if (special) {
1414             special = false;
1415             regex += String.escape(ch);
1416         }
1417         else {
1418             var obj = Date.formatCodeToRegex(ch, currentGroup);
1419             currentGroup += obj.g;
1420             regex += obj.s;
1421             if (obj.g && obj.c) {
1422                 code += obj.c;
1423             }
1424         }
1425     }
1426
1427     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1428         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1429         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1430         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1431         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1432         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1433         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1434         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1435         + "else if (y >= 0 && m >= 0)\n"
1436         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1437         + "else if (y >= 0)\n"
1438         + "{v = new Date(y); v.setFullYear(y);}\n"
1439         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1440         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1441         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1442         + ";}";
1443
1444     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1445     /** eval:var:zzzzzzzzzzzzz */
1446     eval(code);
1447 };
1448
1449 // private
1450 Date.formatCodeToRegex = function(character, currentGroup) {
1451     switch (character) {
1452     case "D":
1453         return {g:0,
1454         c:null,
1455         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1456     case "j":
1457         return {g:1,
1458             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1459             s:"(\\d{1,2})"}; // day of month without leading zeroes
1460     case "d":
1461         return {g:1,
1462             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1463             s:"(\\d{2})"}; // day of month with leading zeroes
1464     case "l":
1465         return {g:0,
1466             c:null,
1467             s:"(?:" + Date.dayNames.join("|") + ")"};
1468     case "S":
1469         return {g:0,
1470             c:null,
1471             s:"(?:st|nd|rd|th)"};
1472     case "w":
1473         return {g:0,
1474             c:null,
1475             s:"\\d"};
1476     case "z":
1477         return {g:0,
1478             c:null,
1479             s:"(?:\\d{1,3})"};
1480     case "W":
1481         return {g:0,
1482             c:null,
1483             s:"(?:\\d{2})"};
1484     case "F":
1485         return {g:1,
1486             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1487             s:"(" + Date.monthNames.join("|") + ")"};
1488     case "M":
1489         return {g:1,
1490             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1491             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1492     case "n":
1493         return {g:1,
1494             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1495             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1496     case "m":
1497         return {g:1,
1498             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1499             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1500     case "t":
1501         return {g:0,
1502             c:null,
1503             s:"\\d{1,2}"};
1504     case "L":
1505         return {g:0,
1506             c:null,
1507             s:"(?:1|0)"};
1508     case "Y":
1509         return {g:1,
1510             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1511             s:"(\\d{4})"};
1512     case "y":
1513         return {g:1,
1514             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1515                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1516             s:"(\\d{1,2})"};
1517     case "a":
1518         return {g:1,
1519             c:"if (results[" + currentGroup + "] == 'am') {\n"
1520                 + "if (h == 12) { h = 0; }\n"
1521                 + "} else { if (h < 12) { h += 12; }}",
1522             s:"(am|pm)"};
1523     case "A":
1524         return {g:1,
1525             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1526                 + "if (h == 12) { h = 0; }\n"
1527                 + "} else { if (h < 12) { h += 12; }}",
1528             s:"(AM|PM)"};
1529     case "g":
1530     case "G":
1531         return {g:1,
1532             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1533             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1534     case "h":
1535     case "H":
1536         return {g:1,
1537             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1538             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1539     case "i":
1540         return {g:1,
1541             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1542             s:"(\\d{2})"};
1543     case "s":
1544         return {g:1,
1545             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1546             s:"(\\d{2})"};
1547     case "O":
1548         return {g:1,
1549             c:[
1550                 "o = results[", currentGroup, "];\n",
1551                 "var sn = o.substring(0,1);\n", // get + / - sign
1552                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1553                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1554                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1555                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1556             ].join(""),
1557             s:"([+\-]\\d{2,4})"};
1558     
1559     
1560     case "P":
1561         return {g:1,
1562                 c:[
1563                    "o = results[", currentGroup, "];\n",
1564                    "var sn = o.substring(0,1);\n",
1565                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1566                    "var mn = o.substring(4,6) % 60;\n",
1567                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1568                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1569             ].join(""),
1570             s:"([+\-]\\d{4})"};
1571     case "T":
1572         return {g:0,
1573             c:null,
1574             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1575     case "Z":
1576         return {g:1,
1577             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1578                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1579             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1580     default:
1581         return {g:0,
1582             c:null,
1583             s:String.escape(character)};
1584     }
1585 };
1586
1587 /**
1588  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1589  * @return {String} The abbreviated timezone name (e.g. 'CST')
1590  */
1591 Date.prototype.getTimezone = function() {
1592     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1593 };
1594
1595 /**
1596  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1597  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1598  */
1599 Date.prototype.getGMTOffset = function() {
1600     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1601         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1602         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1603 };
1604
1605 /**
1606  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1607  * @return {String} 2-characters representing hours and 2-characters representing minutes
1608  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1609  */
1610 Date.prototype.getGMTColonOffset = function() {
1611         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1612                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1613                 + ":"
1614                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1615 }
1616
1617 /**
1618  * Get the numeric day number of the year, adjusted for leap year.
1619  * @return {Number} 0 through 364 (365 in leap years)
1620  */
1621 Date.prototype.getDayOfYear = function() {
1622     var num = 0;
1623     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1624     for (var i = 0; i < this.getMonth(); ++i) {
1625         num += Date.daysInMonth[i];
1626     }
1627     return num + this.getDate() - 1;
1628 };
1629
1630 /**
1631  * Get the string representation of the numeric week number of the year
1632  * (equivalent to the format specifier 'W').
1633  * @return {String} '00' through '52'
1634  */
1635 Date.prototype.getWeekOfYear = function() {
1636     // Skip to Thursday of this week
1637     var now = this.getDayOfYear() + (4 - this.getDay());
1638     // Find the first Thursday of the year
1639     var jan1 = new Date(this.getFullYear(), 0, 1);
1640     var then = (7 - jan1.getDay() + 4);
1641     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1642 };
1643
1644 /**
1645  * Whether or not the current date is in a leap year.
1646  * @return {Boolean} True if the current date is in a leap year, else false
1647  */
1648 Date.prototype.isLeapYear = function() {
1649     var year = this.getFullYear();
1650     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1651 };
1652
1653 /**
1654  * Get the first day of the current month, adjusted for leap year.  The returned value
1655  * is the numeric day index within the week (0-6) which can be used in conjunction with
1656  * the {@link #monthNames} array to retrieve the textual day name.
1657  * Example:
1658  *<pre><code>
1659 var dt = new Date('1/10/2007');
1660 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1661 </code></pre>
1662  * @return {Number} The day number (0-6)
1663  */
1664 Date.prototype.getFirstDayOfMonth = function() {
1665     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1666     return (day < 0) ? (day + 7) : day;
1667 };
1668
1669 /**
1670  * Get the last day of the current month, adjusted for leap year.  The returned value
1671  * is the numeric day index within the week (0-6) which can be used in conjunction with
1672  * the {@link #monthNames} array to retrieve the textual day name.
1673  * Example:
1674  *<pre><code>
1675 var dt = new Date('1/10/2007');
1676 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1677 </code></pre>
1678  * @return {Number} The day number (0-6)
1679  */
1680 Date.prototype.getLastDayOfMonth = function() {
1681     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1682     return (day < 0) ? (day + 7) : day;
1683 };
1684
1685
1686 /**
1687  * Get the first date of this date's month
1688  * @return {Date}
1689  */
1690 Date.prototype.getFirstDateOfMonth = function() {
1691     return new Date(this.getFullYear(), this.getMonth(), 1);
1692 };
1693
1694 /**
1695  * Get the last date of this date's month
1696  * @return {Date}
1697  */
1698 Date.prototype.getLastDateOfMonth = function() {
1699     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1700 };
1701 /**
1702  * Get the number of days in the current month, adjusted for leap year.
1703  * @return {Number} The number of days in the month
1704  */
1705 Date.prototype.getDaysInMonth = function() {
1706     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1707     return Date.daysInMonth[this.getMonth()];
1708 };
1709
1710 /**
1711  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1712  * @return {String} 'st, 'nd', 'rd' or 'th'
1713  */
1714 Date.prototype.getSuffix = function() {
1715     switch (this.getDate()) {
1716         case 1:
1717         case 21:
1718         case 31:
1719             return "st";
1720         case 2:
1721         case 22:
1722             return "nd";
1723         case 3:
1724         case 23:
1725             return "rd";
1726         default:
1727             return "th";
1728     }
1729 };
1730
1731 // private
1732 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1733
1734 /**
1735  * An array of textual month names.
1736  * Override these values for international dates, for example...
1737  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1738  * @type Array
1739  * @static
1740  */
1741 Date.monthNames =
1742    ["January",
1743     "February",
1744     "March",
1745     "April",
1746     "May",
1747     "June",
1748     "July",
1749     "August",
1750     "September",
1751     "October",
1752     "November",
1753     "December"];
1754
1755 /**
1756  * An array of textual day names.
1757  * Override these values for international dates, for example...
1758  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1759  * @type Array
1760  * @static
1761  */
1762 Date.dayNames =
1763    ["Sunday",
1764     "Monday",
1765     "Tuesday",
1766     "Wednesday",
1767     "Thursday",
1768     "Friday",
1769     "Saturday"];
1770
1771 // private
1772 Date.y2kYear = 50;
1773 // private
1774 Date.monthNumbers = {
1775     Jan:0,
1776     Feb:1,
1777     Mar:2,
1778     Apr:3,
1779     May:4,
1780     Jun:5,
1781     Jul:6,
1782     Aug:7,
1783     Sep:8,
1784     Oct:9,
1785     Nov:10,
1786     Dec:11};
1787
1788 /**
1789  * Creates and returns a new Date instance with the exact same date value as the called instance.
1790  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1791  * variable will also be changed.  When the intention is to create a new variable that will not
1792  * modify the original instance, you should create a clone.
1793  *
1794  * Example of correctly cloning a date:
1795  * <pre><code>
1796 //wrong way:
1797 var orig = new Date('10/1/2006');
1798 var copy = orig;
1799 copy.setDate(5);
1800 document.write(orig);  //returns 'Thu Oct 05 2006'!
1801
1802 //correct way:
1803 var orig = new Date('10/1/2006');
1804 var copy = orig.clone();
1805 copy.setDate(5);
1806 document.write(orig);  //returns 'Thu Oct 01 2006'
1807 </code></pre>
1808  * @return {Date} The new Date instance
1809  */
1810 Date.prototype.clone = function() {
1811         return new Date(this.getTime());
1812 };
1813
1814 /**
1815  * Clears any time information from this date
1816  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1817  @return {Date} this or the clone
1818  */
1819 Date.prototype.clearTime = function(clone){
1820     if(clone){
1821         return this.clone().clearTime();
1822     }
1823     this.setHours(0);
1824     this.setMinutes(0);
1825     this.setSeconds(0);
1826     this.setMilliseconds(0);
1827     return this;
1828 };
1829
1830 // private
1831 // safari setMonth is broken -- check that this is only donw once...
1832 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1833     Date.brokenSetMonth = Date.prototype.setMonth;
1834         Date.prototype.setMonth = function(num){
1835                 if(num <= -1){
1836                         var n = Math.ceil(-num);
1837                         var back_year = Math.ceil(n/12);
1838                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1839                         this.setFullYear(this.getFullYear() - back_year);
1840                         return Date.brokenSetMonth.call(this, month);
1841                 } else {
1842                         return Date.brokenSetMonth.apply(this, arguments);
1843                 }
1844         };
1845 }
1846
1847 /** Date interval constant 
1848 * @static 
1849 * @type String */
1850 Date.MILLI = "ms";
1851 /** Date interval constant 
1852 * @static 
1853 * @type String */
1854 Date.SECOND = "s";
1855 /** Date interval constant 
1856 * @static 
1857 * @type String */
1858 Date.MINUTE = "mi";
1859 /** Date interval constant 
1860 * @static 
1861 * @type String */
1862 Date.HOUR = "h";
1863 /** Date interval constant 
1864 * @static 
1865 * @type String */
1866 Date.DAY = "d";
1867 /** Date interval constant 
1868 * @static 
1869 * @type String */
1870 Date.MONTH = "mo";
1871 /** Date interval constant 
1872 * @static 
1873 * @type String */
1874 Date.YEAR = "y";
1875
1876 /**
1877  * Provides a convenient method of performing basic date arithmetic.  This method
1878  * does not modify the Date instance being called - it creates and returns
1879  * a new Date instance containing the resulting date value.
1880  *
1881  * Examples:
1882  * <pre><code>
1883 //Basic usage:
1884 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1885 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1886
1887 //Negative values will subtract correctly:
1888 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1889 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1890
1891 //You can even chain several calls together in one line!
1892 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1893 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1894  </code></pre>
1895  *
1896  * @param {String} interval   A valid date interval enum value
1897  * @param {Number} value      The amount to add to the current date
1898  * @return {Date} The new Date instance
1899  */
1900 Date.prototype.add = function(interval, value){
1901   var d = this.clone();
1902   if (!interval || value === 0) { return d; }
1903   switch(interval.toLowerCase()){
1904     case Date.MILLI:
1905       d.setMilliseconds(this.getMilliseconds() + value);
1906       break;
1907     case Date.SECOND:
1908       d.setSeconds(this.getSeconds() + value);
1909       break;
1910     case Date.MINUTE:
1911       d.setMinutes(this.getMinutes() + value);
1912       break;
1913     case Date.HOUR:
1914       d.setHours(this.getHours() + value);
1915       break;
1916     case Date.DAY:
1917       d.setDate(this.getDate() + value);
1918       break;
1919     case Date.MONTH:
1920       var day = this.getDate();
1921       if(day > 28){
1922           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1923       }
1924       d.setDate(day);
1925       d.setMonth(this.getMonth() + value);
1926       break;
1927     case Date.YEAR:
1928       d.setFullYear(this.getFullYear() + value);
1929       break;
1930   }
1931   return d;
1932 };
1933 /**
1934  * @class Roo.lib.Dom
1935  * @licence LGPL
1936  * @static
1937  * 
1938  * Dom utils (from YIU afaik)
1939  *
1940  * 
1941  **/
1942 Roo.lib.Dom = {
1943     /**
1944      * Get the view width
1945      * @param {Boolean} full True will get the full document, otherwise it's the view width
1946      * @return {Number} The width
1947      */
1948      
1949     getViewWidth : function(full) {
1950         return full ? this.getDocumentWidth() : this.getViewportWidth();
1951     },
1952     /**
1953      * Get the view height
1954      * @param {Boolean} full True will get the full document, otherwise it's the view height
1955      * @return {Number} The height
1956      */
1957     getViewHeight : function(full) {
1958         return full ? this.getDocumentHeight() : this.getViewportHeight();
1959     },
1960     /**
1961      * Get the Full Document height 
1962      * @return {Number} The height
1963      */
1964     getDocumentHeight: function() {
1965         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1966         return Math.max(scrollHeight, this.getViewportHeight());
1967     },
1968     /**
1969      * Get the Full Document width
1970      * @return {Number} The width
1971      */
1972     getDocumentWidth: function() {
1973         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1974         return Math.max(scrollWidth, this.getViewportWidth());
1975     },
1976     /**
1977      * Get the Window Viewport height
1978      * @return {Number} The height
1979      */
1980     getViewportHeight: function() {
1981         var height = self.innerHeight;
1982         var mode = document.compatMode;
1983
1984         if ((mode || Roo.isIE) && !Roo.isOpera) {
1985             height = (mode == "CSS1Compat") ?
1986                      document.documentElement.clientHeight :
1987                      document.body.clientHeight;
1988         }
1989
1990         return height;
1991     },
1992     /**
1993      * Get the Window Viewport width
1994      * @return {Number} The width
1995      */
1996     getViewportWidth: function() {
1997         var width = self.innerWidth;
1998         var mode = document.compatMode;
1999
2000         if (mode || Roo.isIE) {
2001             width = (mode == "CSS1Compat") ?
2002                     document.documentElement.clientWidth :
2003                     document.body.clientWidth;
2004         }
2005         return width;
2006     },
2007
2008     isAncestor : function(p, c) {
2009         p = Roo.getDom(p);
2010         c = Roo.getDom(c);
2011         if (!p || !c) {
2012             return false;
2013         }
2014
2015         if (p.contains && !Roo.isSafari) {
2016             return p.contains(c);
2017         } else if (p.compareDocumentPosition) {
2018             return !!(p.compareDocumentPosition(c) & 16);
2019         } else {
2020             var parent = c.parentNode;
2021             while (parent) {
2022                 if (parent == p) {
2023                     return true;
2024                 }
2025                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2026                     return false;
2027                 }
2028                 parent = parent.parentNode;
2029             }
2030             return false;
2031         }
2032     },
2033
2034     getRegion : function(el) {
2035         return Roo.lib.Region.getRegion(el);
2036     },
2037
2038     getY : function(el) {
2039         return this.getXY(el)[1];
2040     },
2041
2042     getX : function(el) {
2043         return this.getXY(el)[0];
2044     },
2045
2046     getXY : function(el) {
2047         var p, pe, b, scroll, bd = document.body;
2048         el = Roo.getDom(el);
2049         var fly = Roo.lib.AnimBase.fly;
2050         if (el.getBoundingClientRect) {
2051             b = el.getBoundingClientRect();
2052             scroll = fly(document).getScroll();
2053             return [b.left + scroll.left, b.top + scroll.top];
2054         }
2055         var x = 0, y = 0;
2056
2057         p = el;
2058
2059         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2060
2061         while (p) {
2062
2063             x += p.offsetLeft;
2064             y += p.offsetTop;
2065
2066             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2067                 hasAbsolute = true;
2068             }
2069
2070             if (Roo.isGecko) {
2071                 pe = fly(p);
2072
2073                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2074                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2075
2076
2077                 x += bl;
2078                 y += bt;
2079
2080
2081                 if (p != el && pe.getStyle('overflow') != 'visible') {
2082                     x += bl;
2083                     y += bt;
2084                 }
2085             }
2086             p = p.offsetParent;
2087         }
2088
2089         if (Roo.isSafari && hasAbsolute) {
2090             x -= bd.offsetLeft;
2091             y -= bd.offsetTop;
2092         }
2093
2094         if (Roo.isGecko && !hasAbsolute) {
2095             var dbd = fly(bd);
2096             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2097             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2098         }
2099
2100         p = el.parentNode;
2101         while (p && p != bd) {
2102             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2103                 x -= p.scrollLeft;
2104                 y -= p.scrollTop;
2105             }
2106             p = p.parentNode;
2107         }
2108         return [x, y];
2109     },
2110  
2111   
2112
2113
2114     setXY : function(el, xy) {
2115         el = Roo.fly(el, '_setXY');
2116         el.position();
2117         var pts = el.translatePoints(xy);
2118         if (xy[0] !== false) {
2119             el.dom.style.left = pts.left + "px";
2120         }
2121         if (xy[1] !== false) {
2122             el.dom.style.top = pts.top + "px";
2123         }
2124     },
2125
2126     setX : function(el, x) {
2127         this.setXY(el, [x, false]);
2128     },
2129
2130     setY : function(el, y) {
2131         this.setXY(el, [false, y]);
2132     }
2133 };
2134 /*
2135  * Portions of this file are based on pieces of Yahoo User Interface Library
2136  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2137  * YUI licensed under the BSD License:
2138  * http://developer.yahoo.net/yui/license.txt
2139  * <script type="text/javascript">
2140  *
2141  */
2142
2143 Roo.lib.Event = function() {
2144     var loadComplete = false;
2145     var listeners = [];
2146     var unloadListeners = [];
2147     var retryCount = 0;
2148     var onAvailStack = [];
2149     var counter = 0;
2150     var lastError = null;
2151
2152     return {
2153         POLL_RETRYS: 200,
2154         POLL_INTERVAL: 20,
2155         EL: 0,
2156         TYPE: 1,
2157         FN: 2,
2158         WFN: 3,
2159         OBJ: 3,
2160         ADJ_SCOPE: 4,
2161         _interval: null,
2162
2163         startInterval: function() {
2164             if (!this._interval) {
2165                 var self = this;
2166                 var callback = function() {
2167                     self._tryPreloadAttach();
2168                 };
2169                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2170
2171             }
2172         },
2173
2174         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2175             onAvailStack.push({ id:         p_id,
2176                 fn:         p_fn,
2177                 obj:        p_obj,
2178                 override:   p_override,
2179                 checkReady: false    });
2180
2181             retryCount = this.POLL_RETRYS;
2182             this.startInterval();
2183         },
2184
2185
2186         addListener: function(el, eventName, fn) {
2187             el = Roo.getDom(el);
2188             if (!el || !fn) {
2189                 return false;
2190             }
2191
2192             if ("unload" == eventName) {
2193                 unloadListeners[unloadListeners.length] =
2194                 [el, eventName, fn];
2195                 return true;
2196             }
2197
2198             var wrappedFn = function(e) {
2199                 return fn(Roo.lib.Event.getEvent(e));
2200             };
2201
2202             var li = [el, eventName, fn, wrappedFn];
2203
2204             var index = listeners.length;
2205             listeners[index] = li;
2206
2207             this.doAdd(el, eventName, wrappedFn, false);
2208             return true;
2209
2210         },
2211
2212
2213         removeListener: function(el, eventName, fn) {
2214             var i, len;
2215
2216             el = Roo.getDom(el);
2217
2218             if(!fn) {
2219                 return this.purgeElement(el, false, eventName);
2220             }
2221
2222
2223             if ("unload" == eventName) {
2224
2225                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2226                     var li = unloadListeners[i];
2227                     if (li &&
2228                         li[0] == el &&
2229                         li[1] == eventName &&
2230                         li[2] == fn) {
2231                         unloadListeners.splice(i, 1);
2232                         return true;
2233                     }
2234                 }
2235
2236                 return false;
2237             }
2238
2239             var cacheItem = null;
2240
2241
2242             var index = arguments[3];
2243
2244             if ("undefined" == typeof index) {
2245                 index = this._getCacheIndex(el, eventName, fn);
2246             }
2247
2248             if (index >= 0) {
2249                 cacheItem = listeners[index];
2250             }
2251
2252             if (!el || !cacheItem) {
2253                 return false;
2254             }
2255
2256             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2257
2258             delete listeners[index][this.WFN];
2259             delete listeners[index][this.FN];
2260             listeners.splice(index, 1);
2261
2262             return true;
2263
2264         },
2265
2266
2267         getTarget: function(ev, resolveTextNode) {
2268             ev = ev.browserEvent || ev;
2269             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2270             var t = ev.target || ev.srcElement;
2271             return this.resolveTextNode(t);
2272         },
2273
2274
2275         resolveTextNode: function(node) {
2276             if (Roo.isSafari && node && 3 == node.nodeType) {
2277                 return node.parentNode;
2278             } else {
2279                 return node;
2280             }
2281         },
2282
2283
2284         getPageX: function(ev) {
2285             ev = ev.browserEvent || ev;
2286             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2287             var x = ev.pageX;
2288             if (!x && 0 !== x) {
2289                 x = ev.clientX || 0;
2290
2291                 if (Roo.isIE) {
2292                     x += this.getScroll()[1];
2293                 }
2294             }
2295
2296             return x;
2297         },
2298
2299
2300         getPageY: function(ev) {
2301             ev = ev.browserEvent || ev;
2302             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2303             var y = ev.pageY;
2304             if (!y && 0 !== y) {
2305                 y = ev.clientY || 0;
2306
2307                 if (Roo.isIE) {
2308                     y += this.getScroll()[0];
2309                 }
2310             }
2311
2312
2313             return y;
2314         },
2315
2316
2317         getXY: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2320             return [this.getPageX(ev), this.getPageY(ev)];
2321         },
2322
2323
2324         getRelatedTarget: function(ev) {
2325             ev = ev.browserEvent || ev;
2326             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2327             var t = ev.relatedTarget;
2328             if (!t) {
2329                 if (ev.type == "mouseout") {
2330                     t = ev.toElement;
2331                 } else if (ev.type == "mouseover") {
2332                     t = ev.fromElement;
2333                 }
2334             }
2335
2336             return this.resolveTextNode(t);
2337         },
2338
2339
2340         getTime: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2343             if (!ev.time) {
2344                 var t = new Date().getTime();
2345                 try {
2346                     ev.time = t;
2347                 } catch(ex) {
2348                     this.lastError = ex;
2349                     return t;
2350                 }
2351             }
2352
2353             return ev.time;
2354         },
2355
2356
2357         stopEvent: function(ev) {
2358             this.stopPropagation(ev);
2359             this.preventDefault(ev);
2360         },
2361
2362
2363         stopPropagation: function(ev) {
2364             ev = ev.browserEvent || ev;
2365             if (ev.stopPropagation) {
2366                 ev.stopPropagation();
2367             } else {
2368                 ev.cancelBubble = true;
2369             }
2370         },
2371
2372
2373         preventDefault: function(ev) {
2374             ev = ev.browserEvent || ev;
2375             if(ev.preventDefault) {
2376                 ev.preventDefault();
2377             } else {
2378                 ev.returnValue = false;
2379             }
2380         },
2381
2382
2383         getEvent: function(e) {
2384             var ev = e || window.event;
2385             if (!ev) {
2386                 var c = this.getEvent.caller;
2387                 while (c) {
2388                     ev = c.arguments[0];
2389                     if (ev && Event == ev.constructor) {
2390                         break;
2391                     }
2392                     c = c.caller;
2393                 }
2394             }
2395             return ev;
2396         },
2397
2398
2399         getCharCode: function(ev) {
2400             ev = ev.browserEvent || ev;
2401             return ev.charCode || ev.keyCode || 0;
2402         },
2403
2404
2405         _getCacheIndex: function(el, eventName, fn) {
2406             for (var i = 0,len = listeners.length; i < len; ++i) {
2407                 var li = listeners[i];
2408                 if (li &&
2409                     li[this.FN] == fn &&
2410                     li[this.EL] == el &&
2411                     li[this.TYPE] == eventName) {
2412                     return i;
2413                 }
2414             }
2415
2416             return -1;
2417         },
2418
2419
2420         elCache: {},
2421
2422
2423         getEl: function(id) {
2424             return document.getElementById(id);
2425         },
2426
2427
2428         clearCache: function() {
2429         },
2430
2431
2432         _load: function(e) {
2433             loadComplete = true;
2434             var EU = Roo.lib.Event;
2435
2436
2437             if (Roo.isIE) {
2438                 EU.doRemove(window, "load", EU._load);
2439             }
2440         },
2441
2442
2443         _tryPreloadAttach: function() {
2444
2445             if (this.locked) {
2446                 return false;
2447             }
2448
2449             this.locked = true;
2450
2451
2452             var tryAgain = !loadComplete;
2453             if (!tryAgain) {
2454                 tryAgain = (retryCount > 0);
2455             }
2456
2457
2458             var notAvail = [];
2459             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2460                 var item = onAvailStack[i];
2461                 if (item) {
2462                     var el = this.getEl(item.id);
2463
2464                     if (el) {
2465                         if (!item.checkReady ||
2466                             loadComplete ||
2467                             el.nextSibling ||
2468                             (document && document.body)) {
2469
2470                             var scope = el;
2471                             if (item.override) {
2472                                 if (item.override === true) {
2473                                     scope = item.obj;
2474                                 } else {
2475                                     scope = item.override;
2476                                 }
2477                             }
2478                             item.fn.call(scope, item.obj);
2479                             onAvailStack[i] = null;
2480                         }
2481                     } else {
2482                         notAvail.push(item);
2483                     }
2484                 }
2485             }
2486
2487             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2488
2489             if (tryAgain) {
2490
2491                 this.startInterval();
2492             } else {
2493                 clearInterval(this._interval);
2494                 this._interval = null;
2495             }
2496
2497             this.locked = false;
2498
2499             return true;
2500
2501         },
2502
2503
2504         purgeElement: function(el, recurse, eventName) {
2505             var elListeners = this.getListeners(el, eventName);
2506             if (elListeners) {
2507                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2508                     var l = elListeners[i];
2509                     this.removeListener(el, l.type, l.fn);
2510                 }
2511             }
2512
2513             if (recurse && el && el.childNodes) {
2514                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2515                     this.purgeElement(el.childNodes[i], recurse, eventName);
2516                 }
2517             }
2518         },
2519
2520
2521         getListeners: function(el, eventName) {
2522             var results = [], searchLists;
2523             if (!eventName) {
2524                 searchLists = [listeners, unloadListeners];
2525             } else if (eventName == "unload") {
2526                 searchLists = [unloadListeners];
2527             } else {
2528                 searchLists = [listeners];
2529             }
2530
2531             for (var j = 0; j < searchLists.length; ++j) {
2532                 var searchList = searchLists[j];
2533                 if (searchList && searchList.length > 0) {
2534                     for (var i = 0,len = searchList.length; i < len; ++i) {
2535                         var l = searchList[i];
2536                         if (l && l[this.EL] === el &&
2537                             (!eventName || eventName === l[this.TYPE])) {
2538                             results.push({
2539                                 type:   l[this.TYPE],
2540                                 fn:     l[this.FN],
2541                                 obj:    l[this.OBJ],
2542                                 adjust: l[this.ADJ_SCOPE],
2543                                 index:  i
2544                             });
2545                         }
2546                     }
2547                 }
2548             }
2549
2550             return (results.length) ? results : null;
2551         },
2552
2553
2554         _unload: function(e) {
2555
2556             var EU = Roo.lib.Event, i, j, l, len, index;
2557
2558             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2559                 l = unloadListeners[i];
2560                 if (l) {
2561                     var scope = window;
2562                     if (l[EU.ADJ_SCOPE]) {
2563                         if (l[EU.ADJ_SCOPE] === true) {
2564                             scope = l[EU.OBJ];
2565                         } else {
2566                             scope = l[EU.ADJ_SCOPE];
2567                         }
2568                     }
2569                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2570                     unloadListeners[i] = null;
2571                     l = null;
2572                     scope = null;
2573                 }
2574             }
2575
2576             unloadListeners = null;
2577
2578             if (listeners && listeners.length > 0) {
2579                 j = listeners.length;
2580                 while (j) {
2581                     index = j - 1;
2582                     l = listeners[index];
2583                     if (l) {
2584                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2585                                 l[EU.FN], index);
2586                     }
2587                     j = j - 1;
2588                 }
2589                 l = null;
2590
2591                 EU.clearCache();
2592             }
2593
2594             EU.doRemove(window, "unload", EU._unload);
2595
2596         },
2597
2598
2599         getScroll: function() {
2600             var dd = document.documentElement, db = document.body;
2601             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2602                 return [dd.scrollTop, dd.scrollLeft];
2603             } else if (db) {
2604                 return [db.scrollTop, db.scrollLeft];
2605             } else {
2606                 return [0, 0];
2607             }
2608         },
2609
2610
2611         doAdd: function () {
2612             if (window.addEventListener) {
2613                 return function(el, eventName, fn, capture) {
2614                     el.addEventListener(eventName, fn, (capture));
2615                 };
2616             } else if (window.attachEvent) {
2617                 return function(el, eventName, fn, capture) {
2618                     el.attachEvent("on" + eventName, fn);
2619                 };
2620             } else {
2621                 return function() {
2622                 };
2623             }
2624         }(),
2625
2626
2627         doRemove: function() {
2628             if (window.removeEventListener) {
2629                 return function (el, eventName, fn, capture) {
2630                     el.removeEventListener(eventName, fn, (capture));
2631                 };
2632             } else if (window.detachEvent) {
2633                 return function (el, eventName, fn) {
2634                     el.detachEvent("on" + eventName, fn);
2635                 };
2636             } else {
2637                 return function() {
2638                 };
2639             }
2640         }()
2641     };
2642     
2643 }();
2644 (function() {     
2645    
2646     var E = Roo.lib.Event;
2647     E.on = E.addListener;
2648     E.un = E.removeListener;
2649
2650     if (document && document.body) {
2651         E._load();
2652     } else {
2653         E.doAdd(window, "load", E._load);
2654     }
2655     E.doAdd(window, "unload", E._unload);
2656     E._tryPreloadAttach();
2657 })();
2658
2659  
2660
2661 (function() {
2662     /**
2663      * @class Roo.lib.Ajax
2664      *
2665      * provide a simple Ajax request utility functions
2666      * 
2667      * Portions of this file are based on pieces of Yahoo User Interface Library
2668     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2669     * YUI licensed under the BSD License:
2670     * http://developer.yahoo.net/yui/license.txt
2671     * <script type="text/javascript">
2672     *
2673      *
2674      */
2675     Roo.lib.Ajax = {
2676         /**
2677          * @static 
2678          */
2679         request : function(method, uri, cb, data, options) {
2680             if(options){
2681                 var hs = options.headers;
2682                 if(hs){
2683                     for(var h in hs){
2684                         if(hs.hasOwnProperty(h)){
2685                             this.initHeader(h, hs[h], false);
2686                         }
2687                     }
2688                 }
2689                 if(options.xmlData){
2690                     this.initHeader('Content-Type', 'text/xml', false);
2691                     method = 'POST';
2692                     data = options.xmlData;
2693                 }
2694             }
2695
2696             return this.asyncRequest(method, uri, cb, data);
2697         },
2698         /**
2699          * serialize a form
2700          *
2701          * @static
2702          * @param {DomForm} form element
2703          * @return {String} urlencode form output.
2704          */
2705         serializeForm : function(form) {
2706             if(typeof form == 'string') {
2707                 form = (document.getElementById(form) || document.forms[form]);
2708             }
2709
2710             var el, name, val, disabled, data = '', hasSubmit = false;
2711             for (var i = 0; i < form.elements.length; i++) {
2712                 el = form.elements[i];
2713                 disabled = form.elements[i].disabled;
2714                 name = form.elements[i].name;
2715                 val = form.elements[i].value;
2716
2717                 if (!disabled && name){
2718                     switch (el.type)
2719                             {
2720                         case 'select-one':
2721                         case 'select-multiple':
2722                             for (var j = 0; j < el.options.length; j++) {
2723                                 if (el.options[j].selected) {
2724                                     if (Roo.isIE) {
2725                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2726                                     }
2727                                     else {
2728                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2729                                     }
2730                                 }
2731                             }
2732                             break;
2733                         case 'radio':
2734                         case 'checkbox':
2735                             if (el.checked) {
2736                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2737                             }
2738                             break;
2739                         case 'file':
2740
2741                         case undefined:
2742
2743                         case 'reset':
2744
2745                         case 'button':
2746
2747                             break;
2748                         case 'submit':
2749                             if(hasSubmit == false) {
2750                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2751                                 hasSubmit = true;
2752                             }
2753                             break;
2754                         default:
2755                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2756                             break;
2757                     }
2758                 }
2759             }
2760             data = data.substr(0, data.length - 1);
2761             return data;
2762         },
2763
2764         headers:{},
2765
2766         hasHeaders:false,
2767
2768         useDefaultHeader:true,
2769
2770         defaultPostHeader:'application/x-www-form-urlencoded',
2771
2772         useDefaultXhrHeader:true,
2773
2774         defaultXhrHeader:'XMLHttpRequest',
2775
2776         hasDefaultHeaders:true,
2777
2778         defaultHeaders:{},
2779
2780         poll:{},
2781
2782         timeout:{},
2783
2784         pollInterval:50,
2785
2786         transactionId:0,
2787
2788         setProgId:function(id)
2789         {
2790             this.activeX.unshift(id);
2791         },
2792
2793         setDefaultPostHeader:function(b)
2794         {
2795             this.useDefaultHeader = b;
2796         },
2797
2798         setDefaultXhrHeader:function(b)
2799         {
2800             this.useDefaultXhrHeader = b;
2801         },
2802
2803         setPollingInterval:function(i)
2804         {
2805             if (typeof i == 'number' && isFinite(i)) {
2806                 this.pollInterval = i;
2807             }
2808         },
2809
2810         createXhrObject:function(transactionId)
2811         {
2812             var obj,http;
2813             try
2814             {
2815
2816                 http = new XMLHttpRequest();
2817
2818                 obj = { conn:http, tId:transactionId };
2819             }
2820             catch(e)
2821             {
2822                 for (var i = 0; i < this.activeX.length; ++i) {
2823                     try
2824                     {
2825
2826                         http = new ActiveXObject(this.activeX[i]);
2827
2828                         obj = { conn:http, tId:transactionId };
2829                         break;
2830                     }
2831                     catch(e) {
2832                     }
2833                 }
2834             }
2835             finally
2836             {
2837                 return obj;
2838             }
2839         },
2840
2841         getConnectionObject:function()
2842         {
2843             var o;
2844             var tId = this.transactionId;
2845
2846             try
2847             {
2848                 o = this.createXhrObject(tId);
2849                 if (o) {
2850                     this.transactionId++;
2851                 }
2852             }
2853             catch(e) {
2854             }
2855             finally
2856             {
2857                 return o;
2858             }
2859         },
2860
2861         asyncRequest:function(method, uri, callback, postData)
2862         {
2863             var o = this.getConnectionObject();
2864
2865             if (!o) {
2866                 return null;
2867             }
2868             else {
2869                 o.conn.open(method, uri, true);
2870
2871                 if (this.useDefaultXhrHeader) {
2872                     if (!this.defaultHeaders['X-Requested-With']) {
2873                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2874                     }
2875                 }
2876
2877                 if(postData && this.useDefaultHeader){
2878                     this.initHeader('Content-Type', this.defaultPostHeader);
2879                 }
2880
2881                  if (this.hasDefaultHeaders || this.hasHeaders) {
2882                     this.setHeader(o);
2883                 }
2884
2885                 this.handleReadyState(o, callback);
2886                 o.conn.send(postData || null);
2887
2888                 return o;
2889             }
2890         },
2891
2892         handleReadyState:function(o, callback)
2893         {
2894             var oConn = this;
2895
2896             if (callback && callback.timeout) {
2897                 
2898                 this.timeout[o.tId] = window.setTimeout(function() {
2899                     oConn.abort(o, callback, true);
2900                 }, callback.timeout);
2901             }
2902
2903             this.poll[o.tId] = window.setInterval(
2904                     function() {
2905                         if (o.conn && o.conn.readyState == 4) {
2906                             window.clearInterval(oConn.poll[o.tId]);
2907                             delete oConn.poll[o.tId];
2908
2909                             if(callback && callback.timeout) {
2910                                 window.clearTimeout(oConn.timeout[o.tId]);
2911                                 delete oConn.timeout[o.tId];
2912                             }
2913
2914                             oConn.handleTransactionResponse(o, callback);
2915                         }
2916                     }
2917                     , this.pollInterval);
2918         },
2919
2920         handleTransactionResponse:function(o, callback, isAbort)
2921         {
2922
2923             if (!callback) {
2924                 this.releaseObject(o);
2925                 return;
2926             }
2927
2928             var httpStatus, responseObject;
2929
2930             try
2931             {
2932                 if (o.conn.status !== undefined && o.conn.status != 0) {
2933                     httpStatus = o.conn.status;
2934                 }
2935                 else {
2936                     httpStatus = 13030;
2937                 }
2938             }
2939             catch(e) {
2940
2941
2942                 httpStatus = 13030;
2943             }
2944
2945             if (httpStatus >= 200 && httpStatus < 300) {
2946                 responseObject = this.createResponseObject(o, callback.argument);
2947                 if (callback.success) {
2948                     if (!callback.scope) {
2949                         callback.success(responseObject);
2950                     }
2951                     else {
2952
2953
2954                         callback.success.apply(callback.scope, [responseObject]);
2955                     }
2956                 }
2957             }
2958             else {
2959                 switch (httpStatus) {
2960
2961                     case 12002:
2962                     case 12029:
2963                     case 12030:
2964                     case 12031:
2965                     case 12152:
2966                     case 13030:
2967                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2968                         if (callback.failure) {
2969                             if (!callback.scope) {
2970                                 callback.failure(responseObject);
2971                             }
2972                             else {
2973                                 callback.failure.apply(callback.scope, [responseObject]);
2974                             }
2975                         }
2976                         break;
2977                     default:
2978                         responseObject = this.createResponseObject(o, callback.argument);
2979                         if (callback.failure) {
2980                             if (!callback.scope) {
2981                                 callback.failure(responseObject);
2982                             }
2983                             else {
2984                                 callback.failure.apply(callback.scope, [responseObject]);
2985                             }
2986                         }
2987                 }
2988             }
2989
2990             this.releaseObject(o);
2991             responseObject = null;
2992         },
2993
2994         createResponseObject:function(o, callbackArg)
2995         {
2996             var obj = {};
2997             var headerObj = {};
2998
2999             try
3000             {
3001                 var headerStr = o.conn.getAllResponseHeaders();
3002                 var header = headerStr.split('\n');
3003                 for (var i = 0; i < header.length; i++) {
3004                     var delimitPos = header[i].indexOf(':');
3005                     if (delimitPos != -1) {
3006                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3007                     }
3008                 }
3009             }
3010             catch(e) {
3011             }
3012
3013             obj.tId = o.tId;
3014             obj.status = o.conn.status;
3015             obj.statusText = o.conn.statusText;
3016             obj.getResponseHeader = headerObj;
3017             obj.getAllResponseHeaders = headerStr;
3018             obj.responseText = o.conn.responseText;
3019             obj.responseXML = o.conn.responseXML;
3020
3021             if (typeof callbackArg !== undefined) {
3022                 obj.argument = callbackArg;
3023             }
3024
3025             return obj;
3026         },
3027
3028         createExceptionObject:function(tId, callbackArg, isAbort)
3029         {
3030             var COMM_CODE = 0;
3031             var COMM_ERROR = 'communication failure';
3032             var ABORT_CODE = -1;
3033             var ABORT_ERROR = 'transaction aborted';
3034
3035             var obj = {};
3036
3037             obj.tId = tId;
3038             if (isAbort) {
3039                 obj.status = ABORT_CODE;
3040                 obj.statusText = ABORT_ERROR;
3041             }
3042             else {
3043                 obj.status = COMM_CODE;
3044                 obj.statusText = COMM_ERROR;
3045             }
3046
3047             if (callbackArg) {
3048                 obj.argument = callbackArg;
3049             }
3050
3051             return obj;
3052         },
3053
3054         initHeader:function(label, value, isDefault)
3055         {
3056             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3057
3058             if (headerObj[label] === undefined) {
3059                 headerObj[label] = value;
3060             }
3061             else {
3062
3063
3064                 headerObj[label] = value + "," + headerObj[label];
3065             }
3066
3067             if (isDefault) {
3068                 this.hasDefaultHeaders = true;
3069             }
3070             else {
3071                 this.hasHeaders = true;
3072             }
3073         },
3074
3075
3076         setHeader:function(o)
3077         {
3078             if (this.hasDefaultHeaders) {
3079                 for (var prop in this.defaultHeaders) {
3080                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3081                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3082                     }
3083                 }
3084             }
3085
3086             if (this.hasHeaders) {
3087                 for (var prop in this.headers) {
3088                     if (this.headers.hasOwnProperty(prop)) {
3089                         o.conn.setRequestHeader(prop, this.headers[prop]);
3090                     }
3091                 }
3092                 this.headers = {};
3093                 this.hasHeaders = false;
3094             }
3095         },
3096
3097         resetDefaultHeaders:function() {
3098             delete this.defaultHeaders;
3099             this.defaultHeaders = {};
3100             this.hasDefaultHeaders = false;
3101         },
3102
3103         abort:function(o, callback, isTimeout)
3104         {
3105             if(this.isCallInProgress(o)) {
3106                 o.conn.abort();
3107                 window.clearInterval(this.poll[o.tId]);
3108                 delete this.poll[o.tId];
3109                 if (isTimeout) {
3110                     delete this.timeout[o.tId];
3111                 }
3112
3113                 this.handleTransactionResponse(o, callback, true);
3114
3115                 return true;
3116             }
3117             else {
3118                 return false;
3119             }
3120         },
3121
3122
3123         isCallInProgress:function(o)
3124         {
3125             if (o && o.conn) {
3126                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3127             }
3128             else {
3129
3130                 return false;
3131             }
3132         },
3133
3134
3135         releaseObject:function(o)
3136         {
3137
3138             o.conn = null;
3139
3140             o = null;
3141         },
3142
3143         activeX:[
3144         'MSXML2.XMLHTTP.3.0',
3145         'MSXML2.XMLHTTP',
3146         'Microsoft.XMLHTTP'
3147         ]
3148
3149
3150     };
3151 })();/*
3152  * Portions of this file are based on pieces of Yahoo User Interface Library
3153  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3154  * YUI licensed under the BSD License:
3155  * http://developer.yahoo.net/yui/license.txt
3156  * <script type="text/javascript">
3157  *
3158  */
3159
3160 Roo.lib.Region = function(t, r, b, l) {
3161     this.top = t;
3162     this[1] = t;
3163     this.right = r;
3164     this.bottom = b;
3165     this.left = l;
3166     this[0] = l;
3167 };
3168
3169
3170 Roo.lib.Region.prototype = {
3171     contains : function(region) {
3172         return ( region.left >= this.left &&
3173                  region.right <= this.right &&
3174                  region.top >= this.top &&
3175                  region.bottom <= this.bottom    );
3176
3177     },
3178
3179     getArea : function() {
3180         return ( (this.bottom - this.top) * (this.right - this.left) );
3181     },
3182
3183     intersect : function(region) {
3184         var t = Math.max(this.top, region.top);
3185         var r = Math.min(this.right, region.right);
3186         var b = Math.min(this.bottom, region.bottom);
3187         var l = Math.max(this.left, region.left);
3188
3189         if (b >= t && r >= l) {
3190             return new Roo.lib.Region(t, r, b, l);
3191         } else {
3192             return null;
3193         }
3194     },
3195     union : function(region) {
3196         var t = Math.min(this.top, region.top);
3197         var r = Math.max(this.right, region.right);
3198         var b = Math.max(this.bottom, region.bottom);
3199         var l = Math.min(this.left, region.left);
3200
3201         return new Roo.lib.Region(t, r, b, l);
3202     },
3203
3204     adjust : function(t, l, b, r) {
3205         this.top += t;
3206         this.left += l;
3207         this.right += r;
3208         this.bottom += b;
3209         return this;
3210     }
3211 };
3212
3213 Roo.lib.Region.getRegion = function(el) {
3214     var p = Roo.lib.Dom.getXY(el);
3215
3216     var t = p[1];
3217     var r = p[0] + el.offsetWidth;
3218     var b = p[1] + el.offsetHeight;
3219     var l = p[0];
3220
3221     return new Roo.lib.Region(t, r, b, l);
3222 };
3223 /*
3224  * Portions of this file are based on pieces of Yahoo User Interface Library
3225  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3226  * YUI licensed under the BSD License:
3227  * http://developer.yahoo.net/yui/license.txt
3228  * <script type="text/javascript">
3229  *
3230  */
3231 //@@dep Roo.lib.Region
3232
3233
3234 Roo.lib.Point = function(x, y) {
3235     if (x instanceof Array) {
3236         y = x[1];
3237         x = x[0];
3238     }
3239     this.x = this.right = this.left = this[0] = x;
3240     this.y = this.top = this.bottom = this[1] = y;
3241 };
3242
3243 Roo.lib.Point.prototype = new Roo.lib.Region();
3244 /*
3245  * Portions of this file are based on pieces of Yahoo User Interface Library
3246  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3247  * YUI licensed under the BSD License:
3248  * http://developer.yahoo.net/yui/license.txt
3249  * <script type="text/javascript">
3250  *
3251  */
3252  
3253 (function() {   
3254
3255     Roo.lib.Anim = {
3256         scroll : function(el, args, duration, easing, cb, scope) {
3257             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3258         },
3259
3260         motion : function(el, args, duration, easing, cb, scope) {
3261             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3262         },
3263
3264         color : function(el, args, duration, easing, cb, scope) {
3265             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3266         },
3267
3268         run : function(el, args, duration, easing, cb, scope, type) {
3269             type = type || Roo.lib.AnimBase;
3270             if (typeof easing == "string") {
3271                 easing = Roo.lib.Easing[easing];
3272             }
3273             var anim = new type(el, args, duration, easing);
3274             anim.animateX(function() {
3275                 Roo.callback(cb, scope);
3276             });
3277             return anim;
3278         }
3279     };
3280 })();/*
3281  * Portions of this file are based on pieces of Yahoo User Interface Library
3282  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3283  * YUI licensed under the BSD License:
3284  * http://developer.yahoo.net/yui/license.txt
3285  * <script type="text/javascript">
3286  *
3287  */
3288
3289 (function() {    
3290     var libFlyweight;
3291     
3292     function fly(el) {
3293         if (!libFlyweight) {
3294             libFlyweight = new Roo.Element.Flyweight();
3295         }
3296         libFlyweight.dom = el;
3297         return libFlyweight;
3298     }
3299
3300     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3301     
3302    
3303     
3304     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3305         if (el) {
3306             this.init(el, attributes, duration, method);
3307         }
3308     };
3309
3310     Roo.lib.AnimBase.fly = fly;
3311     
3312     
3313     
3314     Roo.lib.AnimBase.prototype = {
3315
3316         toString: function() {
3317             var el = this.getEl();
3318             var id = el.id || el.tagName;
3319             return ("Anim " + id);
3320         },
3321
3322         patterns: {
3323             noNegatives:        /width|height|opacity|padding/i,
3324             offsetAttribute:  /^((width|height)|(top|left))$/,
3325             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3326             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3327         },
3328
3329
3330         doMethod: function(attr, start, end) {
3331             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3332         },
3333
3334
3335         setAttribute: function(attr, val, unit) {
3336             if (this.patterns.noNegatives.test(attr)) {
3337                 val = (val > 0) ? val : 0;
3338             }
3339
3340             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3341         },
3342
3343
3344         getAttribute: function(attr) {
3345             var el = this.getEl();
3346             var val = fly(el).getStyle(attr);
3347
3348             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3349                 return parseFloat(val);
3350             }
3351
3352             var a = this.patterns.offsetAttribute.exec(attr) || [];
3353             var pos = !!( a[3] );
3354             var box = !!( a[2] );
3355
3356
3357             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3358                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3359             } else {
3360                 val = 0;
3361             }
3362
3363             return val;
3364         },
3365
3366
3367         getDefaultUnit: function(attr) {
3368             if (this.patterns.defaultUnit.test(attr)) {
3369                 return 'px';
3370             }
3371
3372             return '';
3373         },
3374
3375         animateX : function(callback, scope) {
3376             var f = function() {
3377                 this.onComplete.removeListener(f);
3378                 if (typeof callback == "function") {
3379                     callback.call(scope || this, this);
3380                 }
3381             };
3382             this.onComplete.addListener(f, this);
3383             this.animate();
3384         },
3385
3386
3387         setRuntimeAttribute: function(attr) {
3388             var start;
3389             var end;
3390             var attributes = this.attributes;
3391
3392             this.runtimeAttributes[attr] = {};
3393
3394             var isset = function(prop) {
3395                 return (typeof prop !== 'undefined');
3396             };
3397
3398             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3399                 return false;
3400             }
3401
3402             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3403
3404
3405             if (isset(attributes[attr]['to'])) {
3406                 end = attributes[attr]['to'];
3407             } else if (isset(attributes[attr]['by'])) {
3408                 if (start.constructor == Array) {
3409                     end = [];
3410                     for (var i = 0, len = start.length; i < len; ++i) {
3411                         end[i] = start[i] + attributes[attr]['by'][i];
3412                     }
3413                 } else {
3414                     end = start + attributes[attr]['by'];
3415                 }
3416             }
3417
3418             this.runtimeAttributes[attr].start = start;
3419             this.runtimeAttributes[attr].end = end;
3420
3421
3422             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3423         },
3424
3425
3426         init: function(el, attributes, duration, method) {
3427
3428             var isAnimated = false;
3429
3430
3431             var startTime = null;
3432
3433
3434             var actualFrames = 0;
3435
3436
3437             el = Roo.getDom(el);
3438
3439
3440             this.attributes = attributes || {};
3441
3442
3443             this.duration = duration || 1;
3444
3445
3446             this.method = method || Roo.lib.Easing.easeNone;
3447
3448
3449             this.useSeconds = true;
3450
3451
3452             this.currentFrame = 0;
3453
3454
3455             this.totalFrames = Roo.lib.AnimMgr.fps;
3456
3457
3458             this.getEl = function() {
3459                 return el;
3460             };
3461
3462
3463             this.isAnimated = function() {
3464                 return isAnimated;
3465             };
3466
3467
3468             this.getStartTime = function() {
3469                 return startTime;
3470             };
3471
3472             this.runtimeAttributes = {};
3473
3474
3475             this.animate = function() {
3476                 if (this.isAnimated()) {
3477                     return false;
3478                 }
3479
3480                 this.currentFrame = 0;
3481
3482                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3483
3484                 Roo.lib.AnimMgr.registerElement(this);
3485             };
3486
3487
3488             this.stop = function(finish) {
3489                 if (finish) {
3490                     this.currentFrame = this.totalFrames;
3491                     this._onTween.fire();
3492                 }
3493                 Roo.lib.AnimMgr.stop(this);
3494             };
3495
3496             var onStart = function() {
3497                 this.onStart.fire();
3498
3499                 this.runtimeAttributes = {};
3500                 for (var attr in this.attributes) {
3501                     this.setRuntimeAttribute(attr);
3502                 }
3503
3504                 isAnimated = true;
3505                 actualFrames = 0;
3506                 startTime = new Date();
3507             };
3508
3509
3510             var onTween = function() {
3511                 var data = {
3512                     duration: new Date() - this.getStartTime(),
3513                     currentFrame: this.currentFrame
3514                 };
3515
3516                 data.toString = function() {
3517                     return (
3518                             'duration: ' + data.duration +
3519                             ', currentFrame: ' + data.currentFrame
3520                             );
3521                 };
3522
3523                 this.onTween.fire(data);
3524
3525                 var runtimeAttributes = this.runtimeAttributes;
3526
3527                 for (var attr in runtimeAttributes) {
3528                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3529                 }
3530
3531                 actualFrames += 1;
3532             };
3533
3534             var onComplete = function() {
3535                 var actual_duration = (new Date() - startTime) / 1000 ;
3536
3537                 var data = {
3538                     duration: actual_duration,
3539                     frames: actualFrames,
3540                     fps: actualFrames / actual_duration
3541                 };
3542
3543                 data.toString = function() {
3544                     return (
3545                             'duration: ' + data.duration +
3546                             ', frames: ' + data.frames +
3547                             ', fps: ' + data.fps
3548                             );
3549                 };
3550
3551                 isAnimated = false;
3552                 actualFrames = 0;
3553                 this.onComplete.fire(data);
3554             };
3555
3556
3557             this._onStart = new Roo.util.Event(this);
3558             this.onStart = new Roo.util.Event(this);
3559             this.onTween = new Roo.util.Event(this);
3560             this._onTween = new Roo.util.Event(this);
3561             this.onComplete = new Roo.util.Event(this);
3562             this._onComplete = new Roo.util.Event(this);
3563             this._onStart.addListener(onStart);
3564             this._onTween.addListener(onTween);
3565             this._onComplete.addListener(onComplete);
3566         }
3567     };
3568 })();
3569 /*
3570  * Portions of this file are based on pieces of Yahoo User Interface Library
3571  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3572  * YUI licensed under the BSD License:
3573  * http://developer.yahoo.net/yui/license.txt
3574  * <script type="text/javascript">
3575  *
3576  */
3577
3578 Roo.lib.AnimMgr = new function() {
3579
3580     var thread = null;
3581
3582
3583     var queue = [];
3584
3585
3586     var tweenCount = 0;
3587
3588
3589     this.fps = 1000;
3590
3591
3592     this.delay = 1;
3593
3594
3595     this.registerElement = function(tween) {
3596         queue[queue.length] = tween;
3597         tweenCount += 1;
3598         tween._onStart.fire();
3599         this.start();
3600     };
3601
3602
3603     this.unRegister = function(tween, index) {
3604         tween._onComplete.fire();
3605         index = index || getIndex(tween);
3606         if (index != -1) {
3607             queue.splice(index, 1);
3608         }
3609
3610         tweenCount -= 1;
3611         if (tweenCount <= 0) {
3612             this.stop();
3613         }
3614     };
3615
3616
3617     this.start = function() {
3618         if (thread === null) {
3619             thread = setInterval(this.run, this.delay);
3620         }
3621     };
3622
3623
3624     this.stop = function(tween) {
3625         if (!tween) {
3626             clearInterval(thread);
3627
3628             for (var i = 0, len = queue.length; i < len; ++i) {
3629                 if (queue[0].isAnimated()) {
3630                     this.unRegister(queue[0], 0);
3631                 }
3632             }
3633
3634             queue = [];
3635             thread = null;
3636             tweenCount = 0;
3637         }
3638         else {
3639             this.unRegister(tween);
3640         }
3641     };
3642
3643
3644     this.run = function() {
3645         for (var i = 0, len = queue.length; i < len; ++i) {
3646             var tween = queue[i];
3647             if (!tween || !tween.isAnimated()) {
3648                 continue;
3649             }
3650
3651             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3652             {
3653                 tween.currentFrame += 1;
3654
3655                 if (tween.useSeconds) {
3656                     correctFrame(tween);
3657                 }
3658                 tween._onTween.fire();
3659             }
3660             else {
3661                 Roo.lib.AnimMgr.stop(tween, i);
3662             }
3663         }
3664     };
3665
3666     var getIndex = function(anim) {
3667         for (var i = 0, len = queue.length; i < len; ++i) {
3668             if (queue[i] == anim) {
3669                 return i;
3670             }
3671         }
3672         return -1;
3673     };
3674
3675
3676     var correctFrame = function(tween) {
3677         var frames = tween.totalFrames;
3678         var frame = tween.currentFrame;
3679         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3680         var elapsed = (new Date() - tween.getStartTime());
3681         var tweak = 0;
3682
3683         if (elapsed < tween.duration * 1000) {
3684             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3685         } else {
3686             tweak = frames - (frame + 1);
3687         }
3688         if (tweak > 0 && isFinite(tweak)) {
3689             if (tween.currentFrame + tweak >= frames) {
3690                 tweak = frames - (frame + 1);
3691             }
3692
3693             tween.currentFrame += tweak;
3694         }
3695     };
3696 };
3697
3698     /*
3699  * Portions of this file are based on pieces of Yahoo User Interface Library
3700  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701  * YUI licensed under the BSD License:
3702  * http://developer.yahoo.net/yui/license.txt
3703  * <script type="text/javascript">
3704  *
3705  */
3706 Roo.lib.Bezier = new function() {
3707
3708         this.getPosition = function(points, t) {
3709             var n = points.length;
3710             var tmp = [];
3711
3712             for (var i = 0; i < n; ++i) {
3713                 tmp[i] = [points[i][0], points[i][1]];
3714             }
3715
3716             for (var j = 1; j < n; ++j) {
3717                 for (i = 0; i < n - j; ++i) {
3718                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3719                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3720                 }
3721             }
3722
3723             return [ tmp[0][0], tmp[0][1] ];
3724
3725         };
3726     }; 
3727
3728 /**
3729  * @class Roo.lib.Color
3730  * @constructor
3731  * An abstract Color implementation. Concrete Color implementations should use
3732  * an instance of this function as their prototype, and implement the getRGB and
3733  * getHSL functions. getRGB should return an object representing the RGB
3734  * components of this Color, with the red, green, and blue components in the
3735  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3736  * return an object representing the HSL components of this Color, with the hue
3737  * component in the range [0,360), the saturation and lightness components in
3738  * the range [0,100], and the alpha component in the range [0,1].
3739  *
3740  *
3741  * Color.js
3742  *
3743  * Functions for Color handling and processing.
3744  *
3745  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3746  *
3747  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3748  * rights to this program, with the intention of it becoming part of the public
3749  * domain. Because this program is released into the public domain, it comes with
3750  * no warranty either expressed or implied, to the extent permitted by law.
3751  * 
3752  * For more free and public domain JavaScript code by the same author, visit:
3753  * http://www.safalra.com/web-design/javascript/
3754  * 
3755  */
3756 Roo.lib.Color = function() { }
3757
3758
3759 Roo.apply(Roo.lib.Color.prototype, {
3760   
3761   rgb : null,
3762   hsv : null,
3763   hsl : null,
3764   
3765   /**
3766    * getIntegerRGB
3767    * @return {Object} an object representing the RGBA components of this Color. The red,
3768    * green, and blue components are converted to integers in the range [0,255].
3769    * The alpha is a value in the range [0,1].
3770    */
3771   getIntegerRGB : function(){
3772
3773     // get the RGB components of this Color
3774     var rgb = this.getRGB();
3775
3776     // return the integer components
3777     return {
3778       'r' : Math.round(rgb.r),
3779       'g' : Math.round(rgb.g),
3780       'b' : Math.round(rgb.b),
3781       'a' : rgb.a
3782     };
3783
3784   },
3785
3786   /**
3787    * getPercentageRGB
3788    * @return {Object} an object representing the RGBA components of this Color. The red,
3789    * green, and blue components are converted to numbers in the range [0,100].
3790    * The alpha is a value in the range [0,1].
3791    */
3792   getPercentageRGB : function(){
3793
3794     // get the RGB components of this Color
3795     var rgb = this.getRGB();
3796
3797     // return the percentage components
3798     return {
3799       'r' : 100 * rgb.r / 255,
3800       'g' : 100 * rgb.g / 255,
3801       'b' : 100 * rgb.b / 255,
3802       'a' : rgb.a
3803     };
3804
3805   },
3806
3807   /**
3808    * getCSSHexadecimalRGB
3809    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3810    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3811    * are two-digit hexadecimal numbers.
3812    */
3813   getCSSHexadecimalRGB : function()
3814   {
3815
3816     // get the integer RGB components
3817     var rgb = this.getIntegerRGB();
3818
3819     // determine the hexadecimal equivalents
3820     var r16 = rgb.r.toString(16);
3821     var g16 = rgb.g.toString(16);
3822     var b16 = rgb.b.toString(16);
3823
3824     // return the CSS RGB Color value
3825     return '#'
3826         + (r16.length == 2 ? r16 : '0' + r16)
3827         + (g16.length == 2 ? g16 : '0' + g16)
3828         + (b16.length == 2 ? b16 : '0' + b16);
3829
3830   },
3831
3832   /**
3833    * getCSSIntegerRGB
3834    * @return {String} a string representing this Color as a CSS integer RGB Color
3835    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3836    * are integers in the range [0,255].
3837    */
3838   getCSSIntegerRGB : function(){
3839
3840     // get the integer RGB components
3841     var rgb = this.getIntegerRGB();
3842
3843     // return the CSS RGB Color value
3844     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3845
3846   },
3847
3848   /**
3849    * getCSSIntegerRGBA
3850    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3851    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3852    * b are integers in the range [0,255] and a is in the range [0,1].
3853    */
3854   getCSSIntegerRGBA : function(){
3855
3856     // get the integer RGB components
3857     var rgb = this.getIntegerRGB();
3858
3859     // return the CSS integer RGBA Color value
3860     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3861
3862   },
3863
3864   /**
3865    * getCSSPercentageRGB
3866    * @return {String} a string representing this Color as a CSS percentage RGB Color
3867    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3868    * b are in the range [0,100].
3869    */
3870   getCSSPercentageRGB : function(){
3871
3872     // get the percentage RGB components
3873     var rgb = this.getPercentageRGB();
3874
3875     // return the CSS RGB Color value
3876     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3877
3878   },
3879
3880   /**
3881    * getCSSPercentageRGBA
3882    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3883    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3884    * and b are in the range [0,100] and a is in the range [0,1].
3885    */
3886   getCSSPercentageRGBA : function(){
3887
3888     // get the percentage RGB components
3889     var rgb = this.getPercentageRGB();
3890
3891     // return the CSS percentage RGBA Color value
3892     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3893
3894   },
3895
3896   /**
3897    * getCSSHSL
3898    * @return {String} a string representing this Color as a CSS HSL Color value - that
3899    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3900    * s and l are in the range [0,100].
3901    */
3902   getCSSHSL : function(){
3903
3904     // get the HSL components
3905     var hsl = this.getHSL();
3906
3907     // return the CSS HSL Color value
3908     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3909
3910   },
3911
3912   /**
3913    * getCSSHSLA
3914    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3915    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3916    * s and l are in the range [0,100], and a is in the range [0,1].
3917    */
3918   getCSSHSLA : function(){
3919
3920     // get the HSL components
3921     var hsl = this.getHSL();
3922
3923     // return the CSS HSL Color value
3924     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3925
3926   },
3927
3928   /**
3929    * Sets the Color of the specified node to this Color. This functions sets
3930    * the CSS 'color' property for the node. The parameter is:
3931    * 
3932    * @param {DomElement} node - the node whose Color should be set
3933    */
3934   setNodeColor : function(node){
3935
3936     // set the Color of the node
3937     node.style.color = this.getCSSHexadecimalRGB();
3938
3939   },
3940
3941   /**
3942    * Sets the background Color of the specified node to this Color. This
3943    * functions sets the CSS 'background-color' property for the node. The
3944    * parameter is:
3945    *
3946    * @param {DomElement} node - the node whose background Color should be set
3947    */
3948   setNodeBackgroundColor : function(node){
3949
3950     // set the background Color of the node
3951     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3952
3953   },
3954   // convert between formats..
3955   toRGB: function()
3956   {
3957     var r = this.getIntegerRGB();
3958     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3959     
3960   },
3961   toHSL : function()
3962   {
3963      var hsl = this.getHSL();
3964   // return the CSS HSL Color value
3965     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3966     
3967   },
3968   
3969   toHSV : function()
3970   {
3971     var rgb = this.toRGB();
3972     var hsv = rgb.getHSV();
3973    // return the CSS HSL Color value
3974     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3975     
3976   },
3977   
3978   // modify  v = 0 ... 1 (eg. 0.5)
3979   saturate : function(v)
3980   {
3981       var rgb = this.toRGB();
3982       var hsv = rgb.getHSV();
3983       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3984       
3985   
3986   },
3987   
3988    
3989   /**
3990    * getRGB
3991    * @return {Object} the RGB and alpha components of this Color as an object with r,
3992    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3993    * the range [0,1].
3994    */
3995   getRGB: function(){
3996    
3997     // return the RGB components
3998     return {
3999       'r' : this.rgb.r,
4000       'g' : this.rgb.g,
4001       'b' : this.rgb.b,
4002       'a' : this.alpha
4003     };
4004
4005   },
4006
4007   /**
4008    * getHSV
4009    * @return {Object} the HSV and alpha components of this Color as an object with h,
4010    * s, v, and a properties. h is in the range [0,360), s and v are in the range
4011    * [0,100], and a is in the range [0,1].
4012    */
4013   getHSV : function()
4014   {
4015     
4016     // calculate the HSV components if necessary
4017     if (this.hsv == null) {
4018       this.calculateHSV();
4019     }
4020
4021     // return the HSV components
4022     return {
4023       'h' : this.hsv.h,
4024       's' : this.hsv.s,
4025       'v' : this.hsv.v,
4026       'a' : this.alpha
4027     };
4028
4029   },
4030
4031   /**
4032    * getHSL
4033    * @return {Object} the HSL and alpha components of this Color as an object with h,
4034    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4035    * [0,100], and a is in the range [0,1].
4036    */
4037   getHSL : function(){
4038     
4039      
4040     // calculate the HSV components if necessary
4041     if (this.hsl == null) { this.calculateHSL(); }
4042
4043     // return the HSL components
4044     return {
4045       'h' : this.hsl.h,
4046       's' : this.hsl.s,
4047       'l' : this.hsl.l,
4048       'a' : this.alpha
4049     };
4050
4051   }
4052   
4053
4054 });
4055
4056
4057 /**
4058  * @class Roo.lib.RGBColor
4059  * @extends Roo.lib.Color
4060  * Creates a Color specified in the RGB Color space, with an optional alpha
4061  * component. The parameters are:
4062  * @constructor
4063  * 
4064
4065  * @param {Number} r - the red component, clipped to the range [0,255]
4066  * @param {Number} g - the green component, clipped to the range [0,255]
4067  * @param {Number} b - the blue component, clipped to the range [0,255]
4068  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4069  *     optional and defaults to 1
4070  */
4071 Roo.lib.RGBColor = function (r, g, b, a){
4072
4073   // store the alpha component after clipping it if necessary
4074   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4075
4076   // store the RGB components after clipping them if necessary
4077   this.rgb =
4078       {
4079         'r' : Math.max(0, Math.min(255, r)),
4080         'g' : Math.max(0, Math.min(255, g)),
4081         'b' : Math.max(0, Math.min(255, b))
4082       };
4083
4084   // initialise the HSV and HSL components to null
4085   
4086
4087   /* 
4088    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4089    * range [0,360). The parameters are:
4090    *
4091    * maximum - the maximum of the RGB component values
4092    * range   - the range of the RGB component values
4093    */
4094    
4095
4096 }
4097 // this does an 'exteds'
4098 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4099
4100   
4101     getHue  : function(maximum, range)
4102     {
4103       var rgb = this.rgb;
4104        
4105       // check whether the range is zero
4106       if (range == 0){
4107   
4108         // set the hue to zero (any hue is acceptable as the Color is grey)
4109         var hue = 0;
4110   
4111       }else{
4112   
4113         // determine which of the components has the highest value and set the hue
4114         switch (maximum){
4115   
4116           // red has the highest value
4117           case rgb.r:
4118             var hue = (rgb.g - rgb.b) / range * 60;
4119             if (hue < 0) { hue += 360; }
4120             break;
4121   
4122           // green has the highest value
4123           case rgb.g:
4124             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4125             break;
4126   
4127           // blue has the highest value
4128           case rgb.b:
4129             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4130             break;
4131   
4132         }
4133   
4134       }
4135   
4136       // return the hue
4137       return hue;
4138   
4139     },
4140
4141   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4142    * be returned be the getHSV function.
4143    */
4144    calculateHSV : function(){
4145     var rgb = this.rgb;
4146     // get the maximum and range of the RGB component values
4147     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4148     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4149
4150     // store the HSV components
4151     this.hsv =
4152         {
4153           'h' : this.getHue(maximum, range),
4154           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4155           'v' : maximum / 2.55
4156         };
4157
4158   },
4159
4160   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4161    * be returned be the getHSL function.
4162    */
4163    calculateHSL : function(){
4164     var rgb = this.rgb;
4165     // get the maximum and range of the RGB component values
4166     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4167     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4168
4169     // determine the lightness in the range [0,1]
4170     var l = maximum / 255 - range / 510;
4171
4172     // store the HSL components
4173     this.hsl =
4174         {
4175           'h' : this.getHue(maximum, range),
4176           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4177           'l' : 100 * l
4178         };
4179
4180   }
4181
4182 });
4183
4184 /**
4185  * @class Roo.lib.HSVColor
4186  * @extends Roo.lib.Color
4187  * Creates a Color specified in the HSV Color space, with an optional alpha
4188  * component. The parameters are:
4189  * @constructor
4190  *
4191  * @param {Number} h - the hue component, wrapped to the range [0,360)
4192  * @param {Number} s - the saturation component, clipped to the range [0,100]
4193  * @param {Number} v - the value component, clipped to the range [0,100]
4194  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4195  *     optional and defaults to 1
4196  */
4197 Roo.lib.HSVColor = function (h, s, v, a){
4198
4199   // store the alpha component after clipping it if necessary
4200   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4201
4202   // store the HSV components after clipping or wrapping them if necessary
4203   this.hsv =
4204       {
4205         'h' : (h % 360 + 360) % 360,
4206         's' : Math.max(0, Math.min(100, s)),
4207         'v' : Math.max(0, Math.min(100, v))
4208       };
4209
4210   // initialise the RGB and HSL components to null
4211   this.rgb = null;
4212   this.hsl = null;
4213 }
4214
4215 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4216   /* Calculates and stores the RGB components of this HSVColor so that they can
4217    * be returned be the getRGB function.
4218    */
4219   calculateRGB: function ()
4220   {
4221     var hsv = this.hsv;
4222     // check whether the saturation is zero
4223     if (hsv.s == 0){
4224
4225       // set the Color to the appropriate shade of grey
4226       var r = hsv.v;
4227       var g = hsv.v;
4228       var b = hsv.v;
4229
4230     }else{
4231
4232       // set some temporary values
4233       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4234       var p  = hsv.v * (1 - hsv.s / 100);
4235       var q  = hsv.v * (1 - hsv.s / 100 * f);
4236       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4237
4238       // set the RGB Color components to their temporary values
4239       switch (Math.floor(hsv.h / 60)){
4240         case 0: var r = hsv.v; var g = t; var b = p; break;
4241         case 1: var r = q; var g = hsv.v; var b = p; break;
4242         case 2: var r = p; var g = hsv.v; var b = t; break;
4243         case 3: var r = p; var g = q; var b = hsv.v; break;
4244         case 4: var r = t; var g = p; var b = hsv.v; break;
4245         case 5: var r = hsv.v; var g = p; var b = q; break;
4246       }
4247
4248     }
4249
4250     // store the RGB components
4251     this.rgb =
4252         {
4253           'r' : r * 2.55,
4254           'g' : g * 2.55,
4255           'b' : b * 2.55
4256         };
4257
4258   },
4259
4260   /* Calculates and stores the HSL components of this HSVColor so that they can
4261    * be returned be the getHSL function.
4262    */
4263   calculateHSL : function (){
4264
4265     var hsv = this.hsv;
4266     // determine the lightness in the range [0,100]
4267     var l = (2 - hsv.s / 100) * hsv.v / 2;
4268
4269     // store the HSL components
4270     this.hsl =
4271         {
4272           'h' : hsv.h,
4273           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4274           'l' : l
4275         };
4276
4277     // correct a division-by-zero error
4278     if (isNaN(hsl.s)) { hsl.s = 0; }
4279
4280   } 
4281  
4282
4283 });
4284  
4285
4286 /**
4287  * @class Roo.lib.HSLColor
4288  * @extends Roo.lib.Color
4289  *
4290  * @constructor
4291  * Creates a Color specified in the HSL Color space, with an optional alpha
4292  * component. The parameters are:
4293  *
4294  * @param {Number} h - the hue component, wrapped to the range [0,360)
4295  * @param {Number} s - the saturation component, clipped to the range [0,100]
4296  * @param {Number} l - the lightness component, clipped to the range [0,100]
4297  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4298  *     optional and defaults to 1
4299  */
4300
4301 Roo.lib.HSLColor = function(h, s, l, a){
4302
4303   // store the alpha component after clipping it if necessary
4304   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4305
4306   // store the HSL components after clipping or wrapping them if necessary
4307   this.hsl =
4308       {
4309         'h' : (h % 360 + 360) % 360,
4310         's' : Math.max(0, Math.min(100, s)),
4311         'l' : Math.max(0, Math.min(100, l))
4312       };
4313
4314   // initialise the RGB and HSV components to null
4315 }
4316
4317 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4318
4319   /* Calculates and stores the RGB components of this HSLColor so that they can
4320    * be returned be the getRGB function.
4321    */
4322   calculateRGB: function (){
4323
4324     // check whether the saturation is zero
4325     if (this.hsl.s == 0){
4326
4327       // store the RGB components representing the appropriate shade of grey
4328       this.rgb =
4329           {
4330             'r' : this.hsl.l * 2.55,
4331             'g' : this.hsl.l * 2.55,
4332             'b' : this.hsl.l * 2.55
4333           };
4334
4335     }else{
4336
4337       // set some temporary values
4338       var p = this.hsl.l < 50
4339             ? this.hsl.l * (1 + hsl.s / 100)
4340             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4341       var q = 2 * hsl.l - p;
4342
4343       // initialise the RGB components
4344       this.rgb =
4345           {
4346             'r' : (h + 120) / 60 % 6,
4347             'g' : h / 60,
4348             'b' : (h + 240) / 60 % 6
4349           };
4350
4351       // loop over the RGB components
4352       for (var key in this.rgb){
4353
4354         // ensure that the property is not inherited from the root object
4355         if (this.rgb.hasOwnProperty(key)){
4356
4357           // set the component to its value in the range [0,100]
4358           if (this.rgb[key] < 1){
4359             this.rgb[key] = q + (p - q) * this.rgb[key];
4360           }else if (this.rgb[key] < 3){
4361             this.rgb[key] = p;
4362           }else if (this.rgb[key] < 4){
4363             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4364           }else{
4365             this.rgb[key] = q;
4366           }
4367
4368           // set the component to its value in the range [0,255]
4369           this.rgb[key] *= 2.55;
4370
4371         }
4372
4373       }
4374
4375     }
4376
4377   },
4378
4379   /* Calculates and stores the HSV components of this HSLColor so that they can
4380    * be returned be the getHSL function.
4381    */
4382    calculateHSV : function(){
4383
4384     // set a temporary value
4385     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4386
4387     // store the HSV components
4388     this.hsv =
4389         {
4390           'h' : this.hsl.h,
4391           's' : 200 * t / (this.hsl.l + t),
4392           'v' : t + this.hsl.l
4393         };
4394
4395     // correct a division-by-zero error
4396     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4397
4398   }
4399  
4400
4401 });
4402 /*
4403  * Portions of this file are based on pieces of Yahoo User Interface Library
4404  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4405  * YUI licensed under the BSD License:
4406  * http://developer.yahoo.net/yui/license.txt
4407  * <script type="text/javascript">
4408  *
4409  */
4410 (function() {
4411
4412     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4413         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4414     };
4415
4416     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4417
4418     var fly = Roo.lib.AnimBase.fly;
4419     var Y = Roo.lib;
4420     var superclass = Y.ColorAnim.superclass;
4421     var proto = Y.ColorAnim.prototype;
4422
4423     proto.toString = function() {
4424         var el = this.getEl();
4425         var id = el.id || el.tagName;
4426         return ("ColorAnim " + id);
4427     };
4428
4429     proto.patterns.color = /color$/i;
4430     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4431     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4432     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4433     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4434
4435
4436     proto.parseColor = function(s) {
4437         if (s.length == 3) {
4438             return s;
4439         }
4440
4441         var c = this.patterns.hex.exec(s);
4442         if (c && c.length == 4) {
4443             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4444         }
4445
4446         c = this.patterns.rgb.exec(s);
4447         if (c && c.length == 4) {
4448             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4449         }
4450
4451         c = this.patterns.hex3.exec(s);
4452         if (c && c.length == 4) {
4453             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4454         }
4455
4456         return null;
4457     };
4458     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4459     proto.getAttribute = function(attr) {
4460         var el = this.getEl();
4461         if (this.patterns.color.test(attr)) {
4462             var val = fly(el).getStyle(attr);
4463
4464             if (this.patterns.transparent.test(val)) {
4465                 var parent = el.parentNode;
4466                 val = fly(parent).getStyle(attr);
4467
4468                 while (parent && this.patterns.transparent.test(val)) {
4469                     parent = parent.parentNode;
4470                     val = fly(parent).getStyle(attr);
4471                     if (parent.tagName.toUpperCase() == 'HTML') {
4472                         val = '#fff';
4473                     }
4474                 }
4475             }
4476         } else {
4477             val = superclass.getAttribute.call(this, attr);
4478         }
4479
4480         return val;
4481     };
4482     proto.getAttribute = function(attr) {
4483         var el = this.getEl();
4484         if (this.patterns.color.test(attr)) {
4485             var val = fly(el).getStyle(attr);
4486
4487             if (this.patterns.transparent.test(val)) {
4488                 var parent = el.parentNode;
4489                 val = fly(parent).getStyle(attr);
4490
4491                 while (parent && this.patterns.transparent.test(val)) {
4492                     parent = parent.parentNode;
4493                     val = fly(parent).getStyle(attr);
4494                     if (parent.tagName.toUpperCase() == 'HTML') {
4495                         val = '#fff';
4496                     }
4497                 }
4498             }
4499         } else {
4500             val = superclass.getAttribute.call(this, attr);
4501         }
4502
4503         return val;
4504     };
4505
4506     proto.doMethod = function(attr, start, end) {
4507         var val;
4508
4509         if (this.patterns.color.test(attr)) {
4510             val = [];
4511             for (var i = 0, len = start.length; i < len; ++i) {
4512                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4513             }
4514
4515             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4516         }
4517         else {
4518             val = superclass.doMethod.call(this, attr, start, end);
4519         }
4520
4521         return val;
4522     };
4523
4524     proto.setRuntimeAttribute = function(attr) {
4525         superclass.setRuntimeAttribute.call(this, attr);
4526
4527         if (this.patterns.color.test(attr)) {
4528             var attributes = this.attributes;
4529             var start = this.parseColor(this.runtimeAttributes[attr].start);
4530             var end = this.parseColor(this.runtimeAttributes[attr].end);
4531
4532             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4533                 end = this.parseColor(attributes[attr].by);
4534
4535                 for (var i = 0, len = start.length; i < len; ++i) {
4536                     end[i] = start[i] + end[i];
4537                 }
4538             }
4539
4540             this.runtimeAttributes[attr].start = start;
4541             this.runtimeAttributes[attr].end = end;
4542         }
4543     };
4544 })();
4545
4546 /*
4547  * Portions of this file are based on pieces of Yahoo User Interface Library
4548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4549  * YUI licensed under the BSD License:
4550  * http://developer.yahoo.net/yui/license.txt
4551  * <script type="text/javascript">
4552  *
4553  */
4554 Roo.lib.Easing = {
4555
4556
4557     easeNone: function (t, b, c, d) {
4558         return c * t / d + b;
4559     },
4560
4561
4562     easeIn: function (t, b, c, d) {
4563         return c * (t /= d) * t + b;
4564     },
4565
4566
4567     easeOut: function (t, b, c, d) {
4568         return -c * (t /= d) * (t - 2) + b;
4569     },
4570
4571
4572     easeBoth: function (t, b, c, d) {
4573         if ((t /= d / 2) < 1) {
4574             return c / 2 * t * t + b;
4575         }
4576
4577         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4578     },
4579
4580
4581     easeInStrong: function (t, b, c, d) {
4582         return c * (t /= d) * t * t * t + b;
4583     },
4584
4585
4586     easeOutStrong: function (t, b, c, d) {
4587         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4588     },
4589
4590
4591     easeBothStrong: function (t, b, c, d) {
4592         if ((t /= d / 2) < 1) {
4593             return c / 2 * t * t * t * t + b;
4594         }
4595
4596         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4597     },
4598
4599
4600
4601     elasticIn: function (t, b, c, d, a, p) {
4602         if (t == 0) {
4603             return b;
4604         }
4605         if ((t /= d) == 1) {
4606             return b + c;
4607         }
4608         if (!p) {
4609             p = d * .3;
4610         }
4611
4612         if (!a || a < Math.abs(c)) {
4613             a = c;
4614             var s = p / 4;
4615         }
4616         else {
4617             var s = p / (2 * Math.PI) * Math.asin(c / a);
4618         }
4619
4620         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4621     },
4622
4623
4624     elasticOut: function (t, b, c, d, a, p) {
4625         if (t == 0) {
4626             return b;
4627         }
4628         if ((t /= d) == 1) {
4629             return b + c;
4630         }
4631         if (!p) {
4632             p = d * .3;
4633         }
4634
4635         if (!a || a < Math.abs(c)) {
4636             a = c;
4637             var s = p / 4;
4638         }
4639         else {
4640             var s = p / (2 * Math.PI) * Math.asin(c / a);
4641         }
4642
4643         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4644     },
4645
4646
4647     elasticBoth: function (t, b, c, d, a, p) {
4648         if (t == 0) {
4649             return b;
4650         }
4651
4652         if ((t /= d / 2) == 2) {
4653             return b + c;
4654         }
4655
4656         if (!p) {
4657             p = d * (.3 * 1.5);
4658         }
4659
4660         if (!a || a < Math.abs(c)) {
4661             a = c;
4662             var s = p / 4;
4663         }
4664         else {
4665             var s = p / (2 * Math.PI) * Math.asin(c / a);
4666         }
4667
4668         if (t < 1) {
4669             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4670                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4671         }
4672         return a * Math.pow(2, -10 * (t -= 1)) *
4673                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4674     },
4675
4676
4677
4678     backIn: function (t, b, c, d, s) {
4679         if (typeof s == 'undefined') {
4680             s = 1.70158;
4681         }
4682         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4683     },
4684
4685
4686     backOut: function (t, b, c, d, s) {
4687         if (typeof s == 'undefined') {
4688             s = 1.70158;
4689         }
4690         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4691     },
4692
4693
4694     backBoth: function (t, b, c, d, s) {
4695         if (typeof s == 'undefined') {
4696             s = 1.70158;
4697         }
4698
4699         if ((t /= d / 2 ) < 1) {
4700             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4701         }
4702         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4703     },
4704
4705
4706     bounceIn: function (t, b, c, d) {
4707         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4708     },
4709
4710
4711     bounceOut: function (t, b, c, d) {
4712         if ((t /= d) < (1 / 2.75)) {
4713             return c * (7.5625 * t * t) + b;
4714         } else if (t < (2 / 2.75)) {
4715             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4716         } else if (t < (2.5 / 2.75)) {
4717             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4718         }
4719         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4720     },
4721
4722
4723     bounceBoth: function (t, b, c, d) {
4724         if (t < d / 2) {
4725             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4726         }
4727         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4728     }
4729 };/*
4730  * Portions of this file are based on pieces of Yahoo User Interface Library
4731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4732  * YUI licensed under the BSD License:
4733  * http://developer.yahoo.net/yui/license.txt
4734  * <script type="text/javascript">
4735  *
4736  */
4737     (function() {
4738         Roo.lib.Motion = function(el, attributes, duration, method) {
4739             if (el) {
4740                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4741             }
4742         };
4743
4744         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4745
4746
4747         var Y = Roo.lib;
4748         var superclass = Y.Motion.superclass;
4749         var proto = Y.Motion.prototype;
4750
4751         proto.toString = function() {
4752             var el = this.getEl();
4753             var id = el.id || el.tagName;
4754             return ("Motion " + id);
4755         };
4756
4757         proto.patterns.points = /^points$/i;
4758
4759         proto.setAttribute = function(attr, val, unit) {
4760             if (this.patterns.points.test(attr)) {
4761                 unit = unit || 'px';
4762                 superclass.setAttribute.call(this, 'left', val[0], unit);
4763                 superclass.setAttribute.call(this, 'top', val[1], unit);
4764             } else {
4765                 superclass.setAttribute.call(this, attr, val, unit);
4766             }
4767         };
4768
4769         proto.getAttribute = function(attr) {
4770             if (this.patterns.points.test(attr)) {
4771                 var val = [
4772                         superclass.getAttribute.call(this, 'left'),
4773                         superclass.getAttribute.call(this, 'top')
4774                         ];
4775             } else {
4776                 val = superclass.getAttribute.call(this, attr);
4777             }
4778
4779             return val;
4780         };
4781
4782         proto.doMethod = function(attr, start, end) {
4783             var val = null;
4784
4785             if (this.patterns.points.test(attr)) {
4786                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4787                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4788             } else {
4789                 val = superclass.doMethod.call(this, attr, start, end);
4790             }
4791             return val;
4792         };
4793
4794         proto.setRuntimeAttribute = function(attr) {
4795             if (this.patterns.points.test(attr)) {
4796                 var el = this.getEl();
4797                 var attributes = this.attributes;
4798                 var start;
4799                 var control = attributes['points']['control'] || [];
4800                 var end;
4801                 var i, len;
4802
4803                 if (control.length > 0 && !(control[0] instanceof Array)) {
4804                     control = [control];
4805                 } else {
4806                     var tmp = [];
4807                     for (i = 0,len = control.length; i < len; ++i) {
4808                         tmp[i] = control[i];
4809                     }
4810                     control = tmp;
4811                 }
4812
4813                 Roo.fly(el).position();
4814
4815                 if (isset(attributes['points']['from'])) {
4816                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4817                 }
4818                 else {
4819                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4820                 }
4821
4822                 start = this.getAttribute('points');
4823
4824
4825                 if (isset(attributes['points']['to'])) {
4826                     end = translateValues.call(this, attributes['points']['to'], start);
4827
4828                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4829                     for (i = 0,len = control.length; i < len; ++i) {
4830                         control[i] = translateValues.call(this, control[i], start);
4831                     }
4832
4833
4834                 } else if (isset(attributes['points']['by'])) {
4835                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4836
4837                     for (i = 0,len = control.length; i < len; ++i) {
4838                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4839                     }
4840                 }
4841
4842                 this.runtimeAttributes[attr] = [start];
4843
4844                 if (control.length > 0) {
4845                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4846                 }
4847
4848                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4849             }
4850             else {
4851                 superclass.setRuntimeAttribute.call(this, attr);
4852             }
4853         };
4854
4855         var translateValues = function(val, start) {
4856             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4857             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4858
4859             return val;
4860         };
4861
4862         var isset = function(prop) {
4863             return (typeof prop !== 'undefined');
4864         };
4865     })();
4866 /*
4867  * Portions of this file are based on pieces of Yahoo User Interface Library
4868  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4869  * YUI licensed under the BSD License:
4870  * http://developer.yahoo.net/yui/license.txt
4871  * <script type="text/javascript">
4872  *
4873  */
4874     (function() {
4875         Roo.lib.Scroll = function(el, attributes, duration, method) {
4876             if (el) {
4877                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4878             }
4879         };
4880
4881         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4882
4883
4884         var Y = Roo.lib;
4885         var superclass = Y.Scroll.superclass;
4886         var proto = Y.Scroll.prototype;
4887
4888         proto.toString = function() {
4889             var el = this.getEl();
4890             var id = el.id || el.tagName;
4891             return ("Scroll " + id);
4892         };
4893
4894         proto.doMethod = function(attr, start, end) {
4895             var val = null;
4896
4897             if (attr == 'scroll') {
4898                 val = [
4899                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4900                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4901                         ];
4902
4903             } else {
4904                 val = superclass.doMethod.call(this, attr, start, end);
4905             }
4906             return val;
4907         };
4908
4909         proto.getAttribute = function(attr) {
4910             var val = null;
4911             var el = this.getEl();
4912
4913             if (attr == 'scroll') {
4914                 val = [ el.scrollLeft, el.scrollTop ];
4915             } else {
4916                 val = superclass.getAttribute.call(this, attr);
4917             }
4918
4919             return val;
4920         };
4921
4922         proto.setAttribute = function(attr, val, unit) {
4923             var el = this.getEl();
4924
4925             if (attr == 'scroll') {
4926                 el.scrollLeft = val[0];
4927                 el.scrollTop = val[1];
4928             } else {
4929                 superclass.setAttribute.call(this, attr, val, unit);
4930             }
4931         };
4932     })();
4933 /**
4934  * Originally based of this code... - refactored for Roo...
4935  * https://github.com/aaalsaleh/undo-manager
4936  
4937  * undo-manager.js
4938  * @author  Abdulrahman Alsaleh 
4939  * @copyright 2015 Abdulrahman Alsaleh 
4940  * @license  MIT License (c) 
4941  *
4942  * Hackily modifyed by alan@roojs.com
4943  *
4944  *
4945  *  
4946  *
4947  *  TOTALLY UNTESTED...
4948  *
4949  *  Documentation to be done....
4950  */
4951  
4952
4953 /**
4954 * @class Roo.lib.UndoManager
4955 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4956 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4957
4958  * Usage:
4959  * <pre><code>
4960
4961
4962 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4963  
4964 </code></pre>
4965
4966 * For more information see this blog post with examples:
4967 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4968      - Create Elements using DOM, HTML fragments and Templates</a>. 
4969 * @constructor
4970 * @param {Number} limit how far back to go ... use 1000?
4971 * @param {Object} scope usually use document..
4972 */
4973
4974 Roo.lib.UndoManager = function (limit, undoScopeHost)
4975 {
4976     this.stack = [];
4977     this.limit = limit;
4978     this.scope = undoScopeHost;
4979     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4980     if (this.fireEvent) {
4981         this.bindEvents();
4982     }
4983     this.reset();
4984     
4985 };
4986         
4987 Roo.lib.UndoManager.prototype = {
4988     
4989     limit : false,
4990     stack : false,
4991     scope :  false,
4992     fireEvent : false,
4993     position : 0,
4994     length : 0,
4995     
4996     
4997      /**
4998      * To push and execute a transaction, the method undoManager.transact
4999      * must be called by passing a transaction object as the first argument, and a merge
5000      * flag as the second argument. A transaction object has the following properties:
5001      *
5002      * Usage:
5003 <pre><code>
5004 undoManager.transact({
5005     label: 'Typing',
5006     execute: function() { ... },
5007     undo: function() { ... },
5008     // redo same as execute
5009     redo: function() { this.execute(); }
5010 }, false);
5011
5012 // merge transaction
5013 undoManager.transact({
5014     label: 'Typing',
5015     execute: function() { ... },  // this will be run...
5016     undo: function() { ... }, // what to do when undo is run.
5017     // redo same as execute
5018     redo: function() { this.execute(); }
5019 }, true); 
5020 </code></pre> 
5021      *
5022      * 
5023      * @param {Object} transaction The transaction to add to the stack.
5024      * @return {String} The HTML fragment
5025      */
5026     
5027     
5028     transact : function (transaction, merge)
5029     {
5030         if (arguments.length < 2) {
5031             throw new TypeError('Not enough arguments to UndoManager.transact.');
5032         }
5033
5034         transaction.execute();
5035
5036         this.stack.splice(0, this.position);
5037         if (merge && this.length) {
5038             this.stack[0].push(transaction);
5039         } else {
5040             this.stack.unshift([transaction]);
5041         }
5042     
5043         this.position = 0;
5044
5045         if (this.limit && this.stack.length > this.limit) {
5046             this.length = this.stack.length = this.limit;
5047         } else {
5048             this.length = this.stack.length;
5049         }
5050
5051         if (this.fireEvent) {
5052             this.scope.dispatchEvent(
5053                 new CustomEvent('DOMTransaction', {
5054                     detail: {
5055                         transactions: this.stack[0].slice()
5056                     },
5057                     bubbles: true,
5058                     cancelable: false
5059                 })
5060             );
5061         }
5062         
5063         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5064       
5065         
5066     },
5067
5068     undo : function ()
5069     {
5070         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5071         
5072         if (this.position < this.length) {
5073             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5074                 this.stack[this.position][i].undo();
5075             }
5076             this.position++;
5077
5078             if (this.fireEvent) {
5079                 this.scope.dispatchEvent(
5080                     new CustomEvent('undo', {
5081                         detail: {
5082                             transactions: this.stack[this.position - 1].slice()
5083                         },
5084                         bubbles: true,
5085                         cancelable: false
5086                     })
5087                 );
5088             }
5089         }
5090     },
5091
5092     redo : function ()
5093     {
5094         if (this.position > 0) {
5095             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5096                 this.stack[this.position - 1][i].redo();
5097             }
5098             this.position--;
5099
5100             if (this.fireEvent) {
5101                 this.scope.dispatchEvent(
5102                     new CustomEvent('redo', {
5103                         detail: {
5104                             transactions: this.stack[this.position].slice()
5105                         },
5106                         bubbles: true,
5107                         cancelable: false
5108                     })
5109                 );
5110             }
5111         }
5112     },
5113
5114     item : function (index)
5115     {
5116         if (index >= 0 && index < this.length) {
5117             return this.stack[index].slice();
5118         }
5119         return null;
5120     },
5121
5122     clearUndo : function () {
5123         this.stack.length = this.length = this.position;
5124     },
5125
5126     clearRedo : function () {
5127         this.stack.splice(0, this.position);
5128         this.position = 0;
5129         this.length = this.stack.length;
5130     },
5131     /**
5132      * Reset the undo - probaly done on load to clear all history.
5133      */
5134     reset : function()
5135     {
5136         this.stack = [];
5137         this.position = 0;
5138         this.length = 0;
5139         this.current_html = this.scope.innerHTML;
5140         if (this.timer !== false) {
5141             clearTimeout(this.timer);
5142         }
5143         this.timer = false;
5144         this.merge = false;
5145         this.addEvent();
5146         
5147     },
5148     current_html : '',
5149     timer : false,
5150     merge : false,
5151     
5152     
5153     // this will handle the undo/redo on the element.?
5154     bindEvents : function()
5155     {
5156         var el  = this.scope;
5157         el.undoManager = this;
5158         
5159         
5160         this.scope.addEventListener('keydown', function(e) {
5161             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5162                 if (e.shiftKey) {
5163                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5164                 } else {
5165                     el.undoManager.undo(); // Ctrl/Command + Z
5166                 }
5167         
5168                 e.preventDefault();
5169             }
5170         });
5171         /// ignore keyup..
5172         this.scope.addEventListener('keyup', function(e) {
5173             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5174                 e.preventDefault();
5175             }
5176         });
5177         
5178         
5179         
5180         var t = this;
5181         
5182         el.addEventListener('input', function(e) {
5183             if(el.innerHTML == t.current_html) {
5184                 return;
5185             }
5186             // only record events every second.
5187             if (t.timer !== false) {
5188                clearTimeout(t.timer);
5189                t.timer = false;
5190             }
5191             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5192             
5193             t.addEvent(t.merge);
5194             t.merge = true; // ignore changes happening every second..
5195         });
5196         },
5197     /**
5198      * Manually add an event.
5199      * Normall called without arguements - and it will just get added to the stack.
5200      * 
5201      */
5202     
5203     addEvent : function(merge)
5204     {
5205         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5206         // not sure if this should clear the timer 
5207         merge = typeof(merge) == 'undefined' ? false : merge; 
5208         
5209         this.scope.undoManager.transact({
5210             scope : this.scope,
5211             oldHTML: this.current_html,
5212             newHTML: this.scope.innerHTML,
5213             // nothing to execute (content already changed when input is fired)
5214             execute: function() { },
5215             undo: function() {
5216                 this.scope.innerHTML = this.current_html = this.oldHTML;
5217             },
5218             redo: function() {
5219                 this.scope.innerHTML = this.current_html = this.newHTML;
5220             }
5221         }, false); //merge);
5222         
5223         this.merge = merge;
5224         
5225         this.current_html = this.scope.innerHTML;
5226     }
5227     
5228     
5229      
5230     
5231     
5232     
5233 };
5234 /**
5235  * @class Roo.lib.Range
5236  * @constructor
5237  * This is a toolkit, normally used to copy features into a Dom Range element
5238  * Roo.lib.Range.wrap(x);
5239  *
5240  *
5241  *
5242  */
5243 Roo.lib.Range = function() { };
5244
5245 /**
5246  * Wrap a Dom Range object, to give it new features...
5247  * @static
5248  * @param {Range} the range to wrap
5249  */
5250 Roo.lib.Range.wrap = function(r) {
5251     return Roo.apply(r, Roo.lib.Range.prototype);
5252 };
5253 /**
5254  * find a parent node eg. LI / OL
5255  * @param {string|Array} node name or array of nodenames
5256  * @return {DomElement|false}
5257  */
5258 Roo.apply(Roo.lib.Range.prototype,
5259 {
5260     
5261     closest : function(str)
5262     {
5263         if (typeof(str) != 'string') {
5264             // assume it's a array.
5265             for(var i = 0;i < str.length;i++) {
5266                 var r = this.closest(str[i]);
5267                 if (r !== false) {
5268                     return r;
5269                 }
5270                 
5271             }
5272             return false;
5273         }
5274         str = str.toLowerCase();
5275         var n = this.commonAncestorContainer; // might not be a node
5276         while (n.nodeType != 1) {
5277             n = n.parentNode;
5278         }
5279         
5280         if (n.nodeName.toLowerCase() == str ) {
5281             return n;
5282         }
5283         if (n.nodeName.toLowerCase() == 'body') {
5284             return false;
5285         }
5286             
5287         return n.closest(str) || false;
5288         
5289     },
5290     cloneRange : function()
5291     {
5292         return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5293     }
5294 });/**
5295  * @class Roo.lib.Selection
5296  * @constructor
5297  * This is a toolkit, normally used to copy features into a Dom Selection element
5298  * Roo.lib.Selection.wrap(x);
5299  *
5300  *
5301  *
5302  */
5303 Roo.lib.Selection = function() { };
5304
5305 /**
5306  * Wrap a Dom Range object, to give it new features...
5307  * @static
5308  * @param {Range} the range to wrap
5309  */
5310 Roo.lib.Selection.wrap = function(r, doc) {
5311     Roo.apply(r, Roo.lib.Selection.prototype);
5312     r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5313     return r;
5314 };
5315 /**
5316  * find a parent node eg. LI / OL
5317  * @param {string|Array} node name or array of nodenames
5318  * @return {DomElement|false}
5319  */
5320 Roo.apply(Roo.lib.Selection.prototype,
5321 {
5322     /**
5323      * the owner document
5324      */
5325     ownerDocument : false,
5326     
5327     getRangeAt : function(n)
5328     {
5329         return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5330     },
5331     
5332     /**
5333      * insert node at selection 
5334      * @param {DomElement|string} node
5335      * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5336      */
5337     insertNode: function(node, cursor)
5338     {
5339         if (typeof(node) == 'string') {
5340             node = this.ownerDocument.createElement(node);
5341             if (cursor == 'in') {
5342                 node.innerHTML = '&nbsp;';
5343             }
5344         }
5345         
5346         var range = this.getRangeAt(0);
5347         
5348         if (this.type != 'Caret') {
5349             range.deleteContents();
5350         }
5351         var sn = node.childNodes[0]; // select the contents.
5352
5353         
5354         
5355         range.insertNode(node);
5356         if (cursor == 'after') {
5357             node.insertAdjacentHTML('afterend', '&nbsp;');
5358             sn = node.nextSibling;
5359         }
5360         
5361         if (cursor == 'none') {
5362             return;
5363         }
5364         
5365         this.cursorText(sn);
5366     },
5367     
5368     cursorText : function(n)
5369     {
5370        
5371         //var range = this.getRangeAt(0);
5372         range = Roo.lib.Range.wrap(new Range());
5373         //range.selectNode(n);
5374         
5375         var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5376         range.setStart(n.parentNode,ix);
5377         range.setEnd(n.parentNode,ix+1);
5378         //range.collapse(false);
5379          
5380         this.removeAllRanges();
5381         this.addRange(range);
5382         
5383         Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5384     },
5385     cursorAfter : function(n)
5386     {
5387         if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
5388             n.insertAdjacentHTML('afterend', '&nbsp;');
5389         }
5390         this.cursorText (n.nextSibling);
5391     }
5392         
5393     
5394 });/*
5395  * Based on:
5396  * Ext JS Library 1.1.1
5397  * Copyright(c) 2006-2007, Ext JS, LLC.
5398  *
5399  * Originally Released Under LGPL - original licence link has changed is not relivant.
5400  *
5401  * Fork - LGPL
5402  * <script type="text/javascript">
5403  */
5404
5405
5406 // nasty IE9 hack - what a pile of crap that is..
5407
5408  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5409     Range.prototype.createContextualFragment = function (html) {
5410         var doc = window.document;
5411         var container = doc.createElement("div");
5412         container.innerHTML = html;
5413         var frag = doc.createDocumentFragment(), n;
5414         while ((n = container.firstChild)) {
5415             frag.appendChild(n);
5416         }
5417         return frag;
5418     };
5419 }
5420
5421 /**
5422  * @class Roo.DomHelper
5423  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5424  * 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>.
5425  * @static
5426  */
5427 Roo.DomHelper = function(){
5428     var tempTableEl = null;
5429     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5430     var tableRe = /^table|tbody|tr|td$/i;
5431     var xmlns = {};
5432     // build as innerHTML where available
5433     /** @ignore */
5434     var createHtml = function(o){
5435         if(typeof o == 'string'){
5436             return o;
5437         }
5438         var b = "";
5439         if(!o.tag){
5440             o.tag = "div";
5441         }
5442         b += "<" + o.tag;
5443         for(var attr in o){
5444             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5445             if(attr == "style"){
5446                 var s = o["style"];
5447                 if(typeof s == "function"){
5448                     s = s.call();
5449                 }
5450                 if(typeof s == "string"){
5451                     b += ' style="' + s + '"';
5452                 }else if(typeof s == "object"){
5453                     b += ' style="';
5454                     for(var key in s){
5455                         if(typeof s[key] != "function"){
5456                             b += key + ":" + s[key] + ";";
5457                         }
5458                     }
5459                     b += '"';
5460                 }
5461             }else{
5462                 if(attr == "cls"){
5463                     b += ' class="' + o["cls"] + '"';
5464                 }else if(attr == "htmlFor"){
5465                     b += ' for="' + o["htmlFor"] + '"';
5466                 }else{
5467                     b += " " + attr + '="' + o[attr] + '"';
5468                 }
5469             }
5470         }
5471         if(emptyTags.test(o.tag)){
5472             b += "/>";
5473         }else{
5474             b += ">";
5475             var cn = o.children || o.cn;
5476             if(cn){
5477                 //http://bugs.kde.org/show_bug.cgi?id=71506
5478                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5479                     for(var i = 0, len = cn.length; i < len; i++) {
5480                         b += createHtml(cn[i], b);
5481                     }
5482                 }else{
5483                     b += createHtml(cn, b);
5484                 }
5485             }
5486             if(o.html){
5487                 b += o.html;
5488             }
5489             b += "</" + o.tag + ">";
5490         }
5491         return b;
5492     };
5493
5494     // build as dom
5495     /** @ignore */
5496     var createDom = function(o, parentNode){
5497          
5498         // defininition craeted..
5499         var ns = false;
5500         if (o.ns && o.ns != 'html') {
5501                
5502             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5503                 xmlns[o.ns] = o.xmlns;
5504                 ns = o.xmlns;
5505             }
5506             if (typeof(xmlns[o.ns]) == 'undefined') {
5507                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5508             }
5509             ns = xmlns[o.ns];
5510         }
5511         
5512         
5513         if (typeof(o) == 'string') {
5514             return parentNode.appendChild(document.createTextNode(o));
5515         }
5516         o.tag = o.tag || div;
5517         if (o.ns && Roo.isIE) {
5518             ns = false;
5519             o.tag = o.ns + ':' + o.tag;
5520             
5521         }
5522         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5523         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5524         for(var attr in o){
5525             
5526             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5527                     attr == "style" || typeof o[attr] == "function") { continue; }
5528                     
5529             if(attr=="cls" && Roo.isIE){
5530                 el.className = o["cls"];
5531             }else{
5532                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5533                 else { 
5534                     el[attr] = o[attr];
5535                 }
5536             }
5537         }
5538         Roo.DomHelper.applyStyles(el, o.style);
5539         var cn = o.children || o.cn;
5540         if(cn){
5541             //http://bugs.kde.org/show_bug.cgi?id=71506
5542              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5543                 for(var i = 0, len = cn.length; i < len; i++) {
5544                     createDom(cn[i], el);
5545                 }
5546             }else{
5547                 createDom(cn, el);
5548             }
5549         }
5550         if(o.html){
5551             el.innerHTML = o.html;
5552         }
5553         if(parentNode){
5554            parentNode.appendChild(el);
5555         }
5556         return el;
5557     };
5558
5559     var ieTable = function(depth, s, h, e){
5560         tempTableEl.innerHTML = [s, h, e].join('');
5561         var i = -1, el = tempTableEl;
5562         while(++i < depth && el.firstChild){
5563             el = el.firstChild;
5564         }
5565         return el;
5566     };
5567
5568     // kill repeat to save bytes
5569     var ts = '<table>',
5570         te = '</table>',
5571         tbs = ts+'<tbody>',
5572         tbe = '</tbody>'+te,
5573         trs = tbs + '<tr>',
5574         tre = '</tr>'+tbe;
5575
5576     /**
5577      * @ignore
5578      * Nasty code for IE's broken table implementation
5579      */
5580     var insertIntoTable = function(tag, where, el, html){
5581         if(!tempTableEl){
5582             tempTableEl = document.createElement('div');
5583         }
5584         var node;
5585         var before = null;
5586         if(tag == 'td'){
5587             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5588                 return;
5589             }
5590             if(where == 'beforebegin'){
5591                 before = el;
5592                 el = el.parentNode;
5593             } else{
5594                 before = el.nextSibling;
5595                 el = el.parentNode;
5596             }
5597             node = ieTable(4, trs, html, tre);
5598         }
5599         else if(tag == 'tr'){
5600             if(where == 'beforebegin'){
5601                 before = el;
5602                 el = el.parentNode;
5603                 node = ieTable(3, tbs, html, tbe);
5604             } else if(where == 'afterend'){
5605                 before = el.nextSibling;
5606                 el = el.parentNode;
5607                 node = ieTable(3, tbs, html, tbe);
5608             } else{ // INTO a TR
5609                 if(where == 'afterbegin'){
5610                     before = el.firstChild;
5611                 }
5612                 node = ieTable(4, trs, html, tre);
5613             }
5614         } else if(tag == 'tbody'){
5615             if(where == 'beforebegin'){
5616                 before = el;
5617                 el = el.parentNode;
5618                 node = ieTable(2, ts, html, te);
5619             } else if(where == 'afterend'){
5620                 before = el.nextSibling;
5621                 el = el.parentNode;
5622                 node = ieTable(2, ts, html, te);
5623             } else{
5624                 if(where == 'afterbegin'){
5625                     before = el.firstChild;
5626                 }
5627                 node = ieTable(3, tbs, html, tbe);
5628             }
5629         } else{ // TABLE
5630             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5631                 return;
5632             }
5633             if(where == 'afterbegin'){
5634                 before = el.firstChild;
5635             }
5636             node = ieTable(2, ts, html, te);
5637         }
5638         el.insertBefore(node, before);
5639         return node;
5640     };
5641     
5642     // this is a bit like the react update code...
5643     // 
5644     
5645     var updateNode = function(from, to)
5646     {
5647         // should we handle non-standard elements?
5648         Roo.log(["UpdateNode" , from, to]);
5649         if (from.nodeType != to.nodeType) {
5650             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5651             from.parentNode.replaceChild(to, from);
5652         }
5653         
5654         if (from.nodeType == 3) {
5655             // assume it's text?!
5656             if (from.data == to.data) {
5657                 return;
5658             }
5659             from.data = to.data;
5660             return;
5661         }
5662         if (!from.parentNode) {
5663             // not sure why this is happening?
5664             return;
5665         }
5666         // assume 'to' doesnt have '1/3 nodetypes!
5667         // not sure why, by from, parent node might not exist?
5668         if (from.nodeType !=1 || from.tagName != to.tagName) {
5669             Roo.log(["ReplaceChild" , from, to ]);
5670             
5671             from.parentNode.replaceChild(to, from);
5672             return;
5673         }
5674         // compare attributes
5675         var ar = Array.from(from.attributes);
5676         for(var i = 0; i< ar.length;i++) {
5677             if (to.hasAttribute(ar[i].name)) {
5678                 continue;
5679             }
5680             if (ar[i].name == 'id') { // always keep ids?
5681                continue;
5682             }
5683             //if (ar[i].name == 'style') {
5684             //   throw "style removed?";
5685             //}
5686             Roo.log("removeAttribute" + ar[i].name);
5687             from.removeAttribute(ar[i].name);
5688         }
5689         ar = to.attributes;
5690         for(var i = 0; i< ar.length;i++) {
5691             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5692                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5693                 continue;
5694             }
5695             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5696             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5697         }
5698         // children
5699         var far = Array.from(from.childNodes);
5700         var tar = Array.from(to.childNodes);
5701         // if the lengths are different.. then it's probably a editable content change, rather than
5702         // a change of the block definition..
5703         
5704         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5705          /*if (from.innerHTML == to.innerHTML) {
5706             return;
5707         }
5708         if (far.length != tar.length) {
5709             from.innerHTML = to.innerHTML;
5710             return;
5711         }
5712         */
5713         
5714         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5715             if (i >= far.length) {
5716                 from.appendChild(tar[i]);
5717                 Roo.log(["add", tar[i]]);
5718                 
5719             } else if ( i  >= tar.length) {
5720                 from.removeChild(far[i]);
5721                 Roo.log(["remove", far[i]]);
5722             } else {
5723                 
5724                 updateNode(far[i], tar[i]);
5725             }    
5726         }
5727         
5728         
5729         
5730         
5731     };
5732     
5733     
5734
5735     return {
5736         /** True to force the use of DOM instead of html fragments @type Boolean */
5737         useDom : false,
5738     
5739         /**
5740          * Returns the markup for the passed Element(s) config
5741          * @param {Object} o The Dom object spec (and children)
5742          * @return {String}
5743          */
5744         markup : function(o){
5745             return createHtml(o);
5746         },
5747     
5748         /**
5749          * Applies a style specification to an element
5750          * @param {String/HTMLElement} el The element to apply styles to
5751          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5752          * a function which returns such a specification.
5753          */
5754         applyStyles : function(el, styles){
5755             if(styles){
5756                el = Roo.fly(el);
5757                if(typeof styles == "string"){
5758                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5759                    var matches;
5760                    while ((matches = re.exec(styles)) != null){
5761                        el.setStyle(matches[1], matches[2]);
5762                    }
5763                }else if (typeof styles == "object"){
5764                    for (var style in styles){
5765                       el.setStyle(style, styles[style]);
5766                    }
5767                }else if (typeof styles == "function"){
5768                     Roo.DomHelper.applyStyles(el, styles.call());
5769                }
5770             }
5771         },
5772     
5773         /**
5774          * Inserts an HTML fragment into the Dom
5775          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5776          * @param {HTMLElement} el The context element
5777          * @param {String} html The HTML fragmenet
5778          * @return {HTMLElement} The new node
5779          */
5780         insertHtml : function(where, el, html){
5781             where = where.toLowerCase();
5782             if(el.insertAdjacentHTML){
5783                 if(tableRe.test(el.tagName)){
5784                     var rs;
5785                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5786                         return rs;
5787                     }
5788                 }
5789                 switch(where){
5790                     case "beforebegin":
5791                         el.insertAdjacentHTML('BeforeBegin', html);
5792                         return el.previousSibling;
5793                     case "afterbegin":
5794                         el.insertAdjacentHTML('AfterBegin', html);
5795                         return el.firstChild;
5796                     case "beforeend":
5797                         el.insertAdjacentHTML('BeforeEnd', html);
5798                         return el.lastChild;
5799                     case "afterend":
5800                         el.insertAdjacentHTML('AfterEnd', html);
5801                         return el.nextSibling;
5802                 }
5803                 throw 'Illegal insertion point -> "' + where + '"';
5804             }
5805             var range = el.ownerDocument.createRange();
5806             var frag;
5807             switch(where){
5808                  case "beforebegin":
5809                     range.setStartBefore(el);
5810                     frag = range.createContextualFragment(html);
5811                     el.parentNode.insertBefore(frag, el);
5812                     return el.previousSibling;
5813                  case "afterbegin":
5814                     if(el.firstChild){
5815                         range.setStartBefore(el.firstChild);
5816                         frag = range.createContextualFragment(html);
5817                         el.insertBefore(frag, el.firstChild);
5818                         return el.firstChild;
5819                     }else{
5820                         el.innerHTML = html;
5821                         return el.firstChild;
5822                     }
5823                 case "beforeend":
5824                     if(el.lastChild){
5825                         range.setStartAfter(el.lastChild);
5826                         frag = range.createContextualFragment(html);
5827                         el.appendChild(frag);
5828                         return el.lastChild;
5829                     }else{
5830                         el.innerHTML = html;
5831                         return el.lastChild;
5832                     }
5833                 case "afterend":
5834                     range.setStartAfter(el);
5835                     frag = range.createContextualFragment(html);
5836                     el.parentNode.insertBefore(frag, el.nextSibling);
5837                     return el.nextSibling;
5838                 }
5839                 throw 'Illegal insertion point -> "' + where + '"';
5840         },
5841     
5842         /**
5843          * Creates new Dom element(s) and inserts them before el
5844          * @param {String/HTMLElement/Element} el The context element
5845          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5846          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5847          * @return {HTMLElement/Roo.Element} The new node
5848          */
5849         insertBefore : function(el, o, returnElement){
5850             return this.doInsert(el, o, returnElement, "beforeBegin");
5851         },
5852     
5853         /**
5854          * Creates new Dom element(s) and inserts them after el
5855          * @param {String/HTMLElement/Element} el The context element
5856          * @param {Object} o The Dom object spec (and children)
5857          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5858          * @return {HTMLElement/Roo.Element} The new node
5859          */
5860         insertAfter : function(el, o, returnElement){
5861             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5862         },
5863     
5864         /**
5865          * Creates new Dom element(s) and inserts them as the first child of el
5866          * @param {String/HTMLElement/Element} el The context element
5867          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5868          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5869          * @return {HTMLElement/Roo.Element} The new node
5870          */
5871         insertFirst : function(el, o, returnElement){
5872             return this.doInsert(el, o, returnElement, "afterBegin");
5873         },
5874     
5875         // private
5876         doInsert : function(el, o, returnElement, pos, sibling){
5877             el = Roo.getDom(el);
5878             var newNode;
5879             if(this.useDom || o.ns){
5880                 newNode = createDom(o, null);
5881                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5882             }else{
5883                 var html = createHtml(o);
5884                 newNode = this.insertHtml(pos, el, html);
5885             }
5886             return returnElement ? Roo.get(newNode, true) : newNode;
5887         },
5888     
5889         /**
5890          * Creates new Dom element(s) and appends them to el
5891          * @param {String/HTMLElement/Element} el The context element
5892          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5893          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5894          * @return {HTMLElement/Roo.Element} The new node
5895          */
5896         append : function(el, o, returnElement){
5897             el = Roo.getDom(el);
5898             var newNode;
5899             if(this.useDom || o.ns){
5900                 newNode = createDom(o, null);
5901                 el.appendChild(newNode);
5902             }else{
5903                 var html = createHtml(o);
5904                 newNode = this.insertHtml("beforeEnd", el, html);
5905             }
5906             return returnElement ? Roo.get(newNode, true) : newNode;
5907         },
5908     
5909         /**
5910          * Creates new Dom element(s) and overwrites the contents of el with them
5911          * @param {String/HTMLElement/Element} el The context element
5912          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5913          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5914          * @return {HTMLElement/Roo.Element} The new node
5915          */
5916         overwrite : function(el, o, returnElement)
5917         {
5918             el = Roo.getDom(el);
5919             if (o.ns) {
5920               
5921                 while (el.childNodes.length) {
5922                     el.removeChild(el.firstChild);
5923                 }
5924                 createDom(o, el);
5925             } else {
5926                 el.innerHTML = createHtml(o);   
5927             }
5928             
5929             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5930         },
5931     
5932         /**
5933          * Creates a new Roo.DomHelper.Template from the Dom object spec
5934          * @param {Object} o The Dom object spec (and children)
5935          * @return {Roo.DomHelper.Template} The new template
5936          */
5937         createTemplate : function(o){
5938             var html = createHtml(o);
5939             return new Roo.Template(html);
5940         },
5941          /**
5942          * Updates the first element with the spec from the o (replacing if necessary)
5943          * This iterates through the children, and updates attributes / children etc..
5944          * @param {String/HTMLElement/Element} el The context element
5945          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5946          */
5947         
5948         update : function(el, o)
5949         {
5950             updateNode(Roo.getDom(el), createDom(o));
5951             
5952         }
5953         
5954         
5955     };
5956 }();
5957 /*
5958  * Based on:
5959  * Ext JS Library 1.1.1
5960  * Copyright(c) 2006-2007, Ext JS, LLC.
5961  *
5962  * Originally Released Under LGPL - original licence link has changed is not relivant.
5963  *
5964  * Fork - LGPL
5965  * <script type="text/javascript">
5966  */
5967  
5968 /**
5969 * @class Roo.Template
5970 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5971 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5972 * Usage:
5973 <pre><code>
5974 var t = new Roo.Template({
5975     html :  '&lt;div name="{id}"&gt;' + 
5976         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5977         '&lt;/div&gt;',
5978     myformat: function (value, allValues) {
5979         return 'XX' + value;
5980     }
5981 });
5982 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5983 </code></pre>
5984 * For more information see this blog post with examples:
5985 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5986      - Create Elements using DOM, HTML fragments and Templates</a>. 
5987 * @constructor
5988 * @param {Object} cfg - Configuration object.
5989 */
5990 Roo.Template = function(cfg){
5991     // BC!
5992     if(cfg instanceof Array){
5993         cfg = cfg.join("");
5994     }else if(arguments.length > 1){
5995         cfg = Array.prototype.join.call(arguments, "");
5996     }
5997     
5998     
5999     if (typeof(cfg) == 'object') {
6000         Roo.apply(this,cfg)
6001     } else {
6002         // bc
6003         this.html = cfg;
6004     }
6005     if (this.url) {
6006         this.load();
6007     }
6008     
6009 };
6010 Roo.Template.prototype = {
6011     
6012     /**
6013      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6014      */
6015     onLoad : false,
6016     
6017     
6018     /**
6019      * @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..
6020      *                    it should be fixed so that template is observable...
6021      */
6022     url : false,
6023     /**
6024      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6025      */
6026     html : '',
6027     
6028     
6029     compiled : false,
6030     loaded : false,
6031     /**
6032      * Returns an HTML fragment of this template with the specified values applied.
6033      * @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'})
6034      * @return {String} The HTML fragment
6035      */
6036     
6037    
6038     
6039     applyTemplate : function(values){
6040         //Roo.log(["applyTemplate", values]);
6041         try {
6042            
6043             if(this.compiled){
6044                 return this.compiled(values);
6045             }
6046             var useF = this.disableFormats !== true;
6047             var fm = Roo.util.Format, tpl = this;
6048             var fn = function(m, name, format, args){
6049                 if(format && useF){
6050                     if(format.substr(0, 5) == "this."){
6051                         return tpl.call(format.substr(5), values[name], values);
6052                     }else{
6053                         if(args){
6054                             // quoted values are required for strings in compiled templates, 
6055                             // but for non compiled we need to strip them
6056                             // quoted reversed for jsmin
6057                             var re = /^\s*['"](.*)["']\s*$/;
6058                             args = args.split(',');
6059                             for(var i = 0, len = args.length; i < len; i++){
6060                                 args[i] = args[i].replace(re, "$1");
6061                             }
6062                             args = [values[name]].concat(args);
6063                         }else{
6064                             args = [values[name]];
6065                         }
6066                         return fm[format].apply(fm, args);
6067                     }
6068                 }else{
6069                     return values[name] !== undefined ? values[name] : "";
6070                 }
6071             };
6072             return this.html.replace(this.re, fn);
6073         } catch (e) {
6074             Roo.log(e);
6075             throw e;
6076         }
6077          
6078     },
6079     
6080     loading : false,
6081       
6082     load : function ()
6083     {
6084          
6085         if (this.loading) {
6086             return;
6087         }
6088         var _t = this;
6089         
6090         this.loading = true;
6091         this.compiled = false;
6092         
6093         var cx = new Roo.data.Connection();
6094         cx.request({
6095             url : this.url,
6096             method : 'GET',
6097             success : function (response) {
6098                 _t.loading = false;
6099                 _t.url = false;
6100                 
6101                 _t.set(response.responseText,true);
6102                 _t.loaded = true;
6103                 if (_t.onLoad) {
6104                     _t.onLoad();
6105                 }
6106              },
6107             failure : function(response) {
6108                 Roo.log("Template failed to load from " + _t.url);
6109                 _t.loading = false;
6110             }
6111         });
6112     },
6113
6114     /**
6115      * Sets the HTML used as the template and optionally compiles it.
6116      * @param {String} html
6117      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6118      * @return {Roo.Template} this
6119      */
6120     set : function(html, compile){
6121         this.html = html;
6122         this.compiled = false;
6123         if(compile){
6124             this.compile();
6125         }
6126         return this;
6127     },
6128     
6129     /**
6130      * True to disable format functions (defaults to false)
6131      * @type Boolean
6132      */
6133     disableFormats : false,
6134     
6135     /**
6136     * The regular expression used to match template variables 
6137     * @type RegExp
6138     * @property 
6139     */
6140     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6141     
6142     /**
6143      * Compiles the template into an internal function, eliminating the RegEx overhead.
6144      * @return {Roo.Template} this
6145      */
6146     compile : function(){
6147         var fm = Roo.util.Format;
6148         var useF = this.disableFormats !== true;
6149         var sep = Roo.isGecko ? "+" : ",";
6150         var fn = function(m, name, format, args){
6151             if(format && useF){
6152                 args = args ? ',' + args : "";
6153                 if(format.substr(0, 5) != "this."){
6154                     format = "fm." + format + '(';
6155                 }else{
6156                     format = 'this.call("'+ format.substr(5) + '", ';
6157                     args = ", values";
6158                 }
6159             }else{
6160                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6161             }
6162             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6163         };
6164         var body;
6165         // branched to use + in gecko and [].join() in others
6166         if(Roo.isGecko){
6167             body = "this.compiled = function(values){ return '" +
6168                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6169                     "';};";
6170         }else{
6171             body = ["this.compiled = function(values){ return ['"];
6172             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6173             body.push("'].join('');};");
6174             body = body.join('');
6175         }
6176         /**
6177          * eval:var:values
6178          * eval:var:fm
6179          */
6180         eval(body);
6181         return this;
6182     },
6183     
6184     // private function used to call members
6185     call : function(fnName, value, allValues){
6186         return this[fnName](value, allValues);
6187     },
6188     
6189     /**
6190      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6191      * @param {String/HTMLElement/Roo.Element} el The context element
6192      * @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'})
6193      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6194      * @return {HTMLElement/Roo.Element} The new node or Element
6195      */
6196     insertFirst: function(el, values, returnElement){
6197         return this.doInsert('afterBegin', el, values, returnElement);
6198     },
6199
6200     /**
6201      * Applies the supplied values to the template and inserts the new node(s) before el.
6202      * @param {String/HTMLElement/Roo.Element} el The context element
6203      * @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'})
6204      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6205      * @return {HTMLElement/Roo.Element} The new node or Element
6206      */
6207     insertBefore: function(el, values, returnElement){
6208         return this.doInsert('beforeBegin', el, values, returnElement);
6209     },
6210
6211     /**
6212      * Applies the supplied values to the template and inserts the new node(s) after el.
6213      * @param {String/HTMLElement/Roo.Element} el The context element
6214      * @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'})
6215      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6216      * @return {HTMLElement/Roo.Element} The new node or Element
6217      */
6218     insertAfter : function(el, values, returnElement){
6219         return this.doInsert('afterEnd', el, values, returnElement);
6220     },
6221     
6222     /**
6223      * Applies the supplied values to the template and appends the new node(s) to el.
6224      * @param {String/HTMLElement/Roo.Element} el The context element
6225      * @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'})
6226      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6227      * @return {HTMLElement/Roo.Element} The new node or Element
6228      */
6229     append : function(el, values, returnElement){
6230         return this.doInsert('beforeEnd', el, values, returnElement);
6231     },
6232
6233     doInsert : function(where, el, values, returnEl){
6234         el = Roo.getDom(el);
6235         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6236         return returnEl ? Roo.get(newNode, true) : newNode;
6237     },
6238
6239     /**
6240      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6241      * @param {String/HTMLElement/Roo.Element} el The context element
6242      * @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'})
6243      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6244      * @return {HTMLElement/Roo.Element} The new node or Element
6245      */
6246     overwrite : function(el, values, returnElement){
6247         el = Roo.getDom(el);
6248         el.innerHTML = this.applyTemplate(values);
6249         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6250     }
6251 };
6252 /**
6253  * Alias for {@link #applyTemplate}
6254  * @method
6255  */
6256 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6257
6258 // backwards compat
6259 Roo.DomHelper.Template = Roo.Template;
6260
6261 /**
6262  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6263  * @param {String/HTMLElement} el A DOM element or its id
6264  * @returns {Roo.Template} The created template
6265  * @static
6266  */
6267 Roo.Template.from = function(el){
6268     el = Roo.getDom(el);
6269     return new Roo.Template(el.value || el.innerHTML);
6270 };/*
6271  * Based on:
6272  * Ext JS Library 1.1.1
6273  * Copyright(c) 2006-2007, Ext JS, LLC.
6274  *
6275  * Originally Released Under LGPL - original licence link has changed is not relivant.
6276  *
6277  * Fork - LGPL
6278  * <script type="text/javascript">
6279  */
6280  
6281
6282 /*
6283  * This is code is also distributed under MIT license for use
6284  * with jQuery and prototype JavaScript libraries.
6285  */
6286 /**
6287  * @class Roo.DomQuery
6288 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).
6289 <p>
6290 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>
6291
6292 <p>
6293 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.
6294 </p>
6295 <h4>Element Selectors:</h4>
6296 <ul class="list">
6297     <li> <b>*</b> any element</li>
6298     <li> <b>E</b> an element with the tag E</li>
6299     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6300     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6301     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6302     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6303 </ul>
6304 <h4>Attribute Selectors:</h4>
6305 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6306 <ul class="list">
6307     <li> <b>E[foo]</b> has an attribute "foo"</li>
6308     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6309     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6310     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6311     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6312     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6313     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6314 </ul>
6315 <h4>Pseudo Classes:</h4>
6316 <ul class="list">
6317     <li> <b>E:first-child</b> E is the first child of its parent</li>
6318     <li> <b>E:last-child</b> E is the last child of its parent</li>
6319     <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>
6320     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6321     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6322     <li> <b>E:only-child</b> E is the only child of its parent</li>
6323     <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>
6324     <li> <b>E:first</b> the first E in the resultset</li>
6325     <li> <b>E:last</b> the last E in the resultset</li>
6326     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6327     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6328     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6329     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6330     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6331     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6332     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6333     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6334     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6335 </ul>
6336 <h4>CSS Value Selectors:</h4>
6337 <ul class="list">
6338     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6339     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6340     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6341     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6342     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6343     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6344 </ul>
6345  * @static
6346  */
6347 Roo.DomQuery = function(){
6348     var cache = {}, simpleCache = {}, valueCache = {};
6349     var nonSpace = /\S/;
6350     var trimRe = /^\s+|\s+$/g;
6351     var tplRe = /\{(\d+)\}/g;
6352     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6353     var tagTokenRe = /^(#)?([\w-\*]+)/;
6354     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6355
6356     function child(p, index){
6357         var i = 0;
6358         var n = p.firstChild;
6359         while(n){
6360             if(n.nodeType == 1){
6361                if(++i == index){
6362                    return n;
6363                }
6364             }
6365             n = n.nextSibling;
6366         }
6367         return null;
6368     };
6369
6370     function next(n){
6371         while((n = n.nextSibling) && n.nodeType != 1);
6372         return n;
6373     };
6374
6375     function prev(n){
6376         while((n = n.previousSibling) && n.nodeType != 1);
6377         return n;
6378     };
6379
6380     function children(d){
6381         var n = d.firstChild, ni = -1;
6382             while(n){
6383                 var nx = n.nextSibling;
6384                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6385                     d.removeChild(n);
6386                 }else{
6387                     n.nodeIndex = ++ni;
6388                 }
6389                 n = nx;
6390             }
6391             return this;
6392         };
6393
6394     function byClassName(c, a, v){
6395         if(!v){
6396             return c;
6397         }
6398         var r = [], ri = -1, cn;
6399         for(var i = 0, ci; ci = c[i]; i++){
6400             
6401             
6402             if((' '+
6403                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6404                  +' ').indexOf(v) != -1){
6405                 r[++ri] = ci;
6406             }
6407         }
6408         return r;
6409     };
6410
6411     function attrValue(n, attr){
6412         if(!n.tagName && typeof n.length != "undefined"){
6413             n = n[0];
6414         }
6415         if(!n){
6416             return null;
6417         }
6418         if(attr == "for"){
6419             return n.htmlFor;
6420         }
6421         if(attr == "class" || attr == "className"){
6422             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6423         }
6424         return n.getAttribute(attr) || n[attr];
6425
6426     };
6427
6428     function getNodes(ns, mode, tagName){
6429         var result = [], ri = -1, cs;
6430         if(!ns){
6431             return result;
6432         }
6433         tagName = tagName || "*";
6434         if(typeof ns.getElementsByTagName != "undefined"){
6435             ns = [ns];
6436         }
6437         if(!mode){
6438             for(var i = 0, ni; ni = ns[i]; i++){
6439                 cs = ni.getElementsByTagName(tagName);
6440                 for(var j = 0, ci; ci = cs[j]; j++){
6441                     result[++ri] = ci;
6442                 }
6443             }
6444         }else if(mode == "/" || mode == ">"){
6445             var utag = tagName.toUpperCase();
6446             for(var i = 0, ni, cn; ni = ns[i]; i++){
6447                 cn = ni.children || ni.childNodes;
6448                 for(var j = 0, cj; cj = cn[j]; j++){
6449                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6450                         result[++ri] = cj;
6451                     }
6452                 }
6453             }
6454         }else if(mode == "+"){
6455             var utag = tagName.toUpperCase();
6456             for(var i = 0, n; n = ns[i]; i++){
6457                 while((n = n.nextSibling) && n.nodeType != 1);
6458                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6459                     result[++ri] = n;
6460                 }
6461             }
6462         }else if(mode == "~"){
6463             for(var i = 0, n; n = ns[i]; i++){
6464                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6465                 if(n){
6466                     result[++ri] = n;
6467                 }
6468             }
6469         }
6470         return result;
6471     };
6472
6473     function concat(a, b){
6474         if(b.slice){
6475             return a.concat(b);
6476         }
6477         for(var i = 0, l = b.length; i < l; i++){
6478             a[a.length] = b[i];
6479         }
6480         return a;
6481     }
6482
6483     function byTag(cs, tagName){
6484         if(cs.tagName || cs == document){
6485             cs = [cs];
6486         }
6487         if(!tagName){
6488             return cs;
6489         }
6490         var r = [], ri = -1;
6491         tagName = tagName.toLowerCase();
6492         for(var i = 0, ci; ci = cs[i]; i++){
6493             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6494                 r[++ri] = ci;
6495             }
6496         }
6497         return r;
6498     };
6499
6500     function byId(cs, attr, id){
6501         if(cs.tagName || cs == document){
6502             cs = [cs];
6503         }
6504         if(!id){
6505             return cs;
6506         }
6507         var r = [], ri = -1;
6508         for(var i = 0,ci; ci = cs[i]; i++){
6509             if(ci && ci.id == id){
6510                 r[++ri] = ci;
6511                 return r;
6512             }
6513         }
6514         return r;
6515     };
6516
6517     function byAttribute(cs, attr, value, op, custom){
6518         var r = [], ri = -1, st = custom=="{";
6519         var f = Roo.DomQuery.operators[op];
6520         for(var i = 0, ci; ci = cs[i]; i++){
6521             var a;
6522             if(st){
6523                 a = Roo.DomQuery.getStyle(ci, attr);
6524             }
6525             else if(attr == "class" || attr == "className"){
6526                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6527             }else if(attr == "for"){
6528                 a = ci.htmlFor;
6529             }else if(attr == "href"){
6530                 a = ci.getAttribute("href", 2);
6531             }else{
6532                 a = ci.getAttribute(attr);
6533             }
6534             if((f && f(a, value)) || (!f && a)){
6535                 r[++ri] = ci;
6536             }
6537         }
6538         return r;
6539     };
6540
6541     function byPseudo(cs, name, value){
6542         return Roo.DomQuery.pseudos[name](cs, value);
6543     };
6544
6545     // This is for IE MSXML which does not support expandos.
6546     // IE runs the same speed using setAttribute, however FF slows way down
6547     // and Safari completely fails so they need to continue to use expandos.
6548     var isIE = window.ActiveXObject ? true : false;
6549
6550     // this eval is stop the compressor from
6551     // renaming the variable to something shorter
6552     
6553     /** eval:var:batch */
6554     var batch = 30803; 
6555
6556     var key = 30803;
6557
6558     function nodupIEXml(cs){
6559         var d = ++key;
6560         cs[0].setAttribute("_nodup", d);
6561         var r = [cs[0]];
6562         for(var i = 1, len = cs.length; i < len; i++){
6563             var c = cs[i];
6564             if(!c.getAttribute("_nodup") != d){
6565                 c.setAttribute("_nodup", d);
6566                 r[r.length] = c;
6567             }
6568         }
6569         for(var i = 0, len = cs.length; i < len; i++){
6570             cs[i].removeAttribute("_nodup");
6571         }
6572         return r;
6573     }
6574
6575     function nodup(cs){
6576         if(!cs){
6577             return [];
6578         }
6579         var len = cs.length, c, i, r = cs, cj, ri = -1;
6580         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6581             return cs;
6582         }
6583         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6584             return nodupIEXml(cs);
6585         }
6586         var d = ++key;
6587         cs[0]._nodup = d;
6588         for(i = 1; c = cs[i]; i++){
6589             if(c._nodup != d){
6590                 c._nodup = d;
6591             }else{
6592                 r = [];
6593                 for(var j = 0; j < i; j++){
6594                     r[++ri] = cs[j];
6595                 }
6596                 for(j = i+1; cj = cs[j]; j++){
6597                     if(cj._nodup != d){
6598                         cj._nodup = d;
6599                         r[++ri] = cj;
6600                     }
6601                 }
6602                 return r;
6603             }
6604         }
6605         return r;
6606     }
6607
6608     function quickDiffIEXml(c1, c2){
6609         var d = ++key;
6610         for(var i = 0, len = c1.length; i < len; i++){
6611             c1[i].setAttribute("_qdiff", d);
6612         }
6613         var r = [];
6614         for(var i = 0, len = c2.length; i < len; i++){
6615             if(c2[i].getAttribute("_qdiff") != d){
6616                 r[r.length] = c2[i];
6617             }
6618         }
6619         for(var i = 0, len = c1.length; i < len; i++){
6620            c1[i].removeAttribute("_qdiff");
6621         }
6622         return r;
6623     }
6624
6625     function quickDiff(c1, c2){
6626         var len1 = c1.length;
6627         if(!len1){
6628             return c2;
6629         }
6630         if(isIE && c1[0].selectSingleNode){
6631             return quickDiffIEXml(c1, c2);
6632         }
6633         var d = ++key;
6634         for(var i = 0; i < len1; i++){
6635             c1[i]._qdiff = d;
6636         }
6637         var r = [];
6638         for(var i = 0, len = c2.length; i < len; i++){
6639             if(c2[i]._qdiff != d){
6640                 r[r.length] = c2[i];
6641             }
6642         }
6643         return r;
6644     }
6645
6646     function quickId(ns, mode, root, id){
6647         if(ns == root){
6648            var d = root.ownerDocument || root;
6649            return d.getElementById(id);
6650         }
6651         ns = getNodes(ns, mode, "*");
6652         return byId(ns, null, id);
6653     }
6654
6655     return {
6656         getStyle : function(el, name){
6657             return Roo.fly(el).getStyle(name);
6658         },
6659         /**
6660          * Compiles a selector/xpath query into a reusable function. The returned function
6661          * takes one parameter "root" (optional), which is the context node from where the query should start.
6662          * @param {String} selector The selector/xpath query
6663          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6664          * @return {Function}
6665          */
6666         compile : function(path, type){
6667             type = type || "select";
6668             
6669             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6670             var q = path, mode, lq;
6671             var tk = Roo.DomQuery.matchers;
6672             var tklen = tk.length;
6673             var mm;
6674
6675             // accept leading mode switch
6676             var lmode = q.match(modeRe);
6677             if(lmode && lmode[1]){
6678                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6679                 q = q.replace(lmode[1], "");
6680             }
6681             // strip leading slashes
6682             while(path.substr(0, 1)=="/"){
6683                 path = path.substr(1);
6684             }
6685
6686             while(q && lq != q){
6687                 lq = q;
6688                 var tm = q.match(tagTokenRe);
6689                 if(type == "select"){
6690                     if(tm){
6691                         if(tm[1] == "#"){
6692                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6693                         }else{
6694                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6695                         }
6696                         q = q.replace(tm[0], "");
6697                     }else if(q.substr(0, 1) != '@'){
6698                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6699                     }
6700                 }else{
6701                     if(tm){
6702                         if(tm[1] == "#"){
6703                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6704                         }else{
6705                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6706                         }
6707                         q = q.replace(tm[0], "");
6708                     }
6709                 }
6710                 while(!(mm = q.match(modeRe))){
6711                     var matched = false;
6712                     for(var j = 0; j < tklen; j++){
6713                         var t = tk[j];
6714                         var m = q.match(t.re);
6715                         if(m){
6716                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6717                                                     return m[i];
6718                                                 });
6719                             q = q.replace(m[0], "");
6720                             matched = true;
6721                             break;
6722                         }
6723                     }
6724                     // prevent infinite loop on bad selector
6725                     if(!matched){
6726                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6727                     }
6728                 }
6729                 if(mm[1]){
6730                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6731                     q = q.replace(mm[1], "");
6732                 }
6733             }
6734             fn[fn.length] = "return nodup(n);\n}";
6735             
6736              /** 
6737               * list of variables that need from compression as they are used by eval.
6738              *  eval:var:batch 
6739              *  eval:var:nodup
6740              *  eval:var:byTag
6741              *  eval:var:ById
6742              *  eval:var:getNodes
6743              *  eval:var:quickId
6744              *  eval:var:mode
6745              *  eval:var:root
6746              *  eval:var:n
6747              *  eval:var:byClassName
6748              *  eval:var:byPseudo
6749              *  eval:var:byAttribute
6750              *  eval:var:attrValue
6751              * 
6752              **/ 
6753             eval(fn.join(""));
6754             return f;
6755         },
6756
6757         /**
6758          * Selects a group of elements.
6759          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6760          * @param {Node} root (optional) The start of the query (defaults to document).
6761          * @return {Array}
6762          */
6763         select : function(path, root, type){
6764             if(!root || root == document){
6765                 root = document;
6766             }
6767             if(typeof root == "string"){
6768                 root = document.getElementById(root);
6769             }
6770             var paths = path.split(",");
6771             var results = [];
6772             for(var i = 0, len = paths.length; i < len; i++){
6773                 var p = paths[i].replace(trimRe, "");
6774                 if(!cache[p]){
6775                     cache[p] = Roo.DomQuery.compile(p);
6776                     if(!cache[p]){
6777                         throw p + " is not a valid selector";
6778                     }
6779                 }
6780                 var result = cache[p](root);
6781                 if(result && result != document){
6782                     results = results.concat(result);
6783                 }
6784             }
6785             if(paths.length > 1){
6786                 return nodup(results);
6787             }
6788             return results;
6789         },
6790
6791         /**
6792          * Selects a single element.
6793          * @param {String} selector The selector/xpath query
6794          * @param {Node} root (optional) The start of the query (defaults to document).
6795          * @return {Element}
6796          */
6797         selectNode : function(path, root){
6798             return Roo.DomQuery.select(path, root)[0];
6799         },
6800
6801         /**
6802          * Selects the value of a node, optionally replacing null with the defaultValue.
6803          * @param {String} selector The selector/xpath query
6804          * @param {Node} root (optional) The start of the query (defaults to document).
6805          * @param {String} defaultValue
6806          */
6807         selectValue : function(path, root, defaultValue){
6808             path = path.replace(trimRe, "");
6809             if(!valueCache[path]){
6810                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6811             }
6812             var n = valueCache[path](root);
6813             n = n[0] ? n[0] : n;
6814             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6815             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6816         },
6817
6818         /**
6819          * Selects the value of a node, parsing integers and floats.
6820          * @param {String} selector The selector/xpath query
6821          * @param {Node} root (optional) The start of the query (defaults to document).
6822          * @param {Number} defaultValue
6823          * @return {Number}
6824          */
6825         selectNumber : function(path, root, defaultValue){
6826             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6827             return parseFloat(v);
6828         },
6829
6830         /**
6831          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6832          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6833          * @param {String} selector The simple selector to test
6834          * @return {Boolean}
6835          */
6836         is : function(el, ss){
6837             if(typeof el == "string"){
6838                 el = document.getElementById(el);
6839             }
6840             var isArray = (el instanceof Array);
6841             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6842             return isArray ? (result.length == el.length) : (result.length > 0);
6843         },
6844
6845         /**
6846          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6847          * @param {Array} el An array of elements to filter
6848          * @param {String} selector The simple selector to test
6849          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6850          * the selector instead of the ones that match
6851          * @return {Array}
6852          */
6853         filter : function(els, ss, nonMatches){
6854             ss = ss.replace(trimRe, "");
6855             if(!simpleCache[ss]){
6856                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6857             }
6858             var result = simpleCache[ss](els);
6859             return nonMatches ? quickDiff(result, els) : result;
6860         },
6861
6862         /**
6863          * Collection of matching regular expressions and code snippets.
6864          */
6865         matchers : [{
6866                 re: /^\.([\w-]+)/,
6867                 select: 'n = byClassName(n, null, " {1} ");'
6868             }, {
6869                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6870                 select: 'n = byPseudo(n, "{1}", "{2}");'
6871             },{
6872                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6873                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6874             }, {
6875                 re: /^#([\w-]+)/,
6876                 select: 'n = byId(n, null, "{1}");'
6877             },{
6878                 re: /^@([\w-]+)/,
6879                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6880             }
6881         ],
6882
6883         /**
6884          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6885          * 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;.
6886          */
6887         operators : {
6888             "=" : function(a, v){
6889                 return a == v;
6890             },
6891             "!=" : function(a, v){
6892                 return a != v;
6893             },
6894             "^=" : function(a, v){
6895                 return a && a.substr(0, v.length) == v;
6896             },
6897             "$=" : function(a, v){
6898                 return a && a.substr(a.length-v.length) == v;
6899             },
6900             "*=" : function(a, v){
6901                 return a && a.indexOf(v) !== -1;
6902             },
6903             "%=" : function(a, v){
6904                 return (a % v) == 0;
6905             },
6906             "|=" : function(a, v){
6907                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6908             },
6909             "~=" : function(a, v){
6910                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6911             }
6912         },
6913
6914         /**
6915          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6916          * and the argument (if any) supplied in the selector.
6917          */
6918         pseudos : {
6919             "first-child" : function(c){
6920                 var r = [], ri = -1, n;
6921                 for(var i = 0, ci; ci = n = c[i]; i++){
6922                     while((n = n.previousSibling) && n.nodeType != 1);
6923                     if(!n){
6924                         r[++ri] = ci;
6925                     }
6926                 }
6927                 return r;
6928             },
6929
6930             "last-child" : function(c){
6931                 var r = [], ri = -1, n;
6932                 for(var i = 0, ci; ci = n = c[i]; i++){
6933                     while((n = n.nextSibling) && n.nodeType != 1);
6934                     if(!n){
6935                         r[++ri] = ci;
6936                     }
6937                 }
6938                 return r;
6939             },
6940
6941             "nth-child" : function(c, a) {
6942                 var r = [], ri = -1;
6943                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6944                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6945                 for(var i = 0, n; n = c[i]; i++){
6946                     var pn = n.parentNode;
6947                     if (batch != pn._batch) {
6948                         var j = 0;
6949                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6950                             if(cn.nodeType == 1){
6951                                cn.nodeIndex = ++j;
6952                             }
6953                         }
6954                         pn._batch = batch;
6955                     }
6956                     if (f == 1) {
6957                         if (l == 0 || n.nodeIndex == l){
6958                             r[++ri] = n;
6959                         }
6960                     } else if ((n.nodeIndex + l) % f == 0){
6961                         r[++ri] = n;
6962                     }
6963                 }
6964
6965                 return r;
6966             },
6967
6968             "only-child" : function(c){
6969                 var r = [], ri = -1;;
6970                 for(var i = 0, ci; ci = c[i]; i++){
6971                     if(!prev(ci) && !next(ci)){
6972                         r[++ri] = ci;
6973                     }
6974                 }
6975                 return r;
6976             },
6977
6978             "empty" : function(c){
6979                 var r = [], ri = -1;
6980                 for(var i = 0, ci; ci = c[i]; i++){
6981                     var cns = ci.childNodes, j = 0, cn, empty = true;
6982                     while(cn = cns[j]){
6983                         ++j;
6984                         if(cn.nodeType == 1 || cn.nodeType == 3){
6985                             empty = false;
6986                             break;
6987                         }
6988                     }
6989                     if(empty){
6990                         r[++ri] = ci;
6991                     }
6992                 }
6993                 return r;
6994             },
6995
6996             "contains" : function(c, v){
6997                 var r = [], ri = -1;
6998                 for(var i = 0, ci; ci = c[i]; i++){
6999                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7000                         r[++ri] = ci;
7001                     }
7002                 }
7003                 return r;
7004             },
7005
7006             "nodeValue" : function(c, v){
7007                 var r = [], ri = -1;
7008                 for(var i = 0, ci; ci = c[i]; i++){
7009                     if(ci.firstChild && ci.firstChild.nodeValue == v){
7010                         r[++ri] = ci;
7011                     }
7012                 }
7013                 return r;
7014             },
7015
7016             "checked" : function(c){
7017                 var r = [], ri = -1;
7018                 for(var i = 0, ci; ci = c[i]; i++){
7019                     if(ci.checked == true){
7020                         r[++ri] = ci;
7021                     }
7022                 }
7023                 return r;
7024             },
7025
7026             "not" : function(c, ss){
7027                 return Roo.DomQuery.filter(c, ss, true);
7028             },
7029
7030             "odd" : function(c){
7031                 return this["nth-child"](c, "odd");
7032             },
7033
7034             "even" : function(c){
7035                 return this["nth-child"](c, "even");
7036             },
7037
7038             "nth" : function(c, a){
7039                 return c[a-1] || [];
7040             },
7041
7042             "first" : function(c){
7043                 return c[0] || [];
7044             },
7045
7046             "last" : function(c){
7047                 return c[c.length-1] || [];
7048             },
7049
7050             "has" : function(c, ss){
7051                 var s = Roo.DomQuery.select;
7052                 var r = [], ri = -1;
7053                 for(var i = 0, ci; ci = c[i]; i++){
7054                     if(s(ss, ci).length > 0){
7055                         r[++ri] = ci;
7056                     }
7057                 }
7058                 return r;
7059             },
7060
7061             "next" : function(c, ss){
7062                 var is = Roo.DomQuery.is;
7063                 var r = [], ri = -1;
7064                 for(var i = 0, ci; ci = c[i]; i++){
7065                     var n = next(ci);
7066                     if(n && is(n, ss)){
7067                         r[++ri] = ci;
7068                     }
7069                 }
7070                 return r;
7071             },
7072
7073             "prev" : function(c, ss){
7074                 var is = Roo.DomQuery.is;
7075                 var r = [], ri = -1;
7076                 for(var i = 0, ci; ci = c[i]; i++){
7077                     var n = prev(ci);
7078                     if(n && is(n, ss)){
7079                         r[++ri] = ci;
7080                     }
7081                 }
7082                 return r;
7083             }
7084         }
7085     };
7086 }();
7087
7088 /**
7089  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7090  * @param {String} path The selector/xpath query
7091  * @param {Node} root (optional) The start of the query (defaults to document).
7092  * @return {Array}
7093  * @member Roo
7094  * @method query
7095  */
7096 Roo.query = Roo.DomQuery.select;
7097 /*
7098  * Based on:
7099  * Ext JS Library 1.1.1
7100  * Copyright(c) 2006-2007, Ext JS, LLC.
7101  *
7102  * Originally Released Under LGPL - original licence link has changed is not relivant.
7103  *
7104  * Fork - LGPL
7105  * <script type="text/javascript">
7106  */
7107
7108 /**
7109  * @class Roo.util.Observable
7110  * Base class that provides a common interface for publishing events. Subclasses are expected to
7111  * to have a property "events" with all the events defined.<br>
7112  * For example:
7113  * <pre><code>
7114  Employee = function(name){
7115     this.name = name;
7116     this.addEvents({
7117         "fired" : true,
7118         "quit" : true
7119     });
7120  }
7121  Roo.extend(Employee, Roo.util.Observable);
7122 </code></pre>
7123  * @param {Object} config properties to use (incuding events / listeners)
7124  */
7125
7126 Roo.util.Observable = function(cfg){
7127     console.log("UTIL OBSERVABLE CONSTRUCTOR");
7128     consolg.log("config");
7129     
7130     cfg = cfg|| {};
7131     this.addEvents(cfg.events || {});
7132     if (cfg.events) {
7133         delete cfg.events; // make sure
7134     }
7135      
7136     Roo.apply(this, cfg);
7137     
7138     if(this.listeners){
7139         this.on(this.listeners);
7140         delete this.listeners;
7141     }
7142 };
7143 Roo.util.Observable.prototype = {
7144     /** 
7145  * @cfg {Object} listeners  list of events and functions to call for this object, 
7146  * For example :
7147  * <pre><code>
7148     listeners :  { 
7149        'click' : function(e) {
7150            ..... 
7151         } ,
7152         .... 
7153     } 
7154   </code></pre>
7155  */
7156     
7157     
7158     /**
7159      * Fires the specified event with the passed parameters (minus the event name).
7160      * @param {String} eventName
7161      * @param {Object...} args Variable number of parameters are passed to handlers
7162      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7163      */
7164     fireEvent : function(){
7165         var ce = this.events[arguments[0].toLowerCase()];
7166         if(typeof ce == "object"){
7167             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7168         }else{
7169             return true;
7170         }
7171     },
7172
7173     // private
7174     filterOptRe : /^(?:scope|delay|buffer|single)$/,
7175
7176     /**
7177      * Appends an event handler to this component
7178      * @param {String}   eventName The type of event to listen for
7179      * @param {Function} handler The method the event invokes
7180      * @param {Object}   scope (optional) The scope in which to execute the handler
7181      * function. The handler function's "this" context.
7182      * @param {Object}   options (optional) An object containing handler configuration
7183      * properties. This may contain any of the following properties:<ul>
7184      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7185      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7186      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7187      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7188      * by the specified number of milliseconds. If the event fires again within that time, the original
7189      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7190      * </ul><br>
7191      * <p>
7192      * <b>Combining Options</b><br>
7193      * Using the options argument, it is possible to combine different types of listeners:<br>
7194      * <br>
7195      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7196                 <pre><code>
7197                 el.on('click', this.onClick, this, {
7198                         single: true,
7199                 delay: 100,
7200                 forumId: 4
7201                 });
7202                 </code></pre>
7203      * <p>
7204      * <b>Attaching multiple handlers in 1 call</b><br>
7205      * The method also allows for a single argument to be passed which is a config object containing properties
7206      * which specify multiple handlers.
7207      * <pre><code>
7208                 el.on({
7209                         'click': {
7210                         fn: this.onClick,
7211                         scope: this,
7212                         delay: 100
7213                 }, 
7214                 'mouseover': {
7215                         fn: this.onMouseOver,
7216                         scope: this
7217                 },
7218                 'mouseout': {
7219                         fn: this.onMouseOut,
7220                         scope: this
7221                 }
7222                 });
7223                 </code></pre>
7224      * <p>
7225      * Or a shorthand syntax which passes the same scope object to all handlers:
7226         <pre><code>
7227                 el.on({
7228                         'click': this.onClick,
7229                 'mouseover': this.onMouseOver,
7230                 'mouseout': this.onMouseOut,
7231                 scope: this
7232                 });
7233                 </code></pre>
7234      */
7235     addListener : function(eventName, fn, scope, o){
7236         if(typeof eventName == "object"){
7237             o = eventName;
7238             for(var e in o){
7239                 if(this.filterOptRe.test(e)){
7240                     continue;
7241                 }
7242                 if(typeof o[e] == "function"){
7243                     // shared options
7244                     this.addListener(e, o[e], o.scope,  o);
7245                 }else{
7246                     // individual options
7247                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7248                 }
7249             }
7250             return;
7251         }
7252         o = (!o || typeof o == "boolean") ? {} : o;
7253         eventName = eventName.toLowerCase();
7254         var ce = this.events[eventName] || true;
7255         if(typeof ce == "boolean"){
7256             ce = new Roo.util.Event(this, eventName);
7257             this.events[eventName] = ce;
7258         }
7259         ce.addListener(fn, scope, o);
7260     },
7261
7262     /**
7263      * Removes a listener
7264      * @param {String}   eventName     The type of event to listen for
7265      * @param {Function} handler        The handler to remove
7266      * @param {Object}   scope  (optional) The scope (this object) for the handler
7267      */
7268     removeListener : function(eventName, fn, scope){
7269         var ce = this.events[eventName.toLowerCase()];
7270         if(typeof ce == "object"){
7271             ce.removeListener(fn, scope);
7272         }
7273     },
7274
7275     /**
7276      * Removes all listeners for this object
7277      */
7278     purgeListeners : function(){
7279         for(var evt in this.events){
7280             if(typeof this.events[evt] == "object"){
7281                  this.events[evt].clearListeners();
7282             }
7283         }
7284     },
7285
7286     relayEvents : function(o, events){
7287         var createHandler = function(ename){
7288             return function(){
7289                  
7290                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7291             };
7292         };
7293         for(var i = 0, len = events.length; i < len; i++){
7294             var ename = events[i];
7295             if(!this.events[ename]){
7296                 this.events[ename] = true;
7297             };
7298             o.on(ename, createHandler(ename), this);
7299         }
7300     },
7301
7302     /**
7303      * Used to define events on this Observable
7304      * @param {Object} object The object with the events defined
7305      */
7306     addEvents : function(o){
7307         if(!this.events){
7308             this.events = {};
7309         }
7310         Roo.applyIf(this.events, o);
7311     },
7312
7313     /**
7314      * Checks to see if this object has any listeners for a specified event
7315      * @param {String} eventName The name of the event to check for
7316      * @return {Boolean} True if the event is being listened for, else false
7317      */
7318     hasListener : function(eventName){
7319         var e = this.events[eventName];
7320         return typeof e == "object" && e.listeners.length > 0;
7321     }
7322 };
7323 /**
7324  * Appends an event handler to this element (shorthand for addListener)
7325  * @param {String}   eventName     The type of event to listen for
7326  * @param {Function} handler        The method the event invokes
7327  * @param {Object}   scope (optional) The scope in which to execute the handler
7328  * function. The handler function's "this" context.
7329  * @param {Object}   options  (optional)
7330  * @method
7331  */
7332 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7333 /**
7334  * Removes a listener (shorthand for removeListener)
7335  * @param {String}   eventName     The type of event to listen for
7336  * @param {Function} handler        The handler to remove
7337  * @param {Object}   scope  (optional) The scope (this object) for the handler
7338  * @method
7339  */
7340 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7341
7342 /**
7343  * Starts capture on the specified Observable. All events will be passed
7344  * to the supplied function with the event name + standard signature of the event
7345  * <b>before</b> the event is fired. If the supplied function returns false,
7346  * the event will not fire.
7347  * @param {Observable} o The Observable to capture
7348  * @param {Function} fn The function to call
7349  * @param {Object} scope (optional) The scope (this object) for the fn
7350  * @static
7351  */
7352 Roo.util.Observable.capture = function(o, fn, scope){
7353     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7354 };
7355
7356 /**
7357  * Removes <b>all</b> added captures from the Observable.
7358  * @param {Observable} o The Observable to release
7359  * @static
7360  */
7361 Roo.util.Observable.releaseCapture = function(o){
7362     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7363 };
7364
7365 (function(){
7366
7367     var createBuffered = function(h, o, scope){
7368         var task = new Roo.util.DelayedTask();
7369         return function(){
7370             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7371         };
7372     };
7373
7374     var createSingle = function(h, e, fn, scope){
7375         return function(){
7376             e.removeListener(fn, scope);
7377             return h.apply(scope, arguments);
7378         };
7379     };
7380
7381     var createDelayed = function(h, o, scope){
7382         return function(){
7383             var args = Array.prototype.slice.call(arguments, 0);
7384             setTimeout(function(){
7385                 h.apply(scope, args);
7386             }, o.delay || 10);
7387         };
7388     };
7389
7390     Roo.util.Event = function(obj, name){
7391         this.name = name;
7392         this.obj = obj;
7393         this.listeners = [];
7394     };
7395
7396     Roo.util.Event.prototype = {
7397         addListener : function(fn, scope, options){
7398             var o = options || {};
7399             scope = scope || this.obj;
7400             if(!this.isListening(fn, scope)){
7401                 var l = {fn: fn, scope: scope, options: o};
7402                 var h = fn;
7403                 if(o.delay){
7404                     h = createDelayed(h, o, scope);
7405                 }
7406                 if(o.single){
7407                     h = createSingle(h, this, fn, scope);
7408                 }
7409                 if(o.buffer){
7410                     h = createBuffered(h, o, scope);
7411                 }
7412                 l.fireFn = h;
7413                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7414                     this.listeners.push(l);
7415                 }else{
7416                     this.listeners = this.listeners.slice(0);
7417                     this.listeners.push(l);
7418                 }
7419             }
7420         },
7421
7422         findListener : function(fn, scope){
7423             scope = scope || this.obj;
7424             var ls = this.listeners;
7425             for(var i = 0, len = ls.length; i < len; i++){
7426                 var l = ls[i];
7427                 if(l.fn == fn && l.scope == scope){
7428                     return i;
7429                 }
7430             }
7431             return -1;
7432         },
7433
7434         isListening : function(fn, scope){
7435             return this.findListener(fn, scope) != -1;
7436         },
7437
7438         removeListener : function(fn, scope){
7439             var index;
7440             if((index = this.findListener(fn, scope)) != -1){
7441                 if(!this.firing){
7442                     this.listeners.splice(index, 1);
7443                 }else{
7444                     this.listeners = this.listeners.slice(0);
7445                     this.listeners.splice(index, 1);
7446                 }
7447                 return true;
7448             }
7449             return false;
7450         },
7451
7452         clearListeners : function(){
7453             this.listeners = [];
7454         },
7455
7456         fire : function(){
7457             var ls = this.listeners, scope, len = ls.length;
7458             if(len > 0){
7459                 this.firing = true;
7460                 var args = Array.prototype.slice.call(arguments, 0);                
7461                 for(var i = 0; i < len; i++){
7462                     var l = ls[i];
7463                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7464                         this.firing = false;
7465                         return false;
7466                     }
7467                 }
7468                 this.firing = false;
7469             }
7470             return true;
7471         }
7472     };
7473 })();/*
7474  * RooJS Library 
7475  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7476  *
7477  * Licence LGPL 
7478  *
7479  */
7480  
7481 /**
7482  * @class Roo.Document
7483  * @extends Roo.util.Observable
7484  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7485  * 
7486  * @param {Object} config the methods and properties of the 'base' class for the application.
7487  * 
7488  *  Generic Page handler - implement this to start your app..
7489  * 
7490  * eg.
7491  *  MyProject = new Roo.Document({
7492         events : {
7493             'load' : true // your events..
7494         },
7495         listeners : {
7496             'ready' : function() {
7497                 // fired on Roo.onReady()
7498             }
7499         }
7500  * 
7501  */
7502 Roo.Document = function(cfg) {
7503      
7504     this.addEvents({ 
7505         'ready' : true
7506     });
7507     Roo.util.Observable.call(this,cfg);
7508     
7509     var _this = this;
7510     
7511     Roo.onReady(function() {
7512         _this.fireEvent('ready');
7513     },null,false);
7514     
7515     
7516 }
7517
7518 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7519  * Based on:
7520  * Ext JS Library 1.1.1
7521  * Copyright(c) 2006-2007, Ext JS, LLC.
7522  *
7523  * Originally Released Under LGPL - original licence link has changed is not relivant.
7524  *
7525  * Fork - LGPL
7526  * <script type="text/javascript">
7527  */
7528
7529 /**
7530  * @class Roo.EventManager
7531  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7532  * several useful events directly.
7533  * See {@link Roo.EventObject} for more details on normalized event objects.
7534  * @static
7535  */
7536 Roo.EventManager = function(){
7537     var docReadyEvent, docReadyProcId, docReadyState = false;
7538     var resizeEvent, resizeTask, textEvent, textSize;
7539     var E = Roo.lib.Event;
7540     var D = Roo.lib.Dom;
7541
7542     
7543     
7544
7545     var fireDocReady = function(){
7546         if(!docReadyState){
7547             docReadyState = true;
7548             Roo.isReady = true;
7549             if(docReadyProcId){
7550                 clearInterval(docReadyProcId);
7551             }
7552             if(Roo.isGecko || Roo.isOpera) {
7553                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7554             }
7555             if(Roo.isIE){
7556                 var defer = document.getElementById("ie-deferred-loader");
7557                 if(defer){
7558                     defer.onreadystatechange = null;
7559                     defer.parentNode.removeChild(defer);
7560                 }
7561             }
7562             if(docReadyEvent){
7563                 docReadyEvent.fire();
7564                 docReadyEvent.clearListeners();
7565             }
7566         }
7567     };
7568     
7569     var initDocReady = function(){
7570         docReadyEvent = new Roo.util.Event();
7571         if(Roo.isGecko || Roo.isOpera) {
7572             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7573         }else if(Roo.isIE){
7574             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7575             var defer = document.getElementById("ie-deferred-loader");
7576             defer.onreadystatechange = function(){
7577                 if(this.readyState == "complete"){
7578                     fireDocReady();
7579                 }
7580             };
7581         }else if(Roo.isSafari){ 
7582             docReadyProcId = setInterval(function(){
7583                 var rs = document.readyState;
7584                 if(rs == "complete") {
7585                     fireDocReady();     
7586                  }
7587             }, 10);
7588         }
7589         // no matter what, make sure it fires on load
7590         E.on(window, "load", fireDocReady);
7591     };
7592
7593     var createBuffered = function(h, o){
7594         var task = new Roo.util.DelayedTask(h);
7595         return function(e){
7596             // create new event object impl so new events don't wipe out properties
7597             e = new Roo.EventObjectImpl(e);
7598             task.delay(o.buffer, h, null, [e]);
7599         };
7600     };
7601
7602     var createSingle = function(h, el, ename, fn){
7603         return function(e){
7604             Roo.EventManager.removeListener(el, ename, fn);
7605             h(e);
7606         };
7607     };
7608
7609     var createDelayed = function(h, o){
7610         return function(e){
7611             // create new event object impl so new events don't wipe out properties
7612             e = new Roo.EventObjectImpl(e);
7613             setTimeout(function(){
7614                 h(e);
7615             }, o.delay || 10);
7616         };
7617     };
7618     var transitionEndVal = false;
7619     
7620     var transitionEnd = function()
7621     {
7622         if (transitionEndVal) {
7623             return transitionEndVal;
7624         }
7625         var el = document.createElement('div');
7626
7627         var transEndEventNames = {
7628             WebkitTransition : 'webkitTransitionEnd',
7629             MozTransition    : 'transitionend',
7630             OTransition      : 'oTransitionEnd otransitionend',
7631             transition       : 'transitionend'
7632         };
7633     
7634         for (var name in transEndEventNames) {
7635             if (el.style[name] !== undefined) {
7636                 transitionEndVal = transEndEventNames[name];
7637                 return  transitionEndVal ;
7638             }
7639         }
7640     }
7641     
7642   
7643
7644     var listen = function(element, ename, opt, fn, scope)
7645     {
7646         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7647         fn = fn || o.fn; scope = scope || o.scope;
7648         var el = Roo.getDom(element);
7649         
7650         
7651         if(!el){
7652             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7653         }
7654         
7655         if (ename == 'transitionend') {
7656             ename = transitionEnd();
7657         }
7658         var h = function(e){
7659             e = Roo.EventObject.setEvent(e);
7660             var t;
7661             if(o.delegate){
7662                 t = e.getTarget(o.delegate, el);
7663                 if(!t){
7664                     return;
7665                 }
7666             }else{
7667                 t = e.target;
7668             }
7669             if(o.stopEvent === true){
7670                 e.stopEvent();
7671             }
7672             if(o.preventDefault === true){
7673                e.preventDefault();
7674             }
7675             if(o.stopPropagation === true){
7676                 e.stopPropagation();
7677             }
7678
7679             if(o.normalized === false){
7680                 e = e.browserEvent;
7681             }
7682
7683             fn.call(scope || el, e, t, o);
7684         };
7685         if(o.delay){
7686             h = createDelayed(h, o);
7687         }
7688         if(o.single){
7689             h = createSingle(h, el, ename, fn);
7690         }
7691         if(o.buffer){
7692             h = createBuffered(h, o);
7693         }
7694         
7695         fn._handlers = fn._handlers || [];
7696         
7697         
7698         fn._handlers.push([Roo.id(el), ename, h]);
7699         
7700         
7701          
7702         E.on(el, ename, h); // this adds the actuall listener to the object..
7703         
7704         
7705         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7706             el.addEventListener("DOMMouseScroll", h, false);
7707             E.on(window, 'unload', function(){
7708                 el.removeEventListener("DOMMouseScroll", h, false);
7709             });
7710         }
7711         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7712             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7713         }
7714         return h;
7715     };
7716
7717     var stopListening = function(el, ename, fn){
7718         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7719         if(hds){
7720             for(var i = 0, len = hds.length; i < len; i++){
7721                 var h = hds[i];
7722                 if(h[0] == id && h[1] == ename){
7723                     hd = h[2];
7724                     hds.splice(i, 1);
7725                     break;
7726                 }
7727             }
7728         }
7729         E.un(el, ename, hd);
7730         el = Roo.getDom(el);
7731         if(ename == "mousewheel" && el.addEventListener){
7732             el.removeEventListener("DOMMouseScroll", hd, false);
7733         }
7734         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7735             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7736         }
7737     };
7738
7739     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7740     
7741     var pub = {
7742         
7743         
7744         /** 
7745          * Fix for doc tools
7746          * @scope Roo.EventManager
7747          */
7748         
7749         
7750         /** 
7751          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7752          * object with a Roo.EventObject
7753          * @param {Function} fn        The method the event invokes
7754          * @param {Object}   scope    An object that becomes the scope of the handler
7755          * @param {boolean}  override If true, the obj passed in becomes
7756          *                             the execution scope of the listener
7757          * @return {Function} The wrapped function
7758          * @deprecated
7759          */
7760         wrap : function(fn, scope, override){
7761             return function(e){
7762                 Roo.EventObject.setEvent(e);
7763                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7764             };
7765         },
7766         
7767         /**
7768      * Appends an event handler to an element (shorthand for addListener)
7769      * @param {String/HTMLElement}   element        The html element or id to assign the
7770      * @param {String}   eventName The type of event to listen for
7771      * @param {Function} handler The method the event invokes
7772      * @param {Object}   scope (optional) The scope in which to execute the handler
7773      * function. The handler function's "this" context.
7774      * @param {Object}   options (optional) An object containing handler configuration
7775      * properties. This may contain any of the following properties:<ul>
7776      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7777      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7778      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7779      * <li>preventDefault {Boolean} True to prevent the default action</li>
7780      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7781      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7782      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7783      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7784      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7785      * by the specified number of milliseconds. If the event fires again within that time, the original
7786      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7787      * </ul><br>
7788      * <p>
7789      * <b>Combining Options</b><br>
7790      * Using the options argument, it is possible to combine different types of listeners:<br>
7791      * <br>
7792      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7793      * Code:<pre><code>
7794 el.on('click', this.onClick, this, {
7795     single: true,
7796     delay: 100,
7797     stopEvent : true,
7798     forumId: 4
7799 });</code></pre>
7800      * <p>
7801      * <b>Attaching multiple handlers in 1 call</b><br>
7802       * The method also allows for a single argument to be passed which is a config object containing properties
7803      * which specify multiple handlers.
7804      * <p>
7805      * Code:<pre><code>
7806 el.on({
7807     'click' : {
7808         fn: this.onClick
7809         scope: this,
7810         delay: 100
7811     },
7812     'mouseover' : {
7813         fn: this.onMouseOver
7814         scope: this
7815     },
7816     'mouseout' : {
7817         fn: this.onMouseOut
7818         scope: this
7819     }
7820 });</code></pre>
7821      * <p>
7822      * Or a shorthand syntax:<br>
7823      * Code:<pre><code>
7824 el.on({
7825     'click' : this.onClick,
7826     'mouseover' : this.onMouseOver,
7827     'mouseout' : this.onMouseOut
7828     scope: this
7829 });</code></pre>
7830      */
7831         addListener : function(element, eventName, fn, scope, options){
7832             if(typeof eventName == "object"){
7833                 var o = eventName;
7834                 for(var e in o){
7835                     if(propRe.test(e)){
7836                         continue;
7837                     }
7838                     if(typeof o[e] == "function"){
7839                         // shared options
7840                         listen(element, e, o, o[e], o.scope);
7841                     }else{
7842                         // individual options
7843                         listen(element, e, o[e]);
7844                     }
7845                 }
7846                 return;
7847             }
7848             return listen(element, eventName, options, fn, scope);
7849         },
7850         
7851         /**
7852          * Removes an event handler
7853          *
7854          * @param {String/HTMLElement}   element        The id or html element to remove the 
7855          *                             event from
7856          * @param {String}   eventName     The type of event
7857          * @param {Function} fn
7858          * @return {Boolean} True if a listener was actually removed
7859          */
7860         removeListener : function(element, eventName, fn){
7861             return stopListening(element, eventName, fn);
7862         },
7863         
7864         /**
7865          * Fires when the document is ready (before onload and before images are loaded). Can be 
7866          * accessed shorthanded Roo.onReady().
7867          * @param {Function} fn        The method the event invokes
7868          * @param {Object}   scope    An  object that becomes the scope of the handler
7869          * @param {boolean}  options
7870          */
7871         onDocumentReady : function(fn, scope, options){
7872             if(docReadyState){ // if it already fired
7873                 docReadyEvent.addListener(fn, scope, options);
7874                 docReadyEvent.fire();
7875                 docReadyEvent.clearListeners();
7876                 return;
7877             }
7878             if(!docReadyEvent){
7879                 initDocReady();
7880             }
7881             docReadyEvent.addListener(fn, scope, options);
7882         },
7883         
7884         /**
7885          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7886          * @param {Function} fn        The method the event invokes
7887          * @param {Object}   scope    An object that becomes the scope of the handler
7888          * @param {boolean}  options
7889          */
7890         onWindowResize : function(fn, scope, options)
7891         {
7892             if(!resizeEvent){
7893                 resizeEvent = new Roo.util.Event();
7894                 resizeTask = new Roo.util.DelayedTask(function(){
7895                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7896                 });
7897                 E.on(window, "resize", function()
7898                 {
7899                     if (Roo.isIE) {
7900                         resizeTask.delay(50);
7901                     } else {
7902                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7903                     }
7904                 });
7905             }
7906             resizeEvent.addListener(fn, scope, options);
7907         },
7908
7909         /**
7910          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7911          * @param {Function} fn        The method the event invokes
7912          * @param {Object}   scope    An object that becomes the scope of the handler
7913          * @param {boolean}  options
7914          */
7915         onTextResize : function(fn, scope, options){
7916             if(!textEvent){
7917                 textEvent = new Roo.util.Event();
7918                 var textEl = new Roo.Element(document.createElement('div'));
7919                 textEl.dom.className = 'x-text-resize';
7920                 textEl.dom.innerHTML = 'X';
7921                 textEl.appendTo(document.body);
7922                 textSize = textEl.dom.offsetHeight;
7923                 setInterval(function(){
7924                     if(textEl.dom.offsetHeight != textSize){
7925                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7926                     }
7927                 }, this.textResizeInterval);
7928             }
7929             textEvent.addListener(fn, scope, options);
7930         },
7931
7932         /**
7933          * Removes the passed window resize listener.
7934          * @param {Function} fn        The method the event invokes
7935          * @param {Object}   scope    The scope of handler
7936          */
7937         removeResizeListener : function(fn, scope){
7938             if(resizeEvent){
7939                 resizeEvent.removeListener(fn, scope);
7940             }
7941         },
7942
7943         // private
7944         fireResize : function(){
7945             if(resizeEvent){
7946                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7947             }   
7948         },
7949         /**
7950          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7951          */
7952         ieDeferSrc : false,
7953         /**
7954          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7955          */
7956         textResizeInterval : 50
7957     };
7958     
7959     /**
7960      * Fix for doc tools
7961      * @scopeAlias pub=Roo.EventManager
7962      */
7963     
7964      /**
7965      * Appends an event handler to an element (shorthand for addListener)
7966      * @param {String/HTMLElement}   element        The html element or id to assign the
7967      * @param {String}   eventName The type of event to listen for
7968      * @param {Function} handler The method the event invokes
7969      * @param {Object}   scope (optional) The scope in which to execute the handler
7970      * function. The handler function's "this" context.
7971      * @param {Object}   options (optional) An object containing handler configuration
7972      * properties. This may contain any of the following properties:<ul>
7973      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7974      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7975      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7976      * <li>preventDefault {Boolean} True to prevent the default action</li>
7977      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7978      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7979      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7980      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7981      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7982      * by the specified number of milliseconds. If the event fires again within that time, the original
7983      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7984      * </ul><br>
7985      * <p>
7986      * <b>Combining Options</b><br>
7987      * Using the options argument, it is possible to combine different types of listeners:<br>
7988      * <br>
7989      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7990      * Code:<pre><code>
7991 el.on('click', this.onClick, this, {
7992     single: true,
7993     delay: 100,
7994     stopEvent : true,
7995     forumId: 4
7996 });</code></pre>
7997      * <p>
7998      * <b>Attaching multiple handlers in 1 call</b><br>
7999       * The method also allows for a single argument to be passed which is a config object containing properties
8000      * which specify multiple handlers.
8001      * <p>
8002      * Code:<pre><code>
8003 el.on({
8004     'click' : {
8005         fn: this.onClick
8006         scope: this,
8007         delay: 100
8008     },
8009     'mouseover' : {
8010         fn: this.onMouseOver
8011         scope: this
8012     },
8013     'mouseout' : {
8014         fn: this.onMouseOut
8015         scope: this
8016     }
8017 });</code></pre>
8018      * <p>
8019      * Or a shorthand syntax:<br>
8020      * Code:<pre><code>
8021 el.on({
8022     'click' : this.onClick,
8023     'mouseover' : this.onMouseOver,
8024     'mouseout' : this.onMouseOut
8025     scope: this
8026 });</code></pre>
8027      */
8028     pub.on = pub.addListener;
8029     pub.un = pub.removeListener;
8030
8031     pub.stoppedMouseDownEvent = new Roo.util.Event();
8032     return pub;
8033 }();
8034 /**
8035   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
8036   * @param {Function} fn        The method the event invokes
8037   * @param {Object}   scope    An  object that becomes the scope of the handler
8038   * @param {boolean}  override If true, the obj passed in becomes
8039   *                             the execution scope of the listener
8040   * @member Roo
8041   * @method onReady
8042  */
8043 Roo.onReady = Roo.EventManager.onDocumentReady;
8044
8045 Roo.onReady(function(){
8046     var bd = Roo.get(document.body);
8047     if(!bd){ return; }
8048
8049     var cls = [
8050             Roo.isIE ? "roo-ie"
8051             : Roo.isIE11 ? "roo-ie11"
8052             : Roo.isEdge ? "roo-edge"
8053             : Roo.isGecko ? "roo-gecko"
8054             : Roo.isOpera ? "roo-opera"
8055             : Roo.isSafari ? "roo-safari" : ""];
8056
8057     if(Roo.isMac){
8058         cls.push("roo-mac");
8059     }
8060     if(Roo.isLinux){
8061         cls.push("roo-linux");
8062     }
8063     if(Roo.isIOS){
8064         cls.push("roo-ios");
8065     }
8066     if(Roo.isTouch){
8067         cls.push("roo-touch");
8068     }
8069     if(Roo.isBorderBox){
8070         cls.push('roo-border-box');
8071     }
8072     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8073         var p = bd.dom.parentNode;
8074         if(p){
8075             p.className += ' roo-strict';
8076         }
8077     }
8078     bd.addClass(cls.join(' '));
8079 });
8080
8081 /**
8082  * @class Roo.EventObject
8083  * EventObject exposes the Yahoo! UI Event functionality directly on the object
8084  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
8085  * Example:
8086  * <pre><code>
8087  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8088     e.preventDefault();
8089     var target = e.getTarget();
8090     ...
8091  }
8092  var myDiv = Roo.get("myDiv");
8093  myDiv.on("click", handleClick);
8094  //or
8095  Roo.EventManager.on("myDiv", 'click', handleClick);
8096  Roo.EventManager.addListener("myDiv", 'click', handleClick);
8097  </code></pre>
8098  * @static
8099  */
8100 Roo.EventObject = function(){
8101     
8102     var E = Roo.lib.Event;
8103     
8104     // safari keypress events for special keys return bad keycodes
8105     var safariKeys = {
8106         63234 : 37, // left
8107         63235 : 39, // right
8108         63232 : 38, // up
8109         63233 : 40, // down
8110         63276 : 33, // page up
8111         63277 : 34, // page down
8112         63272 : 46, // delete
8113         63273 : 36, // home
8114         63275 : 35  // end
8115     };
8116
8117     // normalize button clicks
8118     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8119                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8120
8121     Roo.EventObjectImpl = function(e){
8122         if(e){
8123             this.setEvent(e.browserEvent || e);
8124         }
8125     };
8126     Roo.EventObjectImpl.prototype = {
8127         /**
8128          * Used to fix doc tools.
8129          * @scope Roo.EventObject.prototype
8130          */
8131             
8132
8133         
8134         
8135         /** The normal browser event */
8136         browserEvent : null,
8137         /** The button pressed in a mouse event */
8138         button : -1,
8139         /** True if the shift key was down during the event */
8140         shiftKey : false,
8141         /** True if the control key was down during the event */
8142         ctrlKey : false,
8143         /** True if the alt key was down during the event */
8144         altKey : false,
8145
8146         /** Key constant 
8147         * @type Number */
8148         BACKSPACE : 8,
8149         /** Key constant 
8150         * @type Number */
8151         TAB : 9,
8152         /** Key constant 
8153         * @type Number */
8154         RETURN : 13,
8155         /** Key constant 
8156         * @type Number */
8157         ENTER : 13,
8158         /** Key constant 
8159         * @type Number */
8160         SHIFT : 16,
8161         /** Key constant 
8162         * @type Number */
8163         CONTROL : 17,
8164         /** Key constant 
8165         * @type Number */
8166         ESC : 27,
8167         /** Key constant 
8168         * @type Number */
8169         SPACE : 32,
8170         /** Key constant 
8171         * @type Number */
8172         PAGEUP : 33,
8173         /** Key constant 
8174         * @type Number */
8175         PAGEDOWN : 34,
8176         /** Key constant 
8177         * @type Number */
8178         END : 35,
8179         /** Key constant 
8180         * @type Number */
8181         HOME : 36,
8182         /** Key constant 
8183         * @type Number */
8184         LEFT : 37,
8185         /** Key constant 
8186         * @type Number */
8187         UP : 38,
8188         /** Key constant 
8189         * @type Number */
8190         RIGHT : 39,
8191         /** Key constant 
8192         * @type Number */
8193         DOWN : 40,
8194         /** Key constant 
8195         * @type Number */
8196         DELETE : 46,
8197         /** Key constant 
8198         * @type Number */
8199         F5 : 116,
8200
8201            /** @private */
8202         setEvent : function(e){
8203             if(e == this || (e && e.browserEvent)){ // already wrapped
8204                 return e;
8205             }
8206             this.browserEvent = e;
8207             if(e){
8208                 // normalize buttons
8209                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8210                 if(e.type == 'click' && this.button == -1){
8211                     this.button = 0;
8212                 }
8213                 this.type = e.type;
8214                 this.shiftKey = e.shiftKey;
8215                 // mac metaKey behaves like ctrlKey
8216                 this.ctrlKey = e.ctrlKey || e.metaKey;
8217                 this.altKey = e.altKey;
8218                 // in getKey these will be normalized for the mac
8219                 this.keyCode = e.keyCode;
8220                 // keyup warnings on firefox.
8221                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8222                 // cache the target for the delayed and or buffered events
8223                 this.target = E.getTarget(e);
8224                 // same for XY
8225                 this.xy = E.getXY(e);
8226             }else{
8227                 this.button = -1;
8228                 this.shiftKey = false;
8229                 this.ctrlKey = false;
8230                 this.altKey = false;
8231                 this.keyCode = 0;
8232                 this.charCode =0;
8233                 this.target = null;
8234                 this.xy = [0, 0];
8235             }
8236             return this;
8237         },
8238
8239         /**
8240          * Stop the event (preventDefault and stopPropagation)
8241          */
8242         stopEvent : function(){
8243             if(this.browserEvent){
8244                 if(this.browserEvent.type == 'mousedown'){
8245                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8246                 }
8247                 E.stopEvent(this.browserEvent);
8248             }
8249         },
8250
8251         /**
8252          * Prevents the browsers default handling of the event.
8253          */
8254         preventDefault : function(){
8255             if(this.browserEvent){
8256                 E.preventDefault(this.browserEvent);
8257             }
8258         },
8259
8260         /** @private */
8261         isNavKeyPress : function(){
8262             var k = this.keyCode;
8263             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8264             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8265         },
8266
8267         isSpecialKey : function(){
8268             var k = this.keyCode;
8269             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8270             (k == 16) || (k == 17) ||
8271             (k >= 18 && k <= 20) ||
8272             (k >= 33 && k <= 35) ||
8273             (k >= 36 && k <= 39) ||
8274             (k >= 44 && k <= 45);
8275         },
8276         /**
8277          * Cancels bubbling of the event.
8278          */
8279         stopPropagation : function(){
8280             if(this.browserEvent){
8281                 if(this.type == 'mousedown'){
8282                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8283                 }
8284                 E.stopPropagation(this.browserEvent);
8285             }
8286         },
8287
8288         /**
8289          * Gets the key code for the event.
8290          * @return {Number}
8291          */
8292         getCharCode : function(){
8293             return this.charCode || this.keyCode;
8294         },
8295
8296         /**
8297          * Returns a normalized keyCode for the event.
8298          * @return {Number} The key code
8299          */
8300         getKey : function(){
8301             var k = this.keyCode || this.charCode;
8302             return Roo.isSafari ? (safariKeys[k] || k) : k;
8303         },
8304
8305         /**
8306          * Gets the x coordinate of the event.
8307          * @return {Number}
8308          */
8309         getPageX : function(){
8310             return this.xy[0];
8311         },
8312
8313         /**
8314          * Gets the y coordinate of the event.
8315          * @return {Number}
8316          */
8317         getPageY : function(){
8318             return this.xy[1];
8319         },
8320
8321         /**
8322          * Gets the time of the event.
8323          * @return {Number}
8324          */
8325         getTime : function(){
8326             if(this.browserEvent){
8327                 return E.getTime(this.browserEvent);
8328             }
8329             return null;
8330         },
8331
8332         /**
8333          * Gets the page coordinates of the event.
8334          * @return {Array} The xy values like [x, y]
8335          */
8336         getXY : function(){
8337             return this.xy;
8338         },
8339
8340         /**
8341          * Gets the target for the event.
8342          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8343          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8344                 search as a number or element (defaults to 10 || document.body)
8345          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8346          * @return {HTMLelement}
8347          */
8348         getTarget : function(selector, maxDepth, returnEl){
8349             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8350         },
8351         /**
8352          * Gets the related target.
8353          * @return {HTMLElement}
8354          */
8355         getRelatedTarget : function(){
8356             if(this.browserEvent){
8357                 return E.getRelatedTarget(this.browserEvent);
8358             }
8359             return null;
8360         },
8361
8362         /**
8363          * Normalizes mouse wheel delta across browsers
8364          * @return {Number} The delta
8365          */
8366         getWheelDelta : function(){
8367             var e = this.browserEvent;
8368             var delta = 0;
8369             if(e.wheelDelta){ /* IE/Opera. */
8370                 delta = e.wheelDelta/120;
8371             }else if(e.detail){ /* Mozilla case. */
8372                 delta = -e.detail/3;
8373             }
8374             return delta;
8375         },
8376
8377         /**
8378          * Returns true if the control, meta, shift or alt key was pressed during this event.
8379          * @return {Boolean}
8380          */
8381         hasModifier : function(){
8382             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8383         },
8384
8385         /**
8386          * Returns true if the target of this event equals el or is a child of el
8387          * @param {String/HTMLElement/Element} el
8388          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8389          * @return {Boolean}
8390          */
8391         within : function(el, related){
8392             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8393             return t && Roo.fly(el).contains(t);
8394         },
8395
8396         getPoint : function(){
8397             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8398         }
8399     };
8400
8401     return new Roo.EventObjectImpl();
8402 }();
8403             
8404     /*
8405  * Based on:
8406  * Ext JS Library 1.1.1
8407  * Copyright(c) 2006-2007, Ext JS, LLC.
8408  *
8409  * Originally Released Under LGPL - original licence link has changed is not relivant.
8410  *
8411  * Fork - LGPL
8412  * <script type="text/javascript">
8413  */
8414
8415  
8416 // was in Composite Element!??!?!
8417  
8418 (function(){
8419     var D = Roo.lib.Dom;
8420     var E = Roo.lib.Event;
8421     var A = Roo.lib.Anim;
8422
8423     // local style camelizing for speed
8424     var propCache = {};
8425     var camelRe = /(-[a-z])/gi;
8426     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8427     var view = document.defaultView;
8428
8429 /**
8430  * @class Roo.Element
8431  * Represents an Element in the DOM.<br><br>
8432  * Usage:<br>
8433 <pre><code>
8434 var el = Roo.get("my-div");
8435
8436 // or with getEl
8437 var el = getEl("my-div");
8438
8439 // or with a DOM element
8440 var el = Roo.get(myDivElement);
8441 </code></pre>
8442  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8443  * each call instead of constructing a new one.<br><br>
8444  * <b>Animations</b><br />
8445  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8446  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8447 <pre>
8448 Option    Default   Description
8449 --------- --------  ---------------------------------------------
8450 duration  .35       The duration of the animation in seconds
8451 easing    easeOut   The YUI easing method
8452 callback  none      A function to execute when the anim completes
8453 scope     this      The scope (this) of the callback function
8454 </pre>
8455 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8456 * manipulate the animation. Here's an example:
8457 <pre><code>
8458 var el = Roo.get("my-div");
8459
8460 // no animation
8461 el.setWidth(100);
8462
8463 // default animation
8464 el.setWidth(100, true);
8465
8466 // animation with some options set
8467 el.setWidth(100, {
8468     duration: 1,
8469     callback: this.foo,
8470     scope: this
8471 });
8472
8473 // using the "anim" property to get the Anim object
8474 var opt = {
8475     duration: 1,
8476     callback: this.foo,
8477     scope: this
8478 };
8479 el.setWidth(100, opt);
8480 ...
8481 if(opt.anim.isAnimated()){
8482     opt.anim.stop();
8483 }
8484 </code></pre>
8485 * <b> Composite (Collections of) Elements</b><br />
8486  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8487  * @constructor Create a new Element directly.
8488  * @param {String/HTMLElement} element
8489  * @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).
8490  */
8491     Roo.Element = function(element, forceNew)
8492     {
8493         var dom = typeof element == "string" ?
8494                 document.getElementById(element) : element;
8495         
8496         this.listeners = {};
8497         
8498         if(!dom){ // invalid id/element
8499             return null;
8500         }
8501         var id = dom.id;
8502         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8503             return Roo.Element.cache[id];
8504         }
8505
8506         /**
8507          * The DOM element
8508          * @type HTMLElement
8509          */
8510         this.dom = dom;
8511
8512         /**
8513          * The DOM element ID
8514          * @type String
8515          */
8516         this.id = id || Roo.id(dom);
8517         
8518         return this; // assumed for cctor?
8519     };
8520
8521     var El = Roo.Element;
8522
8523     El.prototype = {
8524         /**
8525          * The element's default display mode  (defaults to "") 
8526          * @type String
8527          */
8528         originalDisplay : "",
8529
8530         
8531         // note this is overridden in BS version..
8532         visibilityMode : 1, 
8533         /**
8534          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8535          * @type String
8536          */
8537         defaultUnit : "px",
8538         
8539         /**
8540          * Sets the element's visibility mode. When setVisible() is called it
8541          * will use this to determine whether to set the visibility or the display property.
8542          * @param visMode Element.VISIBILITY or Element.DISPLAY
8543          * @return {Roo.Element} this
8544          */
8545         setVisibilityMode : function(visMode){
8546             this.visibilityMode = visMode;
8547             return this;
8548         },
8549         /**
8550          * Convenience method for setVisibilityMode(Element.DISPLAY)
8551          * @param {String} display (optional) What to set display to when visible
8552          * @return {Roo.Element} this
8553          */
8554         enableDisplayMode : function(display){
8555             this.setVisibilityMode(El.DISPLAY);
8556             if(typeof display != "undefined") { this.originalDisplay = display; }
8557             return this;
8558         },
8559
8560         /**
8561          * 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)
8562          * @param {String} selector The simple selector to test
8563          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8564                 search as a number or element (defaults to 10 || document.body)
8565          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8566          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8567          */
8568         findParent : function(simpleSelector, maxDepth, returnEl){
8569             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8570             maxDepth = maxDepth || 50;
8571             if(typeof maxDepth != "number"){
8572                 stopEl = Roo.getDom(maxDepth);
8573                 maxDepth = 10;
8574             }
8575             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8576                 if(dq.is(p, simpleSelector)){
8577                     return returnEl ? Roo.get(p) : p;
8578                 }
8579                 depth++;
8580                 p = p.parentNode;
8581             }
8582             return null;
8583         },
8584
8585
8586         /**
8587          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8588          * @param {String} selector The simple selector to test
8589          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8590                 search as a number or element (defaults to 10 || document.body)
8591          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8592          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8593          */
8594         findParentNode : function(simpleSelector, maxDepth, returnEl){
8595             var p = Roo.fly(this.dom.parentNode, '_internal');
8596             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8597         },
8598         
8599         /**
8600          * Looks at  the scrollable parent element
8601          */
8602         findScrollableParent : function()
8603         {
8604             var overflowRegex = /(auto|scroll)/;
8605             
8606             if(this.getStyle('position') === 'fixed'){
8607                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8608             }
8609             
8610             var excludeStaticParent = this.getStyle('position') === "absolute";
8611             
8612             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8613                 
8614                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8615                     continue;
8616                 }
8617                 
8618                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8619                     return parent;
8620                 }
8621                 
8622                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8623                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8624                 }
8625             }
8626             
8627             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8628         },
8629
8630         /**
8631          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8632          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8633          * @param {String} selector The simple selector to test
8634          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8635                 search as a number or element (defaults to 10 || document.body)
8636          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8637          */
8638         up : function(simpleSelector, maxDepth){
8639             return this.findParentNode(simpleSelector, maxDepth, true);
8640         },
8641
8642
8643
8644         /**
8645          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8646          * @param {String} selector The simple selector to test
8647          * @return {Boolean} True if this element matches the selector, else false
8648          */
8649         is : function(simpleSelector){
8650             return Roo.DomQuery.is(this.dom, simpleSelector);
8651         },
8652
8653         /**
8654          * Perform animation on this element.
8655          * @param {Object} args The YUI animation control args
8656          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8657          * @param {Function} onComplete (optional) Function to call when animation completes
8658          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8659          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8660          * @return {Roo.Element} this
8661          */
8662         animate : function(args, duration, onComplete, easing, animType){
8663             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8664             return this;
8665         },
8666
8667         /*
8668          * @private Internal animation call
8669          */
8670         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8671             animType = animType || 'run';
8672             opt = opt || {};
8673             var anim = Roo.lib.Anim[animType](
8674                 this.dom, args,
8675                 (opt.duration || defaultDur) || .35,
8676                 (opt.easing || defaultEase) || 'easeOut',
8677                 function(){
8678                     Roo.callback(cb, this);
8679                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8680                 },
8681                 this
8682             );
8683             opt.anim = anim;
8684             return anim;
8685         },
8686
8687         // private legacy anim prep
8688         preanim : function(a, i){
8689             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8690         },
8691
8692         /**
8693          * Removes worthless text nodes
8694          * @param {Boolean} forceReclean (optional) By default the element
8695          * keeps track if it has been cleaned already so
8696          * you can call this over and over. However, if you update the element and
8697          * need to force a reclean, you can pass true.
8698          */
8699         clean : function(forceReclean){
8700             if(this.isCleaned && forceReclean !== true){
8701                 return this;
8702             }
8703             var ns = /\S/;
8704             var d = this.dom, n = d.firstChild, ni = -1;
8705             while(n){
8706                 var nx = n.nextSibling;
8707                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8708                     d.removeChild(n);
8709                 }else{
8710                     n.nodeIndex = ++ni;
8711                 }
8712                 n = nx;
8713             }
8714             this.isCleaned = true;
8715             return this;
8716         },
8717
8718         // private
8719         calcOffsetsTo : function(el){
8720             el = Roo.get(el);
8721             var d = el.dom;
8722             var restorePos = false;
8723             if(el.getStyle('position') == 'static'){
8724                 el.position('relative');
8725                 restorePos = true;
8726             }
8727             var x = 0, y =0;
8728             var op = this.dom;
8729             while(op && op != d && op.tagName != 'HTML'){
8730                 x+= op.offsetLeft;
8731                 y+= op.offsetTop;
8732                 op = op.offsetParent;
8733             }
8734             if(restorePos){
8735                 el.position('static');
8736             }
8737             return [x, y];
8738         },
8739
8740         /**
8741          * Scrolls this element into view within the passed container.
8742          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8743          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8744          * @return {Roo.Element} this
8745          */
8746         scrollIntoView : function(container, hscroll){
8747             var c = Roo.getDom(container) || document.body;
8748             var el = this.dom;
8749
8750             var o = this.calcOffsetsTo(c),
8751                 l = o[0],
8752                 t = o[1],
8753                 b = t+el.offsetHeight,
8754                 r = l+el.offsetWidth;
8755
8756             var ch = c.clientHeight;
8757             var ct = parseInt(c.scrollTop, 10);
8758             var cl = parseInt(c.scrollLeft, 10);
8759             var cb = ct + ch;
8760             var cr = cl + c.clientWidth;
8761
8762             if(t < ct){
8763                 c.scrollTop = t;
8764             }else if(b > cb){
8765                 c.scrollTop = b-ch;
8766             }
8767
8768             if(hscroll !== false){
8769                 if(l < cl){
8770                     c.scrollLeft = l;
8771                 }else if(r > cr){
8772                     c.scrollLeft = r-c.clientWidth;
8773                 }
8774             }
8775             return this;
8776         },
8777
8778         // private
8779         scrollChildIntoView : function(child, hscroll){
8780             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8781         },
8782
8783         /**
8784          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8785          * the new height may not be available immediately.
8786          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8787          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8788          * @param {Function} onComplete (optional) Function to call when animation completes
8789          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8790          * @return {Roo.Element} this
8791          */
8792         autoHeight : function(animate, duration, onComplete, easing){
8793             var oldHeight = this.getHeight();
8794             this.clip();
8795             this.setHeight(1); // force clipping
8796             setTimeout(function(){
8797                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8798                 if(!animate){
8799                     this.setHeight(height);
8800                     this.unclip();
8801                     if(typeof onComplete == "function"){
8802                         onComplete();
8803                     }
8804                 }else{
8805                     this.setHeight(oldHeight); // restore original height
8806                     this.setHeight(height, animate, duration, function(){
8807                         this.unclip();
8808                         if(typeof onComplete == "function") { onComplete(); }
8809                     }.createDelegate(this), easing);
8810                 }
8811             }.createDelegate(this), 0);
8812             return this;
8813         },
8814
8815         /**
8816          * Returns true if this element is an ancestor of the passed element
8817          * @param {HTMLElement/String} el The element to check
8818          * @return {Boolean} True if this element is an ancestor of el, else false
8819          */
8820         contains : function(el){
8821             if(!el){return false;}
8822             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8823         },
8824
8825         /**
8826          * Checks whether the element is currently visible using both visibility and display properties.
8827          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8828          * @return {Boolean} True if the element is currently visible, else false
8829          */
8830         isVisible : function(deep) {
8831             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8832             if(deep !== true || !vis){
8833                 return vis;
8834             }
8835             var p = this.dom.parentNode;
8836             while(p && p.tagName.toLowerCase() != "body"){
8837                 if(!Roo.fly(p, '_isVisible').isVisible()){
8838                     return false;
8839                 }
8840                 p = p.parentNode;
8841             }
8842             return true;
8843         },
8844
8845         /**
8846          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8847          * @param {String} selector The CSS selector
8848          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8849          * @return {CompositeElement/CompositeElementLite} The composite element
8850          */
8851         select : function(selector, unique){
8852             return El.select(selector, unique, this.dom);
8853         },
8854
8855         /**
8856          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8857          * @param {String} selector The CSS selector
8858          * @return {Array} An array of the matched nodes
8859          */
8860         query : function(selector, unique){
8861             return Roo.DomQuery.select(selector, this.dom);
8862         },
8863
8864         /**
8865          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8866          * @param {String} selector The CSS selector
8867          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8868          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8869          */
8870         child : function(selector, returnDom){
8871             var n = Roo.DomQuery.selectNode(selector, this.dom);
8872             return returnDom ? n : Roo.get(n);
8873         },
8874
8875         /**
8876          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8877          * @param {String} selector The CSS selector
8878          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8879          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8880          */
8881         down : function(selector, returnDom){
8882             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8883             return returnDom ? n : Roo.get(n);
8884         },
8885
8886         /**
8887          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8888          * @param {String} group The group the DD object is member of
8889          * @param {Object} config The DD config object
8890          * @param {Object} overrides An object containing methods to override/implement on the DD object
8891          * @return {Roo.dd.DD} The DD object
8892          */
8893         initDD : function(group, config, overrides){
8894             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8895             return Roo.apply(dd, overrides);
8896         },
8897
8898         /**
8899          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8900          * @param {String} group The group the DDProxy object is member of
8901          * @param {Object} config The DDProxy config object
8902          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8903          * @return {Roo.dd.DDProxy} The DDProxy object
8904          */
8905         initDDProxy : function(group, config, overrides){
8906             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8907             return Roo.apply(dd, overrides);
8908         },
8909
8910         /**
8911          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8912          * @param {String} group The group the DDTarget object is member of
8913          * @param {Object} config The DDTarget config object
8914          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8915          * @return {Roo.dd.DDTarget} The DDTarget object
8916          */
8917         initDDTarget : function(group, config, overrides){
8918             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8919             return Roo.apply(dd, overrides);
8920         },
8921
8922         /**
8923          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8924          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8925          * @param {Boolean} visible Whether the element is visible
8926          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8927          * @return {Roo.Element} this
8928          */
8929          setVisible : function(visible, animate){
8930             if(!animate || !A){
8931                 if(this.visibilityMode == El.DISPLAY){
8932                     this.setDisplayed(visible);
8933                 }else{
8934                     this.fixDisplay();
8935                     this.dom.style.visibility = visible ? "visible" : "hidden";
8936                 }
8937             }else{
8938                 // closure for composites
8939                 var dom = this.dom;
8940                 var visMode = this.visibilityMode;
8941                 if(visible){
8942                     this.setOpacity(.01);
8943                     this.setVisible(true);
8944                 }
8945                 this.anim({opacity: { to: (visible?1:0) }},
8946                       this.preanim(arguments, 1),
8947                       null, .35, 'easeIn', function(){
8948                          if(!visible){
8949                              if(visMode == El.DISPLAY){
8950                                  dom.style.display = "none";
8951                              }else{
8952                                  dom.style.visibility = "hidden";
8953                              }
8954                              Roo.get(dom).setOpacity(1);
8955                          }
8956                      });
8957             }
8958             return this;
8959         },
8960
8961         /**
8962          * Returns true if display is not "none"
8963          * @return {Boolean}
8964          */
8965         isDisplayed : function() {
8966             return this.getStyle("display") != "none";
8967         },
8968
8969         /**
8970          * Toggles the element's visibility or display, depending on visibility mode.
8971          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8972          * @return {Roo.Element} this
8973          */
8974         toggle : function(animate){
8975             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8976             return this;
8977         },
8978
8979         /**
8980          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8981          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8982          * @return {Roo.Element} this
8983          */
8984         setDisplayed : function(value) {
8985             if(typeof value == "boolean"){
8986                value = value ? this.originalDisplay : "none";
8987             }
8988             this.setStyle("display", value);
8989             return this;
8990         },
8991
8992         /**
8993          * Tries to focus the element. Any exceptions are caught and ignored.
8994          * @return {Roo.Element} this
8995          */
8996         focus : function() {
8997             try{
8998                 this.dom.focus();
8999             }catch(e){}
9000             return this;
9001         },
9002
9003         /**
9004          * Tries to blur the element. Any exceptions are caught and ignored.
9005          * @return {Roo.Element} this
9006          */
9007         blur : function() {
9008             try{
9009                 this.dom.blur();
9010             }catch(e){}
9011             return this;
9012         },
9013
9014         /**
9015          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
9016          * @param {String/Array} className The CSS class to add, or an array of classes
9017          * @return {Roo.Element} this
9018          */
9019         addClass : function(className){
9020             if(className instanceof Array){
9021                 for(var i = 0, len = className.length; i < len; i++) {
9022                     this.addClass(className[i]);
9023                 }
9024             }else{
9025                 if(className && !this.hasClass(className)){
9026                     if (this.dom instanceof SVGElement) {
9027                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
9028                     } else {
9029                         this.dom.className = this.dom.className + " " + className;
9030                     }
9031                 }
9032             }
9033             return this;
9034         },
9035
9036         /**
9037          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9038          * @param {String/Array} className The CSS class to add, or an array of classes
9039          * @return {Roo.Element} this
9040          */
9041         radioClass : function(className){
9042             var siblings = this.dom.parentNode.childNodes;
9043             for(var i = 0; i < siblings.length; i++) {
9044                 var s = siblings[i];
9045                 if(s.nodeType == 1){
9046                     Roo.get(s).removeClass(className);
9047                 }
9048             }
9049             this.addClass(className);
9050             return this;
9051         },
9052
9053         /**
9054          * Removes one or more CSS classes from the element.
9055          * @param {String/Array} className The CSS class to remove, or an array of classes
9056          * @return {Roo.Element} this
9057          */
9058         removeClass : function(className){
9059             
9060             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9061             if(!className || !cn){
9062                 return this;
9063             }
9064             if(className instanceof Array){
9065                 for(var i = 0, len = className.length; i < len; i++) {
9066                     this.removeClass(className[i]);
9067                 }
9068             }else{
9069                 if(this.hasClass(className)){
9070                     var re = this.classReCache[className];
9071                     if (!re) {
9072                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9073                        this.classReCache[className] = re;
9074                     }
9075                     if (this.dom instanceof SVGElement) {
9076                         this.dom.className.baseVal = cn.replace(re, " ");
9077                     } else {
9078                         this.dom.className = cn.replace(re, " ");
9079                     }
9080                 }
9081             }
9082             return this;
9083         },
9084
9085         // private
9086         classReCache: {},
9087
9088         /**
9089          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9090          * @param {String} className The CSS class to toggle
9091          * @return {Roo.Element} this
9092          */
9093         toggleClass : function(className){
9094             if(this.hasClass(className)){
9095                 this.removeClass(className);
9096             }else{
9097                 this.addClass(className);
9098             }
9099             return this;
9100         },
9101
9102         /**
9103          * Checks if the specified CSS class exists on this element's DOM node.
9104          * @param {String} className The CSS class to check for
9105          * @return {Boolean} True if the class exists, else false
9106          */
9107         hasClass : function(className){
9108             if (this.dom instanceof SVGElement) {
9109                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
9110             } 
9111             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9112         },
9113
9114         /**
9115          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
9116          * @param {String} oldClassName The CSS class to replace
9117          * @param {String} newClassName The replacement CSS class
9118          * @return {Roo.Element} this
9119          */
9120         replaceClass : function(oldClassName, newClassName){
9121             this.removeClass(oldClassName);
9122             this.addClass(newClassName);
9123             return this;
9124         },
9125
9126         /**
9127          * Returns an object with properties matching the styles requested.
9128          * For example, el.getStyles('color', 'font-size', 'width') might return
9129          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9130          * @param {String} style1 A style name
9131          * @param {String} style2 A style name
9132          * @param {String} etc.
9133          * @return {Object} The style object
9134          */
9135         getStyles : function(){
9136             var a = arguments, len = a.length, r = {};
9137             for(var i = 0; i < len; i++){
9138                 r[a[i]] = this.getStyle(a[i]);
9139             }
9140             return r;
9141         },
9142
9143         /**
9144          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9145          * @param {String} property The style property whose value is returned.
9146          * @return {String} The current value of the style property for this element.
9147          */
9148         getStyle : function(){
9149             return view && view.getComputedStyle ?
9150                 function(prop){
9151                     var el = this.dom, v, cs, camel;
9152                     if(prop == 'float'){
9153                         prop = "cssFloat";
9154                     }
9155                     if(el.style && (v = el.style[prop])){
9156                         return v;
9157                     }
9158                     if(cs = view.getComputedStyle(el, "")){
9159                         if(!(camel = propCache[prop])){
9160                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
9161                         }
9162                         return cs[camel];
9163                     }
9164                     return null;
9165                 } :
9166                 function(prop){
9167                     var el = this.dom, v, cs, camel;
9168                     if(prop == 'opacity'){
9169                         if(typeof el.style.filter == 'string'){
9170                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9171                             if(m){
9172                                 var fv = parseFloat(m[1]);
9173                                 if(!isNaN(fv)){
9174                                     return fv ? fv / 100 : 0;
9175                                 }
9176                             }
9177                         }
9178                         return 1;
9179                     }else if(prop == 'float'){
9180                         prop = "styleFloat";
9181                     }
9182                     if(!(camel = propCache[prop])){
9183                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
9184                     }
9185                     if(v = el.style[camel]){
9186                         return v;
9187                     }
9188                     if(cs = el.currentStyle){
9189                         return cs[camel];
9190                     }
9191                     return null;
9192                 };
9193         }(),
9194
9195         /**
9196          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9197          * @param {String/Object} property The style property to be set, or an object of multiple styles.
9198          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9199          * @return {Roo.Element} this
9200          */
9201         setStyle : function(prop, value){
9202             if(typeof prop == "string"){
9203                 
9204                 if (prop == 'float') {
9205                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9206                     return this;
9207                 }
9208                 
9209                 var camel;
9210                 if(!(camel = propCache[prop])){
9211                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9212                 }
9213                 
9214                 if(camel == 'opacity') {
9215                     this.setOpacity(value);
9216                 }else{
9217                     this.dom.style[camel] = value;
9218                 }
9219             }else{
9220                 for(var style in prop){
9221                     if(typeof prop[style] != "function"){
9222                        this.setStyle(style, prop[style]);
9223                     }
9224                 }
9225             }
9226             return this;
9227         },
9228
9229         /**
9230          * More flexible version of {@link #setStyle} for setting style properties.
9231          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9232          * a function which returns such a specification.
9233          * @return {Roo.Element} this
9234          */
9235         applyStyles : function(style){
9236             Roo.DomHelper.applyStyles(this.dom, style);
9237             return this;
9238         },
9239
9240         /**
9241           * 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).
9242           * @return {Number} The X position of the element
9243           */
9244         getX : function(){
9245             return D.getX(this.dom);
9246         },
9247
9248         /**
9249           * 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).
9250           * @return {Number} The Y position of the element
9251           */
9252         getY : function(){
9253             return D.getY(this.dom);
9254         },
9255
9256         /**
9257           * 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).
9258           * @return {Array} The XY position of the element
9259           */
9260         getXY : function(){
9261             return D.getXY(this.dom);
9262         },
9263
9264         /**
9265          * 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).
9266          * @param {Number} The X position of the element
9267          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9268          * @return {Roo.Element} this
9269          */
9270         setX : function(x, animate){
9271             if(!animate || !A){
9272                 D.setX(this.dom, x);
9273             }else{
9274                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9275             }
9276             return this;
9277         },
9278
9279         /**
9280          * 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).
9281          * @param {Number} The Y position of the element
9282          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9283          * @return {Roo.Element} this
9284          */
9285         setY : function(y, animate){
9286             if(!animate || !A){
9287                 D.setY(this.dom, y);
9288             }else{
9289                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9290             }
9291             return this;
9292         },
9293
9294         /**
9295          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9296          * @param {String} left The left CSS property value
9297          * @return {Roo.Element} this
9298          */
9299         setLeft : function(left){
9300             this.setStyle("left", this.addUnits(left));
9301             return this;
9302         },
9303
9304         /**
9305          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9306          * @param {String} top The top CSS property value
9307          * @return {Roo.Element} this
9308          */
9309         setTop : function(top){
9310             this.setStyle("top", this.addUnits(top));
9311             return this;
9312         },
9313
9314         /**
9315          * Sets the element's CSS right style.
9316          * @param {String} right The right CSS property value
9317          * @return {Roo.Element} this
9318          */
9319         setRight : function(right){
9320             this.setStyle("right", this.addUnits(right));
9321             return this;
9322         },
9323
9324         /**
9325          * Sets the element's CSS bottom style.
9326          * @param {String} bottom The bottom CSS property value
9327          * @return {Roo.Element} this
9328          */
9329         setBottom : function(bottom){
9330             this.setStyle("bottom", this.addUnits(bottom));
9331             return this;
9332         },
9333
9334         /**
9335          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9336          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9337          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9338          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9339          * @return {Roo.Element} this
9340          */
9341         setXY : function(pos, animate){
9342             if(!animate || !A){
9343                 D.setXY(this.dom, pos);
9344             }else{
9345                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9346             }
9347             return this;
9348         },
9349
9350         /**
9351          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9352          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9353          * @param {Number} x X value for new position (coordinates are page-based)
9354          * @param {Number} y Y value for new position (coordinates are page-based)
9355          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9356          * @return {Roo.Element} this
9357          */
9358         setLocation : function(x, y, animate){
9359             this.setXY([x, y], this.preanim(arguments, 2));
9360             return this;
9361         },
9362
9363         /**
9364          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9365          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9366          * @param {Number} x X value for new position (coordinates are page-based)
9367          * @param {Number} y Y value for new position (coordinates are page-based)
9368          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9369          * @return {Roo.Element} this
9370          */
9371         moveTo : function(x, y, animate){
9372             this.setXY([x, y], this.preanim(arguments, 2));
9373             return this;
9374         },
9375
9376         /**
9377          * Returns the region of the given element.
9378          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9379          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9380          */
9381         getRegion : function(){
9382             return D.getRegion(this.dom);
9383         },
9384
9385         /**
9386          * Returns the offset height of the element
9387          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9388          * @return {Number} The element's height
9389          */
9390         getHeight : function(contentHeight){
9391             var h = this.dom.offsetHeight || 0;
9392             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9393         },
9394
9395         /**
9396          * Returns the offset width of the element
9397          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9398          * @return {Number} The element's width
9399          */
9400         getWidth : function(contentWidth){
9401             var w = this.dom.offsetWidth || 0;
9402             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9403         },
9404
9405         /**
9406          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9407          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9408          * if a height has not been set using CSS.
9409          * @return {Number}
9410          */
9411         getComputedHeight : function(){
9412             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9413             if(!h){
9414                 h = parseInt(this.getStyle('height'), 10) || 0;
9415                 if(!this.isBorderBox()){
9416                     h += this.getFrameWidth('tb');
9417                 }
9418             }
9419             return h;
9420         },
9421
9422         /**
9423          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9424          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9425          * if a width has not been set using CSS.
9426          * @return {Number}
9427          */
9428         getComputedWidth : function(){
9429             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9430             if(!w){
9431                 w = parseInt(this.getStyle('width'), 10) || 0;
9432                 if(!this.isBorderBox()){
9433                     w += this.getFrameWidth('lr');
9434                 }
9435             }
9436             return w;
9437         },
9438
9439         /**
9440          * Returns the size of the element.
9441          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9442          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9443          */
9444         getSize : function(contentSize){
9445             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9446         },
9447
9448         /**
9449          * Returns the width and height of the viewport.
9450          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9451          */
9452         getViewSize : function(){
9453             var d = this.dom, doc = document, aw = 0, ah = 0;
9454             if(d == doc || d == doc.body){
9455                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9456             }else{
9457                 return {
9458                     width : d.clientWidth,
9459                     height: d.clientHeight
9460                 };
9461             }
9462         },
9463
9464         /**
9465          * Returns the value of the "value" attribute
9466          * @param {Boolean} asNumber true to parse the value as a number
9467          * @return {String/Number}
9468          */
9469         getValue : function(asNumber){
9470             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9471         },
9472
9473         // private
9474         adjustWidth : function(width){
9475             if(typeof width == "number"){
9476                 if(this.autoBoxAdjust && !this.isBorderBox()){
9477                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9478                 }
9479                 if(width < 0){
9480                     width = 0;
9481                 }
9482             }
9483             return width;
9484         },
9485
9486         // private
9487         adjustHeight : function(height){
9488             if(typeof height == "number"){
9489                if(this.autoBoxAdjust && !this.isBorderBox()){
9490                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9491                }
9492                if(height < 0){
9493                    height = 0;
9494                }
9495             }
9496             return height;
9497         },
9498
9499         /**
9500          * Set the width of the element
9501          * @param {Number} width The new width
9502          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9503          * @return {Roo.Element} this
9504          */
9505         setWidth : function(width, animate){
9506             width = this.adjustWidth(width);
9507             if(!animate || !A){
9508                 this.dom.style.width = this.addUnits(width);
9509             }else{
9510                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9511             }
9512             return this;
9513         },
9514
9515         /**
9516          * Set the height of the element
9517          * @param {Number} height The new height
9518          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9519          * @return {Roo.Element} this
9520          */
9521          setHeight : function(height, animate){
9522             height = this.adjustHeight(height);
9523             if(!animate || !A){
9524                 this.dom.style.height = this.addUnits(height);
9525             }else{
9526                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9527             }
9528             return this;
9529         },
9530
9531         /**
9532          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9533          * @param {Number} width The new width
9534          * @param {Number} height The new height
9535          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9536          * @return {Roo.Element} this
9537          */
9538          setSize : function(width, height, animate){
9539             if(typeof width == "object"){ // in case of object from getSize()
9540                 height = width.height; width = width.width;
9541             }
9542             width = this.adjustWidth(width); height = this.adjustHeight(height);
9543             if(!animate || !A){
9544                 this.dom.style.width = this.addUnits(width);
9545                 this.dom.style.height = this.addUnits(height);
9546             }else{
9547                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9548             }
9549             return this;
9550         },
9551
9552         /**
9553          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9554          * @param {Number} x X value for new position (coordinates are page-based)
9555          * @param {Number} y Y value for new position (coordinates are page-based)
9556          * @param {Number} width The new width
9557          * @param {Number} height The new height
9558          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9559          * @return {Roo.Element} this
9560          */
9561         setBounds : function(x, y, width, height, animate){
9562             if(!animate || !A){
9563                 this.setSize(width, height);
9564                 this.setLocation(x, y);
9565             }else{
9566                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9567                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9568                               this.preanim(arguments, 4), 'motion');
9569             }
9570             return this;
9571         },
9572
9573         /**
9574          * 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.
9575          * @param {Roo.lib.Region} region The region to fill
9576          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9577          * @return {Roo.Element} this
9578          */
9579         setRegion : function(region, animate){
9580             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9581             return this;
9582         },
9583
9584         /**
9585          * Appends an event handler
9586          *
9587          * @param {String}   eventName     The type of event to append
9588          * @param {Function} fn        The method the event invokes
9589          * @param {Object} scope       (optional) The scope (this object) of the fn
9590          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9591          */
9592         addListener : function(eventName, fn, scope, options)
9593         {
9594             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9595                 this.addListener('touchstart', this.onTapHandler, this);
9596             }
9597             
9598             // we need to handle a special case where dom element is a svg element.
9599             // in this case we do not actua
9600             if (!this.dom) {
9601                 return;
9602             }
9603             
9604             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9605                 if (typeof(this.listeners[eventName]) == 'undefined') {
9606                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9607                 }
9608                 this.listeners[eventName].addListener(fn, scope, options);
9609                 return;
9610             }
9611             
9612                 
9613             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9614             
9615             
9616         },
9617         tapedTwice : false,
9618         onTapHandler : function(event)
9619         {
9620             if(!this.tapedTwice) {
9621                 this.tapedTwice = true;
9622                 var s = this;
9623                 setTimeout( function() {
9624                     s.tapedTwice = false;
9625                 }, 300 );
9626                 return;
9627             }
9628             event.preventDefault();
9629             var revent = new MouseEvent('dblclick',  {
9630                 view: window,
9631                 bubbles: true,
9632                 cancelable: true
9633             });
9634              
9635             this.dom.dispatchEvent(revent);
9636             //action on double tap goes below
9637              
9638         }, 
9639  
9640         /**
9641          * Removes an event handler from this element
9642          * @param {String} eventName the type of event to remove
9643          * @param {Function} fn the method the event invokes
9644          * @param {Function} scope (needed for svg fake listeners)
9645          * @return {Roo.Element} this
9646          */
9647         removeListener : function(eventName, fn, scope){
9648             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9649             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9650                 return this;
9651             }
9652             this.listeners[eventName].removeListener(fn, scope);
9653             return this;
9654         },
9655
9656         /**
9657          * Removes all previous added listeners from this element
9658          * @return {Roo.Element} this
9659          */
9660         removeAllListeners : function(){
9661             E.purgeElement(this.dom);
9662             this.listeners = {};
9663             return this;
9664         },
9665
9666         relayEvent : function(eventName, observable){
9667             this.on(eventName, function(e){
9668                 observable.fireEvent(eventName, e);
9669             });
9670         },
9671
9672         
9673         /**
9674          * Set the opacity of the element
9675          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9676          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9677          * @return {Roo.Element} this
9678          */
9679          setOpacity : function(opacity, animate){
9680             if(!animate || !A){
9681                 var s = this.dom.style;
9682                 if(Roo.isIE){
9683                     s.zoom = 1;
9684                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9685                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9686                 }else{
9687                     s.opacity = opacity;
9688                 }
9689             }else{
9690                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9691             }
9692             return this;
9693         },
9694
9695         /**
9696          * Gets the left X coordinate
9697          * @param {Boolean} local True to get the local css position instead of page coordinate
9698          * @return {Number}
9699          */
9700         getLeft : function(local){
9701             if(!local){
9702                 return this.getX();
9703             }else{
9704                 return parseInt(this.getStyle("left"), 10) || 0;
9705             }
9706         },
9707
9708         /**
9709          * Gets the right X coordinate of the element (element X position + element width)
9710          * @param {Boolean} local True to get the local css position instead of page coordinate
9711          * @return {Number}
9712          */
9713         getRight : function(local){
9714             if(!local){
9715                 return this.getX() + this.getWidth();
9716             }else{
9717                 return (this.getLeft(true) + this.getWidth()) || 0;
9718             }
9719         },
9720
9721         /**
9722          * Gets the top Y coordinate
9723          * @param {Boolean} local True to get the local css position instead of page coordinate
9724          * @return {Number}
9725          */
9726         getTop : function(local) {
9727             if(!local){
9728                 return this.getY();
9729             }else{
9730                 return parseInt(this.getStyle("top"), 10) || 0;
9731             }
9732         },
9733
9734         /**
9735          * Gets the bottom Y coordinate of the element (element Y position + element height)
9736          * @param {Boolean} local True to get the local css position instead of page coordinate
9737          * @return {Number}
9738          */
9739         getBottom : function(local){
9740             if(!local){
9741                 return this.getY() + this.getHeight();
9742             }else{
9743                 return (this.getTop(true) + this.getHeight()) || 0;
9744             }
9745         },
9746
9747         /**
9748         * Initializes positioning on this element. If a desired position is not passed, it will make the
9749         * the element positioned relative IF it is not already positioned.
9750         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9751         * @param {Number} zIndex (optional) The zIndex to apply
9752         * @param {Number} x (optional) Set the page X position
9753         * @param {Number} y (optional) Set the page Y position
9754         */
9755         position : function(pos, zIndex, x, y){
9756             if(!pos){
9757                if(this.getStyle('position') == 'static'){
9758                    this.setStyle('position', 'relative');
9759                }
9760             }else{
9761                 this.setStyle("position", pos);
9762             }
9763             if(zIndex){
9764                 this.setStyle("z-index", zIndex);
9765             }
9766             if(x !== undefined && y !== undefined){
9767                 this.setXY([x, y]);
9768             }else if(x !== undefined){
9769                 this.setX(x);
9770             }else if(y !== undefined){
9771                 this.setY(y);
9772             }
9773         },
9774
9775         /**
9776         * Clear positioning back to the default when the document was loaded
9777         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9778         * @return {Roo.Element} this
9779          */
9780         clearPositioning : function(value){
9781             value = value ||'';
9782             this.setStyle({
9783                 "left": value,
9784                 "right": value,
9785                 "top": value,
9786                 "bottom": value,
9787                 "z-index": "",
9788                 "position" : "static"
9789             });
9790             return this;
9791         },
9792
9793         /**
9794         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9795         * snapshot before performing an update and then restoring the element.
9796         * @return {Object}
9797         */
9798         getPositioning : function(){
9799             var l = this.getStyle("left");
9800             var t = this.getStyle("top");
9801             return {
9802                 "position" : this.getStyle("position"),
9803                 "left" : l,
9804                 "right" : l ? "" : this.getStyle("right"),
9805                 "top" : t,
9806                 "bottom" : t ? "" : this.getStyle("bottom"),
9807                 "z-index" : this.getStyle("z-index")
9808             };
9809         },
9810
9811         /**
9812          * Gets the width of the border(s) for the specified side(s)
9813          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9814          * passing lr would get the border (l)eft width + the border (r)ight width.
9815          * @return {Number} The width of the sides passed added together
9816          */
9817         getBorderWidth : function(side){
9818             return this.addStyles(side, El.borders);
9819         },
9820
9821         /**
9822          * Gets the width of the padding(s) for the specified side(s)
9823          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9824          * passing lr would get the padding (l)eft + the padding (r)ight.
9825          * @return {Number} The padding of the sides passed added together
9826          */
9827         getPadding : function(side){
9828             return this.addStyles(side, El.paddings);
9829         },
9830
9831         /**
9832         * Set positioning with an object returned by getPositioning().
9833         * @param {Object} posCfg
9834         * @return {Roo.Element} this
9835          */
9836         setPositioning : function(pc){
9837             this.applyStyles(pc);
9838             if(pc.right == "auto"){
9839                 this.dom.style.right = "";
9840             }
9841             if(pc.bottom == "auto"){
9842                 this.dom.style.bottom = "";
9843             }
9844             return this;
9845         },
9846
9847         // private
9848         fixDisplay : function(){
9849             if(this.getStyle("display") == "none"){
9850                 this.setStyle("visibility", "hidden");
9851                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9852                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9853                     this.setStyle("display", "block");
9854                 }
9855             }
9856         },
9857
9858         /**
9859          * Quick set left and top adding default units
9860          * @param {String} left The left CSS property value
9861          * @param {String} top The top CSS property value
9862          * @return {Roo.Element} this
9863          */
9864          setLeftTop : function(left, top){
9865             this.dom.style.left = this.addUnits(left);
9866             this.dom.style.top = this.addUnits(top);
9867             return this;
9868         },
9869
9870         /**
9871          * Move this element relative to its current position.
9872          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9873          * @param {Number} distance How far to move the element in pixels
9874          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9875          * @return {Roo.Element} this
9876          */
9877          move : function(direction, distance, animate){
9878             var xy = this.getXY();
9879             direction = direction.toLowerCase();
9880             switch(direction){
9881                 case "l":
9882                 case "left":
9883                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9884                     break;
9885                case "r":
9886                case "right":
9887                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9888                     break;
9889                case "t":
9890                case "top":
9891                case "up":
9892                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9893                     break;
9894                case "b":
9895                case "bottom":
9896                case "down":
9897                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9898                     break;
9899             }
9900             return this;
9901         },
9902
9903         /**
9904          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9905          * @return {Roo.Element} this
9906          */
9907         clip : function(){
9908             if(!this.isClipped){
9909                this.isClipped = true;
9910                this.originalClip = {
9911                    "o": this.getStyle("overflow"),
9912                    "x": this.getStyle("overflow-x"),
9913                    "y": this.getStyle("overflow-y")
9914                };
9915                this.setStyle("overflow", "hidden");
9916                this.setStyle("overflow-x", "hidden");
9917                this.setStyle("overflow-y", "hidden");
9918             }
9919             return this;
9920         },
9921
9922         /**
9923          *  Return clipping (overflow) to original clipping before clip() was called
9924          * @return {Roo.Element} this
9925          */
9926         unclip : function(){
9927             if(this.isClipped){
9928                 this.isClipped = false;
9929                 var o = this.originalClip;
9930                 if(o.o){this.setStyle("overflow", o.o);}
9931                 if(o.x){this.setStyle("overflow-x", o.x);}
9932                 if(o.y){this.setStyle("overflow-y", o.y);}
9933             }
9934             return this;
9935         },
9936
9937
9938         /**
9939          * Gets the x,y coordinates specified by the anchor position on the element.
9940          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9941          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9942          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9943          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9944          * @return {Array} [x, y] An array containing the element's x and y coordinates
9945          */
9946         getAnchorXY : function(anchor, local, s){
9947             //Passing a different size is useful for pre-calculating anchors,
9948             //especially for anchored animations that change the el size.
9949
9950             var w, h, vp = false;
9951             if(!s){
9952                 var d = this.dom;
9953                 if(d == document.body || d == document){
9954                     vp = true;
9955                     w = D.getViewWidth(); h = D.getViewHeight();
9956                 }else{
9957                     w = this.getWidth(); h = this.getHeight();
9958                 }
9959             }else{
9960                 w = s.width;  h = s.height;
9961             }
9962             var x = 0, y = 0, r = Math.round;
9963             switch((anchor || "tl").toLowerCase()){
9964                 case "c":
9965                     x = r(w*.5);
9966                     y = r(h*.5);
9967                 break;
9968                 case "t":
9969                     x = r(w*.5);
9970                     y = 0;
9971                 break;
9972                 case "l":
9973                     x = 0;
9974                     y = r(h*.5);
9975                 break;
9976                 case "r":
9977                     x = w;
9978                     y = r(h*.5);
9979                 break;
9980                 case "b":
9981                     x = r(w*.5);
9982                     y = h;
9983                 break;
9984                 case "tl":
9985                     x = 0;
9986                     y = 0;
9987                 break;
9988                 case "bl":
9989                     x = 0;
9990                     y = h;
9991                 break;
9992                 case "br":
9993                     x = w;
9994                     y = h;
9995                 break;
9996                 case "tr":
9997                     x = w;
9998                     y = 0;
9999                 break;
10000             }
10001             if(local === true){
10002                 return [x, y];
10003             }
10004             if(vp){
10005                 var sc = this.getScroll();
10006                 return [x + sc.left, y + sc.top];
10007             }
10008             //Add the element's offset xy
10009             var o = this.getXY();
10010             return [x+o[0], y+o[1]];
10011         },
10012
10013         /**
10014          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
10015          * supported position values.
10016          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10017          * @param {String} position The position to align to.
10018          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10019          * @return {Array} [x, y]
10020          */
10021         getAlignToXY : function(el, p, o)
10022         {
10023             el = Roo.get(el);
10024             var d = this.dom;
10025             if(!el.dom){
10026                 throw "Element.alignTo with an element that doesn't exist";
10027             }
10028             var c = false; //constrain to viewport
10029             var p1 = "", p2 = "";
10030             o = o || [0,0];
10031
10032             if(!p){
10033                 p = "tl-bl";
10034             }else if(p == "?"){
10035                 p = "tl-bl?";
10036             }else if(p.indexOf("-") == -1){
10037                 p = "tl-" + p;
10038             }
10039             p = p.toLowerCase();
10040             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10041             if(!m){
10042                throw "Element.alignTo with an invalid alignment " + p;
10043             }
10044             p1 = m[1]; p2 = m[2]; c = !!m[3];
10045
10046             //Subtract the aligned el's internal xy from the target's offset xy
10047             //plus custom offset to get the aligned el's new offset xy
10048             var a1 = this.getAnchorXY(p1, true);
10049             var a2 = el.getAnchorXY(p2, false);
10050             var x = a2[0] - a1[0] + o[0];
10051             var y = a2[1] - a1[1] + o[1];
10052             if(c){
10053                 //constrain the aligned el to viewport if necessary
10054                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10055                 // 5px of margin for ie
10056                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10057
10058                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10059                 //perpendicular to the vp border, allow the aligned el to slide on that border,
10060                 //otherwise swap the aligned el to the opposite border of the target.
10061                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10062                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10063                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
10064                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10065
10066                var doc = document;
10067                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10068                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10069
10070                if((x+w) > dw + scrollX){
10071                     x = swapX ? r.left-w : dw+scrollX-w;
10072                 }
10073                if(x < scrollX){
10074                    x = swapX ? r.right : scrollX;
10075                }
10076                if((y+h) > dh + scrollY){
10077                     y = swapY ? r.top-h : dh+scrollY-h;
10078                 }
10079                if (y < scrollY){
10080                    y = swapY ? r.bottom : scrollY;
10081                }
10082             }
10083             return [x,y];
10084         },
10085
10086         // private
10087         getConstrainToXY : function(){
10088             var os = {top:0, left:0, bottom:0, right: 0};
10089
10090             return function(el, local, offsets, proposedXY){
10091                 el = Roo.get(el);
10092                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10093
10094                 var vw, vh, vx = 0, vy = 0;
10095                 if(el.dom == document.body || el.dom == document){
10096                     vw = Roo.lib.Dom.getViewWidth();
10097                     vh = Roo.lib.Dom.getViewHeight();
10098                 }else{
10099                     vw = el.dom.clientWidth;
10100                     vh = el.dom.clientHeight;
10101                     if(!local){
10102                         var vxy = el.getXY();
10103                         vx = vxy[0];
10104                         vy = vxy[1];
10105                     }
10106                 }
10107
10108                 var s = el.getScroll();
10109
10110                 vx += offsets.left + s.left;
10111                 vy += offsets.top + s.top;
10112
10113                 vw -= offsets.right;
10114                 vh -= offsets.bottom;
10115
10116                 var vr = vx+vw;
10117                 var vb = vy+vh;
10118
10119                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10120                 var x = xy[0], y = xy[1];
10121                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10122
10123                 // only move it if it needs it
10124                 var moved = false;
10125
10126                 // first validate right/bottom
10127                 if((x + w) > vr){
10128                     x = vr - w;
10129                     moved = true;
10130                 }
10131                 if((y + h) > vb){
10132                     y = vb - h;
10133                     moved = true;
10134                 }
10135                 // then make sure top/left isn't negative
10136                 if(x < vx){
10137                     x = vx;
10138                     moved = true;
10139                 }
10140                 if(y < vy){
10141                     y = vy;
10142                     moved = true;
10143                 }
10144                 return moved ? [x, y] : false;
10145             };
10146         }(),
10147
10148         // private
10149         adjustForConstraints : function(xy, parent, offsets){
10150             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
10151         },
10152
10153         /**
10154          * Aligns this element with another element relative to the specified anchor points. If the other element is the
10155          * document it aligns it to the viewport.
10156          * The position parameter is optional, and can be specified in any one of the following formats:
10157          * <ul>
10158          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10159          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10160          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
10161          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
10162          *   <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
10163          *       element's anchor point, and the second value is used as the target's anchor point.</li>
10164          * </ul>
10165          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
10166          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10167          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
10168          * that specified in order to enforce the viewport constraints.
10169          * Following are all of the supported anchor positions:
10170     <pre>
10171     Value  Description
10172     -----  -----------------------------
10173     tl     The top left corner (default)
10174     t      The center of the top edge
10175     tr     The top right corner
10176     l      The center of the left edge
10177     c      In the center of the element
10178     r      The center of the right edge
10179     bl     The bottom left corner
10180     b      The center of the bottom edge
10181     br     The bottom right corner
10182     </pre>
10183     Example Usage:
10184     <pre><code>
10185     // align el to other-el using the default positioning ("tl-bl", non-constrained)
10186     el.alignTo("other-el");
10187
10188     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10189     el.alignTo("other-el", "tr?");
10190
10191     // align the bottom right corner of el with the center left edge of other-el
10192     el.alignTo("other-el", "br-l?");
10193
10194     // align the center of el with the bottom left corner of other-el and
10195     // adjust the x position by -6 pixels (and the y position by 0)
10196     el.alignTo("other-el", "c-bl", [-6, 0]);
10197     </code></pre>
10198          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10199          * @param {String} position The position to align to.
10200          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10201          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10202          * @return {Roo.Element} this
10203          */
10204         alignTo : function(element, position, offsets, animate){
10205             var xy = this.getAlignToXY(element, position, offsets);
10206             this.setXY(xy, this.preanim(arguments, 3));
10207             return this;
10208         },
10209
10210         /**
10211          * Anchors an element to another element and realigns it when the window is resized.
10212          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10213          * @param {String} position The position to align to.
10214          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10215          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10216          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10217          * is a number, it is used as the buffer delay (defaults to 50ms).
10218          * @param {Function} callback The function to call after the animation finishes
10219          * @return {Roo.Element} this
10220          */
10221         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10222             var action = function(){
10223                 this.alignTo(el, alignment, offsets, animate);
10224                 Roo.callback(callback, this);
10225             };
10226             Roo.EventManager.onWindowResize(action, this);
10227             var tm = typeof monitorScroll;
10228             if(tm != 'undefined'){
10229                 Roo.EventManager.on(window, 'scroll', action, this,
10230                     {buffer: tm == 'number' ? monitorScroll : 50});
10231             }
10232             action.call(this); // align immediately
10233             return this;
10234         },
10235         /**
10236          * Clears any opacity settings from this element. Required in some cases for IE.
10237          * @return {Roo.Element} this
10238          */
10239         clearOpacity : function(){
10240             if (window.ActiveXObject) {
10241                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10242                     this.dom.style.filter = "";
10243                 }
10244             } else {
10245                 this.dom.style.opacity = "";
10246                 this.dom.style["-moz-opacity"] = "";
10247                 this.dom.style["-khtml-opacity"] = "";
10248             }
10249             return this;
10250         },
10251
10252         /**
10253          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10254          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10255          * @return {Roo.Element} this
10256          */
10257         hide : function(animate){
10258             this.setVisible(false, this.preanim(arguments, 0));
10259             return this;
10260         },
10261
10262         /**
10263         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10264         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10265          * @return {Roo.Element} this
10266          */
10267         show : function(animate){
10268             this.setVisible(true, this.preanim(arguments, 0));
10269             return this;
10270         },
10271
10272         /**
10273          * @private Test if size has a unit, otherwise appends the default
10274          */
10275         addUnits : function(size){
10276             return Roo.Element.addUnits(size, this.defaultUnit);
10277         },
10278
10279         /**
10280          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10281          * @return {Roo.Element} this
10282          */
10283         beginMeasure : function(){
10284             var el = this.dom;
10285             if(el.offsetWidth || el.offsetHeight){
10286                 return this; // offsets work already
10287             }
10288             var changed = [];
10289             var p = this.dom, b = document.body; // start with this element
10290             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10291                 var pe = Roo.get(p);
10292                 if(pe.getStyle('display') == 'none'){
10293                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10294                     p.style.visibility = "hidden";
10295                     p.style.display = "block";
10296                 }
10297                 p = p.parentNode;
10298             }
10299             this._measureChanged = changed;
10300             return this;
10301
10302         },
10303
10304         /**
10305          * Restores displays to before beginMeasure was called
10306          * @return {Roo.Element} this
10307          */
10308         endMeasure : function(){
10309             var changed = this._measureChanged;
10310             if(changed){
10311                 for(var i = 0, len = changed.length; i < len; i++) {
10312                     var r = changed[i];
10313                     r.el.style.visibility = r.visibility;
10314                     r.el.style.display = "none";
10315                 }
10316                 this._measureChanged = null;
10317             }
10318             return this;
10319         },
10320
10321         /**
10322         * Update the innerHTML of this element, optionally searching for and processing scripts
10323         * @param {String} html The new HTML
10324         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10325         * @param {Function} callback For async script loading you can be noticed when the update completes
10326         * @return {Roo.Element} this
10327          */
10328         update : function(html, loadScripts, callback){
10329             if(typeof html == "undefined"){
10330                 html = "";
10331             }
10332             if(loadScripts !== true){
10333                 this.dom.innerHTML = html;
10334                 if(typeof callback == "function"){
10335                     callback();
10336                 }
10337                 return this;
10338             }
10339             var id = Roo.id();
10340             var dom = this.dom;
10341
10342             html += '<span id="' + id + '"></span>';
10343
10344             E.onAvailable(id, function(){
10345                 var hd = document.getElementsByTagName("head")[0];
10346                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10347                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10348                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10349
10350                 var match;
10351                 while(match = re.exec(html)){
10352                     var attrs = match[1];
10353                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10354                     if(srcMatch && srcMatch[2]){
10355                        var s = document.createElement("script");
10356                        s.src = srcMatch[2];
10357                        var typeMatch = attrs.match(typeRe);
10358                        if(typeMatch && typeMatch[2]){
10359                            s.type = typeMatch[2];
10360                        }
10361                        hd.appendChild(s);
10362                     }else if(match[2] && match[2].length > 0){
10363                         if(window.execScript) {
10364                            window.execScript(match[2]);
10365                         } else {
10366                             /**
10367                              * eval:var:id
10368                              * eval:var:dom
10369                              * eval:var:html
10370                              * 
10371                              */
10372                            window.eval(match[2]);
10373                         }
10374                     }
10375                 }
10376                 var el = document.getElementById(id);
10377                 if(el){el.parentNode.removeChild(el);}
10378                 if(typeof callback == "function"){
10379                     callback();
10380                 }
10381             });
10382             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10383             return this;
10384         },
10385
10386         /**
10387          * Direct access to the UpdateManager update() method (takes the same parameters).
10388          * @param {String/Function} url The url for this request or a function to call to get the url
10389          * @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}
10390          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10391          * @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.
10392          * @return {Roo.Element} this
10393          */
10394         load : function(){
10395             var um = this.getUpdateManager();
10396             um.update.apply(um, arguments);
10397             return this;
10398         },
10399
10400         /**
10401         * Gets this element's UpdateManager
10402         * @return {Roo.UpdateManager} The UpdateManager
10403         */
10404         getUpdateManager : function(){
10405             if(!this.updateManager){
10406                 this.updateManager = new Roo.UpdateManager(this);
10407             }
10408             return this.updateManager;
10409         },
10410
10411         /**
10412          * Disables text selection for this element (normalized across browsers)
10413          * @return {Roo.Element} this
10414          */
10415         unselectable : function(){
10416             this.dom.unselectable = "on";
10417             this.swallowEvent("selectstart", true);
10418             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10419             this.addClass("x-unselectable");
10420             return this;
10421         },
10422
10423         /**
10424         * Calculates the x, y to center this element on the screen
10425         * @return {Array} The x, y values [x, y]
10426         */
10427         getCenterXY : function(){
10428             return this.getAlignToXY(document, 'c-c');
10429         },
10430
10431         /**
10432         * Centers the Element in either the viewport, or another Element.
10433         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10434         */
10435         center : function(centerIn){
10436             this.alignTo(centerIn || document, 'c-c');
10437             return this;
10438         },
10439
10440         /**
10441          * Tests various css rules/browsers to determine if this element uses a border box
10442          * @return {Boolean}
10443          */
10444         isBorderBox : function(){
10445             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10446         },
10447
10448         /**
10449          * Return a box {x, y, width, height} that can be used to set another elements
10450          * size/location to match this element.
10451          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10452          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10453          * @return {Object} box An object in the format {x, y, width, height}
10454          */
10455         getBox : function(contentBox, local){
10456             var xy;
10457             if(!local){
10458                 xy = this.getXY();
10459             }else{
10460                 var left = parseInt(this.getStyle("left"), 10) || 0;
10461                 var top = parseInt(this.getStyle("top"), 10) || 0;
10462                 xy = [left, top];
10463             }
10464             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10465             if(!contentBox){
10466                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10467             }else{
10468                 var l = this.getBorderWidth("l")+this.getPadding("l");
10469                 var r = this.getBorderWidth("r")+this.getPadding("r");
10470                 var t = this.getBorderWidth("t")+this.getPadding("t");
10471                 var b = this.getBorderWidth("b")+this.getPadding("b");
10472                 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)};
10473             }
10474             bx.right = bx.x + bx.width;
10475             bx.bottom = bx.y + bx.height;
10476             return bx;
10477         },
10478
10479         /**
10480          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10481          for more information about the sides.
10482          * @param {String} sides
10483          * @return {Number}
10484          */
10485         getFrameWidth : function(sides, onlyContentBox){
10486             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10487         },
10488
10489         /**
10490          * 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.
10491          * @param {Object} box The box to fill {x, y, width, height}
10492          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10493          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10494          * @return {Roo.Element} this
10495          */
10496         setBox : function(box, adjust, animate){
10497             var w = box.width, h = box.height;
10498             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10499                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10500                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10501             }
10502             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10503             return this;
10504         },
10505
10506         /**
10507          * Forces the browser to repaint this element
10508          * @return {Roo.Element} this
10509          */
10510          repaint : function(){
10511             var dom = this.dom;
10512             this.addClass("x-repaint");
10513             setTimeout(function(){
10514                 Roo.get(dom).removeClass("x-repaint");
10515             }, 1);
10516             return this;
10517         },
10518
10519         /**
10520          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10521          * then it returns the calculated width of the sides (see getPadding)
10522          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10523          * @return {Object/Number}
10524          */
10525         getMargins : function(side){
10526             if(!side){
10527                 return {
10528                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10529                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10530                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10531                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10532                 };
10533             }else{
10534                 return this.addStyles(side, El.margins);
10535              }
10536         },
10537
10538         // private
10539         addStyles : function(sides, styles){
10540             var val = 0, v, w;
10541             for(var i = 0, len = sides.length; i < len; i++){
10542                 v = this.getStyle(styles[sides.charAt(i)]);
10543                 if(v){
10544                      w = parseInt(v, 10);
10545                      if(w){ val += w; }
10546                 }
10547             }
10548             return val;
10549         },
10550
10551         /**
10552          * Creates a proxy element of this element
10553          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10554          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10555          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10556          * @return {Roo.Element} The new proxy element
10557          */
10558         createProxy : function(config, renderTo, matchBox){
10559             if(renderTo){
10560                 renderTo = Roo.getDom(renderTo);
10561             }else{
10562                 renderTo = document.body;
10563             }
10564             config = typeof config == "object" ?
10565                 config : {tag : "div", cls: config};
10566             var proxy = Roo.DomHelper.append(renderTo, config, true);
10567             if(matchBox){
10568                proxy.setBox(this.getBox());
10569             }
10570             return proxy;
10571         },
10572
10573         /**
10574          * Puts a mask over this element to disable user interaction. Requires core.css.
10575          * This method can only be applied to elements which accept child nodes.
10576          * @param {String} msg (optional) A message to display in the mask
10577          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10578          * @return {Element} The mask  element
10579          */
10580         mask : function(msg, msgCls)
10581         {
10582             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10583                 this.setStyle("position", "relative");
10584             }
10585             if(!this._mask){
10586                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10587             }
10588             
10589             this.addClass("x-masked");
10590             this._mask.setDisplayed(true);
10591             
10592             // we wander
10593             var z = 0;
10594             var dom = this.dom;
10595             while (dom && dom.style) {
10596                 if (!isNaN(parseInt(dom.style.zIndex))) {
10597                     z = Math.max(z, parseInt(dom.style.zIndex));
10598                 }
10599                 dom = dom.parentNode;
10600             }
10601             // if we are masking the body - then it hides everything..
10602             if (this.dom == document.body) {
10603                 z = 1000000;
10604                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10605                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10606             }
10607            
10608             if(typeof msg == 'string'){
10609                 if(!this._maskMsg){
10610                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10611                         cls: "roo-el-mask-msg", 
10612                         cn: [
10613                             {
10614                                 tag: 'i',
10615                                 cls: 'fa fa-spinner fa-spin'
10616                             },
10617                             {
10618                                 tag: 'div'
10619                             }   
10620                         ]
10621                     }, true);
10622                 }
10623                 var mm = this._maskMsg;
10624                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10625                 if (mm.dom.lastChild) { // weird IE issue?
10626                     mm.dom.lastChild.innerHTML = msg;
10627                 }
10628                 mm.setDisplayed(true);
10629                 mm.center(this);
10630                 mm.setStyle('z-index', z + 102);
10631             }
10632             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10633                 this._mask.setHeight(this.getHeight());
10634             }
10635             this._mask.setStyle('z-index', z + 100);
10636             
10637             return this._mask;
10638         },
10639
10640         /**
10641          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10642          * it is cached for reuse.
10643          */
10644         unmask : function(removeEl){
10645             if(this._mask){
10646                 if(removeEl === true){
10647                     this._mask.remove();
10648                     delete this._mask;
10649                     if(this._maskMsg){
10650                         this._maskMsg.remove();
10651                         delete this._maskMsg;
10652                     }
10653                 }else{
10654                     this._mask.setDisplayed(false);
10655                     if(this._maskMsg){
10656                         this._maskMsg.setDisplayed(false);
10657                     }
10658                 }
10659             }
10660             this.removeClass("x-masked");
10661         },
10662
10663         /**
10664          * Returns true if this element is masked
10665          * @return {Boolean}
10666          */
10667         isMasked : function(){
10668             return this._mask && this._mask.isVisible();
10669         },
10670
10671         /**
10672          * Creates an iframe shim for this element to keep selects and other windowed objects from
10673          * showing through.
10674          * @return {Roo.Element} The new shim element
10675          */
10676         createShim : function(){
10677             var el = document.createElement('iframe');
10678             el.frameBorder = 'no';
10679             el.className = 'roo-shim';
10680             if(Roo.isIE && Roo.isSecure){
10681                 el.src = Roo.SSL_SECURE_URL;
10682             }
10683             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10684             shim.autoBoxAdjust = false;
10685             return shim;
10686         },
10687
10688         /**
10689          * Removes this element from the DOM and deletes it from the cache
10690          */
10691         remove : function(){
10692             if(this.dom.parentNode){
10693                 this.dom.parentNode.removeChild(this.dom);
10694             }
10695             delete El.cache[this.dom.id];
10696         },
10697
10698         /**
10699          * Sets up event handlers to add and remove a css class when the mouse is over this element
10700          * @param {String} className
10701          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10702          * mouseout events for children elements
10703          * @return {Roo.Element} this
10704          */
10705         addClassOnOver : function(className, preventFlicker){
10706             this.on("mouseover", function(){
10707                 Roo.fly(this, '_internal').addClass(className);
10708             }, this.dom);
10709             var removeFn = function(e){
10710                 if(preventFlicker !== true || !e.within(this, true)){
10711                     Roo.fly(this, '_internal').removeClass(className);
10712                 }
10713             };
10714             this.on("mouseout", removeFn, this.dom);
10715             return this;
10716         },
10717
10718         /**
10719          * Sets up event handlers to add and remove a css class when this element has the focus
10720          * @param {String} className
10721          * @return {Roo.Element} this
10722          */
10723         addClassOnFocus : function(className){
10724             this.on("focus", function(){
10725                 Roo.fly(this, '_internal').addClass(className);
10726             }, this.dom);
10727             this.on("blur", function(){
10728                 Roo.fly(this, '_internal').removeClass(className);
10729             }, this.dom);
10730             return this;
10731         },
10732         /**
10733          * 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)
10734          * @param {String} className
10735          * @return {Roo.Element} this
10736          */
10737         addClassOnClick : function(className){
10738             var dom = this.dom;
10739             this.on("mousedown", function(){
10740                 Roo.fly(dom, '_internal').addClass(className);
10741                 var d = Roo.get(document);
10742                 var fn = function(){
10743                     Roo.fly(dom, '_internal').removeClass(className);
10744                     d.removeListener("mouseup", fn);
10745                 };
10746                 d.on("mouseup", fn);
10747             });
10748             return this;
10749         },
10750
10751         /**
10752          * Stops the specified event from bubbling and optionally prevents the default action
10753          * @param {String} eventName
10754          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10755          * @return {Roo.Element} this
10756          */
10757         swallowEvent : function(eventName, preventDefault){
10758             var fn = function(e){
10759                 e.stopPropagation();
10760                 if(preventDefault){
10761                     e.preventDefault();
10762                 }
10763             };
10764             if(eventName instanceof Array){
10765                 for(var i = 0, len = eventName.length; i < len; i++){
10766                      this.on(eventName[i], fn);
10767                 }
10768                 return this;
10769             }
10770             this.on(eventName, fn);
10771             return this;
10772         },
10773
10774         /**
10775          * @private
10776          */
10777         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10778
10779         /**
10780          * Sizes this element to its parent element's dimensions performing
10781          * neccessary box adjustments.
10782          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10783          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10784          * @return {Roo.Element} this
10785          */
10786         fitToParent : function(monitorResize, targetParent) {
10787           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10788           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10789           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10790             return this;
10791           }
10792           var p = Roo.get(targetParent || this.dom.parentNode);
10793           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10794           if (monitorResize === true) {
10795             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10796             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10797           }
10798           return this;
10799         },
10800
10801         /**
10802          * Gets the next sibling, skipping text nodes
10803          * @return {HTMLElement} The next sibling or null
10804          */
10805         getNextSibling : function(){
10806             var n = this.dom.nextSibling;
10807             while(n && n.nodeType != 1){
10808                 n = n.nextSibling;
10809             }
10810             return n;
10811         },
10812
10813         /**
10814          * Gets the previous sibling, skipping text nodes
10815          * @return {HTMLElement} The previous sibling or null
10816          */
10817         getPrevSibling : function(){
10818             var n = this.dom.previousSibling;
10819             while(n && n.nodeType != 1){
10820                 n = n.previousSibling;
10821             }
10822             return n;
10823         },
10824
10825
10826         /**
10827          * Appends the passed element(s) to this element
10828          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10829          * @return {Roo.Element} this
10830          */
10831         appendChild: function(el){
10832             el = Roo.get(el);
10833             el.appendTo(this);
10834             return this;
10835         },
10836
10837         /**
10838          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10839          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10840          * automatically generated with the specified attributes.
10841          * @param {HTMLElement} insertBefore (optional) a child element of this element
10842          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10843          * @return {Roo.Element} The new child element
10844          */
10845         createChild: function(config, insertBefore, returnDom){
10846             config = config || {tag:'div'};
10847             if(insertBefore){
10848                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10849             }
10850             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10851         },
10852
10853         /**
10854          * Appends this element to the passed element
10855          * @param {String/HTMLElement/Element} el The new parent element
10856          * @return {Roo.Element} this
10857          */
10858         appendTo: function(el){
10859             el = Roo.getDom(el);
10860             el.appendChild(this.dom);
10861             return this;
10862         },
10863
10864         /**
10865          * Inserts this element before the passed element in the DOM
10866          * @param {String/HTMLElement/Element} el The element to insert before
10867          * @return {Roo.Element} this
10868          */
10869         insertBefore: function(el){
10870             el = Roo.getDom(el);
10871             el.parentNode.insertBefore(this.dom, el);
10872             return this;
10873         },
10874
10875         /**
10876          * Inserts this element after the passed element in the DOM
10877          * @param {String/HTMLElement/Element} el The element to insert after
10878          * @return {Roo.Element} this
10879          */
10880         insertAfter: function(el){
10881             el = Roo.getDom(el);
10882             el.parentNode.insertBefore(this.dom, el.nextSibling);
10883             return this;
10884         },
10885
10886         /**
10887          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10888          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10889          * @return {Roo.Element} The new child
10890          */
10891         insertFirst: function(el, returnDom){
10892             el = el || {};
10893             if(typeof el == 'object' && !el.nodeType){ // dh config
10894                 return this.createChild(el, this.dom.firstChild, returnDom);
10895             }else{
10896                 el = Roo.getDom(el);
10897                 this.dom.insertBefore(el, this.dom.firstChild);
10898                 return !returnDom ? Roo.get(el) : el;
10899             }
10900         },
10901
10902         /**
10903          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10904          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10905          * @param {String} where (optional) 'before' or 'after' defaults to before
10906          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10907          * @return {Roo.Element} the inserted Element
10908          */
10909         insertSibling: function(el, where, returnDom){
10910             where = where ? where.toLowerCase() : 'before';
10911             el = el || {};
10912             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10913
10914             if(typeof el == 'object' && !el.nodeType){ // dh config
10915                 if(where == 'after' && !this.dom.nextSibling){
10916                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10917                 }else{
10918                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10919                 }
10920
10921             }else{
10922                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10923                             where == 'before' ? this.dom : this.dom.nextSibling);
10924                 if(!returnDom){
10925                     rt = Roo.get(rt);
10926                 }
10927             }
10928             return rt;
10929         },
10930
10931         /**
10932          * Creates and wraps this element with another element
10933          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10934          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10935          * @return {HTMLElement/Element} The newly created wrapper element
10936          */
10937         wrap: function(config, returnDom){
10938             if(!config){
10939                 config = {tag: "div"};
10940             }
10941             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10942             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10943             return newEl;
10944         },
10945
10946         /**
10947          * Replaces the passed element with this element
10948          * @param {String/HTMLElement/Element} el The element to replace
10949          * @return {Roo.Element} this
10950          */
10951         replace: function(el){
10952             el = Roo.get(el);
10953             this.insertBefore(el);
10954             el.remove();
10955             return this;
10956         },
10957
10958         /**
10959          * Inserts an html fragment into this element
10960          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10961          * @param {String} html The HTML fragment
10962          * @param {Boolean} returnEl True to return an Roo.Element
10963          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10964          */
10965         insertHtml : function(where, html, returnEl){
10966             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10967             return returnEl ? Roo.get(el) : el;
10968         },
10969
10970         /**
10971          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10972          * @param {Object} o The object with the attributes
10973          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10974          * @return {Roo.Element} this
10975          */
10976         set : function(o, useSet){
10977             var el = this.dom;
10978             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10979             for(var attr in o){
10980                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10981                 if(attr=="cls"){
10982                     el.className = o["cls"];
10983                 }else{
10984                     if(useSet) {
10985                         el.setAttribute(attr, o[attr]);
10986                     } else {
10987                         el[attr] = o[attr];
10988                     }
10989                 }
10990             }
10991             if(o.style){
10992                 Roo.DomHelper.applyStyles(el, o.style);
10993             }
10994             return this;
10995         },
10996
10997         /**
10998          * Convenience method for constructing a KeyMap
10999          * @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:
11000          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
11001          * @param {Function} fn The function to call
11002          * @param {Object} scope (optional) The scope of the function
11003          * @return {Roo.KeyMap} The KeyMap created
11004          */
11005         addKeyListener : function(key, fn, scope){
11006             var config;
11007             if(typeof key != "object" || key instanceof Array){
11008                 config = {
11009                     key: key,
11010                     fn: fn,
11011                     scope: scope
11012                 };
11013             }else{
11014                 config = {
11015                     key : key.key,
11016                     shift : key.shift,
11017                     ctrl : key.ctrl,
11018                     alt : key.alt,
11019                     fn: fn,
11020                     scope: scope
11021                 };
11022             }
11023             return new Roo.KeyMap(this, config);
11024         },
11025
11026         /**
11027          * Creates a KeyMap for this element
11028          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11029          * @return {Roo.KeyMap} The KeyMap created
11030          */
11031         addKeyMap : function(config){
11032             return new Roo.KeyMap(this, config);
11033         },
11034
11035         /**
11036          * Returns true if this element is scrollable.
11037          * @return {Boolean}
11038          */
11039          isScrollable : function(){
11040             var dom = this.dom;
11041             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11042         },
11043
11044         /**
11045          * 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().
11046          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11047          * @param {Number} value The new scroll value
11048          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11049          * @return {Element} this
11050          */
11051
11052         scrollTo : function(side, value, animate){
11053             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11054             if(!animate || !A){
11055                 this.dom[prop] = value;
11056             }else{
11057                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11058                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11059             }
11060             return this;
11061         },
11062
11063         /**
11064          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11065          * within this element's scrollable range.
11066          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11067          * @param {Number} distance How far to scroll the element in pixels
11068          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11069          * @return {Boolean} Returns true if a scroll was triggered or false if the element
11070          * was scrolled as far as it could go.
11071          */
11072          scroll : function(direction, distance, animate){
11073              if(!this.isScrollable()){
11074                  return;
11075              }
11076              var el = this.dom;
11077              var l = el.scrollLeft, t = el.scrollTop;
11078              var w = el.scrollWidth, h = el.scrollHeight;
11079              var cw = el.clientWidth, ch = el.clientHeight;
11080              direction = direction.toLowerCase();
11081              var scrolled = false;
11082              var a = this.preanim(arguments, 2);
11083              switch(direction){
11084                  case "l":
11085                  case "left":
11086                      if(w - l > cw){
11087                          var v = Math.min(l + distance, w-cw);
11088                          this.scrollTo("left", v, a);
11089                          scrolled = true;
11090                      }
11091                      break;
11092                 case "r":
11093                 case "right":
11094                      if(l > 0){
11095                          var v = Math.max(l - distance, 0);
11096                          this.scrollTo("left", v, a);
11097                          scrolled = true;
11098                      }
11099                      break;
11100                 case "t":
11101                 case "top":
11102                 case "up":
11103                      if(t > 0){
11104                          var v = Math.max(t - distance, 0);
11105                          this.scrollTo("top", v, a);
11106                          scrolled = true;
11107                      }
11108                      break;
11109                 case "b":
11110                 case "bottom":
11111                 case "down":
11112                      if(h - t > ch){
11113                          var v = Math.min(t + distance, h-ch);
11114                          this.scrollTo("top", v, a);
11115                          scrolled = true;
11116                      }
11117                      break;
11118              }
11119              return scrolled;
11120         },
11121
11122         /**
11123          * Translates the passed page coordinates into left/top css values for this element
11124          * @param {Number/Array} x The page x or an array containing [x, y]
11125          * @param {Number} y The page y
11126          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11127          */
11128         translatePoints : function(x, y){
11129             if(typeof x == 'object' || x instanceof Array){
11130                 y = x[1]; x = x[0];
11131             }
11132             var p = this.getStyle('position');
11133             var o = this.getXY();
11134
11135             var l = parseInt(this.getStyle('left'), 10);
11136             var t = parseInt(this.getStyle('top'), 10);
11137
11138             if(isNaN(l)){
11139                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11140             }
11141             if(isNaN(t)){
11142                 t = (p == "relative") ? 0 : this.dom.offsetTop;
11143             }
11144
11145             return {left: (x - o[0] + l), top: (y - o[1] + t)};
11146         },
11147
11148         /**
11149          * Returns the current scroll position of the element.
11150          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11151          */
11152         getScroll : function(){
11153             var d = this.dom, doc = document;
11154             if(d == doc || d == doc.body){
11155                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11156                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11157                 return {left: l, top: t};
11158             }else{
11159                 return {left: d.scrollLeft, top: d.scrollTop};
11160             }
11161         },
11162
11163         /**
11164          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11165          * are convert to standard 6 digit hex color.
11166          * @param {String} attr The css attribute
11167          * @param {String} defaultValue The default value to use when a valid color isn't found
11168          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11169          * YUI color anims.
11170          */
11171         getColor : function(attr, defaultValue, prefix){
11172             var v = this.getStyle(attr);
11173             if(!v || v == "transparent" || v == "inherit") {
11174                 return defaultValue;
11175             }
11176             var color = typeof prefix == "undefined" ? "#" : prefix;
11177             if(v.substr(0, 4) == "rgb("){
11178                 var rvs = v.slice(4, v.length -1).split(",");
11179                 for(var i = 0; i < 3; i++){
11180                     var h = parseInt(rvs[i]).toString(16);
11181                     if(h < 16){
11182                         h = "0" + h;
11183                     }
11184                     color += h;
11185                 }
11186             } else {
11187                 if(v.substr(0, 1) == "#"){
11188                     if(v.length == 4) {
11189                         for(var i = 1; i < 4; i++){
11190                             var c = v.charAt(i);
11191                             color +=  c + c;
11192                         }
11193                     }else if(v.length == 7){
11194                         color += v.substr(1);
11195                     }
11196                 }
11197             }
11198             return(color.length > 5 ? color.toLowerCase() : defaultValue);
11199         },
11200
11201         /**
11202          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11203          * gradient background, rounded corners and a 4-way shadow.
11204          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11205          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11206          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11207          * @return {Roo.Element} this
11208          */
11209         boxWrap : function(cls){
11210             cls = cls || 'x-box';
11211             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11212             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11213             return el;
11214         },
11215
11216         /**
11217          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11218          * @param {String} namespace The namespace in which to look for the attribute
11219          * @param {String} name The attribute name
11220          * @return {String} The attribute value
11221          */
11222         getAttributeNS : Roo.isIE ? function(ns, name){
11223             var d = this.dom;
11224             var type = typeof d[ns+":"+name];
11225             if(type != 'undefined' && type != 'unknown'){
11226                 return d[ns+":"+name];
11227             }
11228             return d[name];
11229         } : function(ns, name){
11230             var d = this.dom;
11231             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11232         },
11233         
11234         
11235         /**
11236          * Sets or Returns the value the dom attribute value
11237          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11238          * @param {String} value (optional) The value to set the attribute to
11239          * @return {String} The attribute value
11240          */
11241         attr : function(name){
11242             if (arguments.length > 1) {
11243                 this.dom.setAttribute(name, arguments[1]);
11244                 return arguments[1];
11245             }
11246             if (typeof(name) == 'object') {
11247                 for(var i in name) {
11248                     this.attr(i, name[i]);
11249                 }
11250                 return name;
11251             }
11252             
11253             
11254             if (!this.dom.hasAttribute(name)) {
11255                 return undefined;
11256             }
11257             return this.dom.getAttribute(name);
11258         }
11259         
11260         
11261         
11262     };
11263
11264     var ep = El.prototype;
11265
11266     /**
11267      * Appends an event handler (Shorthand for addListener)
11268      * @param {String}   eventName     The type of event to append
11269      * @param {Function} fn        The method the event invokes
11270      * @param {Object} scope       (optional) The scope (this object) of the fn
11271      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11272      * @method
11273      */
11274     ep.on = ep.addListener;
11275         // backwards compat
11276     ep.mon = ep.addListener;
11277
11278     /**
11279      * Removes an event handler from this element (shorthand for removeListener)
11280      * @param {String} eventName the type of event to remove
11281      * @param {Function} fn the method the event invokes
11282      * @return {Roo.Element} this
11283      * @method
11284      */
11285     ep.un = ep.removeListener;
11286
11287     /**
11288      * true to automatically adjust width and height settings for box-model issues (default to true)
11289      */
11290     ep.autoBoxAdjust = true;
11291
11292     // private
11293     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11294
11295     // private
11296     El.addUnits = function(v, defaultUnit){
11297         if(v === "" || v == "auto"){
11298             return v;
11299         }
11300         if(v === undefined){
11301             return '';
11302         }
11303         if(typeof v == "number" || !El.unitPattern.test(v)){
11304             return v + (defaultUnit || 'px');
11305         }
11306         return v;
11307     };
11308
11309     // special markup used throughout Roo when box wrapping elements
11310     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>';
11311     /**
11312      * Visibility mode constant - Use visibility to hide element
11313      * @static
11314      * @type Number
11315      */
11316     El.VISIBILITY = 1;
11317     /**
11318      * Visibility mode constant - Use display to hide element
11319      * @static
11320      * @type Number
11321      */
11322     El.DISPLAY = 2;
11323
11324     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11325     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11326     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11327
11328
11329
11330     /**
11331      * @private
11332      */
11333     El.cache = {};
11334
11335     var docEl;
11336
11337     /**
11338      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11339      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11340      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11341      * @return {Element} The Element object
11342      * @static
11343      */
11344     El.get = function(el){
11345         var ex, elm, id;
11346         if(!el){ return null; }
11347         if(typeof el == "string"){ // element id
11348             if(!(elm = document.getElementById(el))){
11349                 return null;
11350             }
11351             if(ex = El.cache[el]){
11352                 ex.dom = elm;
11353             }else{
11354                 ex = El.cache[el] = new El(elm);
11355             }
11356             return ex;
11357         }else if(el.tagName){ // dom element
11358             if(!(id = el.id)){
11359                 id = Roo.id(el);
11360             }
11361             if(ex = El.cache[id]){
11362                 ex.dom = el;
11363             }else{
11364                 ex = El.cache[id] = new El(el);
11365             }
11366             return ex;
11367         }else if(el instanceof El){
11368             if(el != docEl){
11369                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11370                                                               // catch case where it hasn't been appended
11371                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11372             }
11373             return el;
11374         }else if(el.isComposite){
11375             return el;
11376         }else if(el instanceof Array){
11377             return El.select(el);
11378         }else if(el == document){
11379             // create a bogus element object representing the document object
11380             if(!docEl){
11381                 var f = function(){};
11382                 f.prototype = El.prototype;
11383                 docEl = new f();
11384                 docEl.dom = document;
11385             }
11386             return docEl;
11387         }
11388         return null;
11389     };
11390
11391     // private
11392     El.uncache = function(el){
11393         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11394             if(a[i]){
11395                 delete El.cache[a[i].id || a[i]];
11396             }
11397         }
11398     };
11399
11400     // private
11401     // Garbage collection - uncache elements/purge listeners on orphaned elements
11402     // so we don't hold a reference and cause the browser to retain them
11403     El.garbageCollect = function(){
11404         if(!Roo.enableGarbageCollector){
11405             clearInterval(El.collectorThread);
11406             return;
11407         }
11408         for(var eid in El.cache){
11409             var el = El.cache[eid], d = el.dom;
11410             // -------------------------------------------------------
11411             // Determining what is garbage:
11412             // -------------------------------------------------------
11413             // !d
11414             // dom node is null, definitely garbage
11415             // -------------------------------------------------------
11416             // !d.parentNode
11417             // no parentNode == direct orphan, definitely garbage
11418             // -------------------------------------------------------
11419             // !d.offsetParent && !document.getElementById(eid)
11420             // display none elements have no offsetParent so we will
11421             // also try to look it up by it's id. However, check
11422             // offsetParent first so we don't do unneeded lookups.
11423             // This enables collection of elements that are not orphans
11424             // directly, but somewhere up the line they have an orphan
11425             // parent.
11426             // -------------------------------------------------------
11427             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11428                 delete El.cache[eid];
11429                 if(d && Roo.enableListenerCollection){
11430                     E.purgeElement(d);
11431                 }
11432             }
11433         }
11434     }
11435     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11436
11437
11438     // dom is optional
11439     El.Flyweight = function(dom){
11440         this.dom = dom;
11441     };
11442     El.Flyweight.prototype = El.prototype;
11443
11444     El._flyweights = {};
11445     /**
11446      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11447      * the dom node can be overwritten by other code.
11448      * @param {String/HTMLElement} el The dom node or id
11449      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11450      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11451      * @static
11452      * @return {Element} The shared Element object
11453      */
11454     El.fly = function(el, named){
11455         named = named || '_global';
11456         el = Roo.getDom(el);
11457         if(!el){
11458             return null;
11459         }
11460         if(!El._flyweights[named]){
11461             El._flyweights[named] = new El.Flyweight();
11462         }
11463         El._flyweights[named].dom = el;
11464         return El._flyweights[named];
11465     };
11466
11467     /**
11468      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11469      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11470      * Shorthand of {@link Roo.Element#get}
11471      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11472      * @return {Element} The Element object
11473      * @member Roo
11474      * @method get
11475      */
11476     Roo.get = El.get;
11477     /**
11478      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11479      * the dom node can be overwritten by other code.
11480      * Shorthand of {@link Roo.Element#fly}
11481      * @param {String/HTMLElement} el The dom node or id
11482      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11483      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11484      * @static
11485      * @return {Element} The shared Element object
11486      * @member Roo
11487      * @method fly
11488      */
11489     Roo.fly = El.fly;
11490
11491     // speedy lookup for elements never to box adjust
11492     var noBoxAdjust = Roo.isStrict ? {
11493         select:1
11494     } : {
11495         input:1, select:1, textarea:1
11496     };
11497     if(Roo.isIE || Roo.isGecko){
11498         noBoxAdjust['button'] = 1;
11499     }
11500
11501
11502     Roo.EventManager.on(window, 'unload', function(){
11503         delete El.cache;
11504         delete El._flyweights;
11505     });
11506 })();
11507
11508
11509
11510
11511 if(Roo.DomQuery){
11512     Roo.Element.selectorFunction = Roo.DomQuery.select;
11513 }
11514
11515 Roo.Element.select = function(selector, unique, root){
11516     var els;
11517     if(typeof selector == "string"){
11518         els = Roo.Element.selectorFunction(selector, root);
11519     }else if(selector.length !== undefined){
11520         els = selector;
11521     }else{
11522         throw "Invalid selector";
11523     }
11524     if(unique === true){
11525         return new Roo.CompositeElement(els);
11526     }else{
11527         return new Roo.CompositeElementLite(els);
11528     }
11529 };
11530 /**
11531  * Selects elements based on the passed CSS selector to enable working on them as 1.
11532  * @param {String/Array} selector The CSS selector or an array of elements
11533  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11534  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11535  * @return {CompositeElementLite/CompositeElement}
11536  * @member Roo
11537  * @method select
11538  */
11539 Roo.select = Roo.Element.select;
11540
11541
11542
11543
11544
11545
11546
11547
11548
11549
11550
11551
11552
11553
11554 /*
11555  * Based on:
11556  * Ext JS Library 1.1.1
11557  * Copyright(c) 2006-2007, Ext JS, LLC.
11558  *
11559  * Originally Released Under LGPL - original licence link has changed is not relivant.
11560  *
11561  * Fork - LGPL
11562  * <script type="text/javascript">
11563  */
11564
11565
11566
11567 //Notifies Element that fx methods are available
11568 Roo.enableFx = true;
11569
11570 /**
11571  * @class Roo.Fx
11572  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11573  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11574  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11575  * Element effects to work.</p><br/>
11576  *
11577  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11578  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11579  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11580  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11581  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11582  * expected results and should be done with care.</p><br/>
11583  *
11584  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11585  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11586 <pre>
11587 Value  Description
11588 -----  -----------------------------
11589 tl     The top left corner
11590 t      The center of the top edge
11591 tr     The top right corner
11592 l      The center of the left edge
11593 r      The center of the right edge
11594 bl     The bottom left corner
11595 b      The center of the bottom edge
11596 br     The bottom right corner
11597 </pre>
11598  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11599  * below are common options that can be passed to any Fx method.</b>
11600  * @cfg {Function} callback A function called when the effect is finished
11601  * @cfg {Object} scope The scope of the effect function
11602  * @cfg {String} easing A valid Easing value for the effect
11603  * @cfg {String} afterCls A css class to apply after the effect
11604  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11605  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11606  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11607  * effects that end with the element being visually hidden, ignored otherwise)
11608  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11609  * a function which returns such a specification that will be applied to the Element after the effect finishes
11610  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11611  * @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
11612  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11613  */
11614 Roo.Fx = {
11615         /**
11616          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11617          * origin for the slide effect.  This function automatically handles wrapping the element with
11618          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11619          * Usage:
11620          *<pre><code>
11621 // default: slide the element in from the top
11622 el.slideIn();
11623
11624 // custom: slide the element in from the right with a 2-second duration
11625 el.slideIn('r', { duration: 2 });
11626
11627 // common config options shown with default values
11628 el.slideIn('t', {
11629     easing: 'easeOut',
11630     duration: .5
11631 });
11632 </code></pre>
11633          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11634          * @param {Object} options (optional) Object literal with any of the Fx config options
11635          * @return {Roo.Element} The Element
11636          */
11637     slideIn : function(anchor, o){
11638         var el = this.getFxEl();
11639         o = o || {};
11640
11641         el.queueFx(o, function(){
11642
11643             anchor = anchor || "t";
11644
11645             // fix display to visibility
11646             this.fixDisplay();
11647
11648             // restore values after effect
11649             var r = this.getFxRestore();
11650             var b = this.getBox();
11651             // fixed size for slide
11652             this.setSize(b);
11653
11654             // wrap if needed
11655             var wrap = this.fxWrap(r.pos, o, "hidden");
11656
11657             var st = this.dom.style;
11658             st.visibility = "visible";
11659             st.position = "absolute";
11660
11661             // clear out temp styles after slide and unwrap
11662             var after = function(){
11663                 el.fxUnwrap(wrap, r.pos, o);
11664                 st.width = r.width;
11665                 st.height = r.height;
11666                 el.afterFx(o);
11667             };
11668             // time to calc the positions
11669             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11670
11671             switch(anchor.toLowerCase()){
11672                 case "t":
11673                     wrap.setSize(b.width, 0);
11674                     st.left = st.bottom = "0";
11675                     a = {height: bh};
11676                 break;
11677                 case "l":
11678                     wrap.setSize(0, b.height);
11679                     st.right = st.top = "0";
11680                     a = {width: bw};
11681                 break;
11682                 case "r":
11683                     wrap.setSize(0, b.height);
11684                     wrap.setX(b.right);
11685                     st.left = st.top = "0";
11686                     a = {width: bw, points: pt};
11687                 break;
11688                 case "b":
11689                     wrap.setSize(b.width, 0);
11690                     wrap.setY(b.bottom);
11691                     st.left = st.top = "0";
11692                     a = {height: bh, points: pt};
11693                 break;
11694                 case "tl":
11695                     wrap.setSize(0, 0);
11696                     st.right = st.bottom = "0";
11697                     a = {width: bw, height: bh};
11698                 break;
11699                 case "bl":
11700                     wrap.setSize(0, 0);
11701                     wrap.setY(b.y+b.height);
11702                     st.right = st.top = "0";
11703                     a = {width: bw, height: bh, points: pt};
11704                 break;
11705                 case "br":
11706                     wrap.setSize(0, 0);
11707                     wrap.setXY([b.right, b.bottom]);
11708                     st.left = st.top = "0";
11709                     a = {width: bw, height: bh, points: pt};
11710                 break;
11711                 case "tr":
11712                     wrap.setSize(0, 0);
11713                     wrap.setX(b.x+b.width);
11714                     st.left = st.bottom = "0";
11715                     a = {width: bw, height: bh, points: pt};
11716                 break;
11717             }
11718             this.dom.style.visibility = "visible";
11719             wrap.show();
11720
11721             arguments.callee.anim = wrap.fxanim(a,
11722                 o,
11723                 'motion',
11724                 .5,
11725                 'easeOut', after);
11726         });
11727         return this;
11728     },
11729     
11730         /**
11731          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11732          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11733          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11734          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11735          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11736          * Usage:
11737          *<pre><code>
11738 // default: slide the element out to the top
11739 el.slideOut();
11740
11741 // custom: slide the element out to the right with a 2-second duration
11742 el.slideOut('r', { duration: 2 });
11743
11744 // common config options shown with default values
11745 el.slideOut('t', {
11746     easing: 'easeOut',
11747     duration: .5,
11748     remove: false,
11749     useDisplay: false
11750 });
11751 </code></pre>
11752          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11753          * @param {Object} options (optional) Object literal with any of the Fx config options
11754          * @return {Roo.Element} The Element
11755          */
11756     slideOut : function(anchor, o){
11757         var el = this.getFxEl();
11758         o = o || {};
11759
11760         el.queueFx(o, function(){
11761
11762             anchor = anchor || "t";
11763
11764             // restore values after effect
11765             var r = this.getFxRestore();
11766             
11767             var b = this.getBox();
11768             // fixed size for slide
11769             this.setSize(b);
11770
11771             // wrap if needed
11772             var wrap = this.fxWrap(r.pos, o, "visible");
11773
11774             var st = this.dom.style;
11775             st.visibility = "visible";
11776             st.position = "absolute";
11777
11778             wrap.setSize(b);
11779
11780             var after = function(){
11781                 if(o.useDisplay){
11782                     el.setDisplayed(false);
11783                 }else{
11784                     el.hide();
11785                 }
11786
11787                 el.fxUnwrap(wrap, r.pos, o);
11788
11789                 st.width = r.width;
11790                 st.height = r.height;
11791
11792                 el.afterFx(o);
11793             };
11794
11795             var a, zero = {to: 0};
11796             switch(anchor.toLowerCase()){
11797                 case "t":
11798                     st.left = st.bottom = "0";
11799                     a = {height: zero};
11800                 break;
11801                 case "l":
11802                     st.right = st.top = "0";
11803                     a = {width: zero};
11804                 break;
11805                 case "r":
11806                     st.left = st.top = "0";
11807                     a = {width: zero, points: {to:[b.right, b.y]}};
11808                 break;
11809                 case "b":
11810                     st.left = st.top = "0";
11811                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11812                 break;
11813                 case "tl":
11814                     st.right = st.bottom = "0";
11815                     a = {width: zero, height: zero};
11816                 break;
11817                 case "bl":
11818                     st.right = st.top = "0";
11819                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11820                 break;
11821                 case "br":
11822                     st.left = st.top = "0";
11823                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11824                 break;
11825                 case "tr":
11826                     st.left = st.bottom = "0";
11827                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11828                 break;
11829             }
11830
11831             arguments.callee.anim = wrap.fxanim(a,
11832                 o,
11833                 'motion',
11834                 .5,
11835                 "easeOut", after);
11836         });
11837         return this;
11838     },
11839
11840         /**
11841          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11842          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11843          * The element must be removed from the DOM using the 'remove' config option if desired.
11844          * Usage:
11845          *<pre><code>
11846 // default
11847 el.puff();
11848
11849 // common config options shown with default values
11850 el.puff({
11851     easing: 'easeOut',
11852     duration: .5,
11853     remove: false,
11854     useDisplay: false
11855 });
11856 </code></pre>
11857          * @param {Object} options (optional) Object literal with any of the Fx config options
11858          * @return {Roo.Element} The Element
11859          */
11860     puff : function(o){
11861         var el = this.getFxEl();
11862         o = o || {};
11863
11864         el.queueFx(o, function(){
11865             this.clearOpacity();
11866             this.show();
11867
11868             // restore values after effect
11869             var r = this.getFxRestore();
11870             var st = this.dom.style;
11871
11872             var after = function(){
11873                 if(o.useDisplay){
11874                     el.setDisplayed(false);
11875                 }else{
11876                     el.hide();
11877                 }
11878
11879                 el.clearOpacity();
11880
11881                 el.setPositioning(r.pos);
11882                 st.width = r.width;
11883                 st.height = r.height;
11884                 st.fontSize = '';
11885                 el.afterFx(o);
11886             };
11887
11888             var width = this.getWidth();
11889             var height = this.getHeight();
11890
11891             arguments.callee.anim = this.fxanim({
11892                     width : {to: this.adjustWidth(width * 2)},
11893                     height : {to: this.adjustHeight(height * 2)},
11894                     points : {by: [-(width * .5), -(height * .5)]},
11895                     opacity : {to: 0},
11896                     fontSize: {to:200, unit: "%"}
11897                 },
11898                 o,
11899                 'motion',
11900                 .5,
11901                 "easeOut", after);
11902         });
11903         return this;
11904     },
11905
11906         /**
11907          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11908          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11909          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11910          * Usage:
11911          *<pre><code>
11912 // default
11913 el.switchOff();
11914
11915 // all config options shown with default values
11916 el.switchOff({
11917     easing: 'easeIn',
11918     duration: .3,
11919     remove: false,
11920     useDisplay: false
11921 });
11922 </code></pre>
11923          * @param {Object} options (optional) Object literal with any of the Fx config options
11924          * @return {Roo.Element} The Element
11925          */
11926     switchOff : function(o){
11927         var el = this.getFxEl();
11928         o = o || {};
11929
11930         el.queueFx(o, function(){
11931             this.clearOpacity();
11932             this.clip();
11933
11934             // restore values after effect
11935             var r = this.getFxRestore();
11936             var st = this.dom.style;
11937
11938             var after = function(){
11939                 if(o.useDisplay){
11940                     el.setDisplayed(false);
11941                 }else{
11942                     el.hide();
11943                 }
11944
11945                 el.clearOpacity();
11946                 el.setPositioning(r.pos);
11947                 st.width = r.width;
11948                 st.height = r.height;
11949
11950                 el.afterFx(o);
11951             };
11952
11953             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11954                 this.clearOpacity();
11955                 (function(){
11956                     this.fxanim({
11957                         height:{to:1},
11958                         points:{by:[0, this.getHeight() * .5]}
11959                     }, o, 'motion', 0.3, 'easeIn', after);
11960                 }).defer(100, this);
11961             });
11962         });
11963         return this;
11964     },
11965
11966     /**
11967      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11968      * changed using the "attr" config option) and then fading back to the original color. If no original
11969      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11970      * Usage:
11971 <pre><code>
11972 // default: highlight background to yellow
11973 el.highlight();
11974
11975 // custom: highlight foreground text to blue for 2 seconds
11976 el.highlight("0000ff", { attr: 'color', duration: 2 });
11977
11978 // common config options shown with default values
11979 el.highlight("ffff9c", {
11980     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11981     endColor: (current color) or "ffffff",
11982     easing: 'easeIn',
11983     duration: 1
11984 });
11985 </code></pre>
11986      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11987      * @param {Object} options (optional) Object literal with any of the Fx config options
11988      * @return {Roo.Element} The Element
11989      */ 
11990     highlight : function(color, o){
11991         var el = this.getFxEl();
11992         o = o || {};
11993
11994         el.queueFx(o, function(){
11995             color = color || "ffff9c";
11996             attr = o.attr || "backgroundColor";
11997
11998             this.clearOpacity();
11999             this.show();
12000
12001             var origColor = this.getColor(attr);
12002             var restoreColor = this.dom.style[attr];
12003             endColor = (o.endColor || origColor) || "ffffff";
12004
12005             var after = function(){
12006                 el.dom.style[attr] = restoreColor;
12007                 el.afterFx(o);
12008             };
12009
12010             var a = {};
12011             a[attr] = {from: color, to: endColor};
12012             arguments.callee.anim = this.fxanim(a,
12013                 o,
12014                 'color',
12015                 1,
12016                 'easeIn', after);
12017         });
12018         return this;
12019     },
12020
12021    /**
12022     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
12023     * Usage:
12024 <pre><code>
12025 // default: a single light blue ripple
12026 el.frame();
12027
12028 // custom: 3 red ripples lasting 3 seconds total
12029 el.frame("ff0000", 3, { duration: 3 });
12030
12031 // common config options shown with default values
12032 el.frame("C3DAF9", 1, {
12033     duration: 1 //duration of entire animation (not each individual ripple)
12034     // Note: Easing is not configurable and will be ignored if included
12035 });
12036 </code></pre>
12037     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12038     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12039     * @param {Object} options (optional) Object literal with any of the Fx config options
12040     * @return {Roo.Element} The Element
12041     */
12042     frame : function(color, count, o){
12043         var el = this.getFxEl();
12044         o = o || {};
12045
12046         el.queueFx(o, function(){
12047             color = color || "#C3DAF9";
12048             if(color.length == 6){
12049                 color = "#" + color;
12050             }
12051             count = count || 1;
12052             duration = o.duration || 1;
12053             this.show();
12054
12055             var b = this.getBox();
12056             var animFn = function(){
12057                 var proxy = this.createProxy({
12058
12059                      style:{
12060                         visbility:"hidden",
12061                         position:"absolute",
12062                         "z-index":"35000", // yee haw
12063                         border:"0px solid " + color
12064                      }
12065                   });
12066                 var scale = Roo.isBorderBox ? 2 : 1;
12067                 proxy.animate({
12068                     top:{from:b.y, to:b.y - 20},
12069                     left:{from:b.x, to:b.x - 20},
12070                     borderWidth:{from:0, to:10},
12071                     opacity:{from:1, to:0},
12072                     height:{from:b.height, to:(b.height + (20*scale))},
12073                     width:{from:b.width, to:(b.width + (20*scale))}
12074                 }, duration, function(){
12075                     proxy.remove();
12076                 });
12077                 if(--count > 0){
12078                      animFn.defer((duration/2)*1000, this);
12079                 }else{
12080                     el.afterFx(o);
12081                 }
12082             };
12083             animFn.call(this);
12084         });
12085         return this;
12086     },
12087
12088    /**
12089     * Creates a pause before any subsequent queued effects begin.  If there are
12090     * no effects queued after the pause it will have no effect.
12091     * Usage:
12092 <pre><code>
12093 el.pause(1);
12094 </code></pre>
12095     * @param {Number} seconds The length of time to pause (in seconds)
12096     * @return {Roo.Element} The Element
12097     */
12098     pause : function(seconds){
12099         var el = this.getFxEl();
12100         var o = {};
12101
12102         el.queueFx(o, function(){
12103             setTimeout(function(){
12104                 el.afterFx(o);
12105             }, seconds * 1000);
12106         });
12107         return this;
12108     },
12109
12110    /**
12111     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
12112     * using the "endOpacity" config option.
12113     * Usage:
12114 <pre><code>
12115 // default: fade in from opacity 0 to 100%
12116 el.fadeIn();
12117
12118 // custom: fade in from opacity 0 to 75% over 2 seconds
12119 el.fadeIn({ endOpacity: .75, duration: 2});
12120
12121 // common config options shown with default values
12122 el.fadeIn({
12123     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12124     easing: 'easeOut',
12125     duration: .5
12126 });
12127 </code></pre>
12128     * @param {Object} options (optional) Object literal with any of the Fx config options
12129     * @return {Roo.Element} The Element
12130     */
12131     fadeIn : function(o){
12132         var el = this.getFxEl();
12133         o = o || {};
12134         el.queueFx(o, function(){
12135             this.setOpacity(0);
12136             this.fixDisplay();
12137             this.dom.style.visibility = 'visible';
12138             var to = o.endOpacity || 1;
12139             arguments.callee.anim = this.fxanim({opacity:{to:to}},
12140                 o, null, .5, "easeOut", function(){
12141                 if(to == 1){
12142                     this.clearOpacity();
12143                 }
12144                 el.afterFx(o);
12145             });
12146         });
12147         return this;
12148     },
12149
12150    /**
12151     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
12152     * using the "endOpacity" config option.
12153     * Usage:
12154 <pre><code>
12155 // default: fade out from the element's current opacity to 0
12156 el.fadeOut();
12157
12158 // custom: fade out from the element's current opacity to 25% over 2 seconds
12159 el.fadeOut({ endOpacity: .25, duration: 2});
12160
12161 // common config options shown with default values
12162 el.fadeOut({
12163     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12164     easing: 'easeOut',
12165     duration: .5
12166     remove: false,
12167     useDisplay: false
12168 });
12169 </code></pre>
12170     * @param {Object} options (optional) Object literal with any of the Fx config options
12171     * @return {Roo.Element} The Element
12172     */
12173     fadeOut : function(o){
12174         var el = this.getFxEl();
12175         o = o || {};
12176         el.queueFx(o, function(){
12177             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12178                 o, null, .5, "easeOut", function(){
12179                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12180                      this.dom.style.display = "none";
12181                 }else{
12182                      this.dom.style.visibility = "hidden";
12183                 }
12184                 this.clearOpacity();
12185                 el.afterFx(o);
12186             });
12187         });
12188         return this;
12189     },
12190
12191    /**
12192     * Animates the transition of an element's dimensions from a starting height/width
12193     * to an ending height/width.
12194     * Usage:
12195 <pre><code>
12196 // change height and width to 100x100 pixels
12197 el.scale(100, 100);
12198
12199 // common config options shown with default values.  The height and width will default to
12200 // the element's existing values if passed as null.
12201 el.scale(
12202     [element's width],
12203     [element's height], {
12204     easing: 'easeOut',
12205     duration: .35
12206 });
12207 </code></pre>
12208     * @param {Number} width  The new width (pass undefined to keep the original width)
12209     * @param {Number} height  The new height (pass undefined to keep the original height)
12210     * @param {Object} options (optional) Object literal with any of the Fx config options
12211     * @return {Roo.Element} The Element
12212     */
12213     scale : function(w, h, o){
12214         this.shift(Roo.apply({}, o, {
12215             width: w,
12216             height: h
12217         }));
12218         return this;
12219     },
12220
12221    /**
12222     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12223     * Any of these properties not specified in the config object will not be changed.  This effect 
12224     * requires that at least one new dimension, position or opacity setting must be passed in on
12225     * the config object in order for the function to have any effect.
12226     * Usage:
12227 <pre><code>
12228 // slide the element horizontally to x position 200 while changing the height and opacity
12229 el.shift({ x: 200, height: 50, opacity: .8 });
12230
12231 // common config options shown with default values.
12232 el.shift({
12233     width: [element's width],
12234     height: [element's height],
12235     x: [element's x position],
12236     y: [element's y position],
12237     opacity: [element's opacity],
12238     easing: 'easeOut',
12239     duration: .35
12240 });
12241 </code></pre>
12242     * @param {Object} options  Object literal with any of the Fx config options
12243     * @return {Roo.Element} The Element
12244     */
12245     shift : function(o){
12246         var el = this.getFxEl();
12247         o = o || {};
12248         el.queueFx(o, function(){
12249             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12250             if(w !== undefined){
12251                 a.width = {to: this.adjustWidth(w)};
12252             }
12253             if(h !== undefined){
12254                 a.height = {to: this.adjustHeight(h)};
12255             }
12256             if(x !== undefined || y !== undefined){
12257                 a.points = {to: [
12258                     x !== undefined ? x : this.getX(),
12259                     y !== undefined ? y : this.getY()
12260                 ]};
12261             }
12262             if(op !== undefined){
12263                 a.opacity = {to: op};
12264             }
12265             if(o.xy !== undefined){
12266                 a.points = {to: o.xy};
12267             }
12268             arguments.callee.anim = this.fxanim(a,
12269                 o, 'motion', .35, "easeOut", function(){
12270                 el.afterFx(o);
12271             });
12272         });
12273         return this;
12274     },
12275
12276         /**
12277          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12278          * ending point of the effect.
12279          * Usage:
12280          *<pre><code>
12281 // default: slide the element downward while fading out
12282 el.ghost();
12283
12284 // custom: slide the element out to the right with a 2-second duration
12285 el.ghost('r', { duration: 2 });
12286
12287 // common config options shown with default values
12288 el.ghost('b', {
12289     easing: 'easeOut',
12290     duration: .5
12291     remove: false,
12292     useDisplay: false
12293 });
12294 </code></pre>
12295          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12296          * @param {Object} options (optional) Object literal with any of the Fx config options
12297          * @return {Roo.Element} The Element
12298          */
12299     ghost : function(anchor, o){
12300         var el = this.getFxEl();
12301         o = o || {};
12302
12303         el.queueFx(o, function(){
12304             anchor = anchor || "b";
12305
12306             // restore values after effect
12307             var r = this.getFxRestore();
12308             var w = this.getWidth(),
12309                 h = this.getHeight();
12310
12311             var st = this.dom.style;
12312
12313             var after = function(){
12314                 if(o.useDisplay){
12315                     el.setDisplayed(false);
12316                 }else{
12317                     el.hide();
12318                 }
12319
12320                 el.clearOpacity();
12321                 el.setPositioning(r.pos);
12322                 st.width = r.width;
12323                 st.height = r.height;
12324
12325                 el.afterFx(o);
12326             };
12327
12328             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12329             switch(anchor.toLowerCase()){
12330                 case "t":
12331                     pt.by = [0, -h];
12332                 break;
12333                 case "l":
12334                     pt.by = [-w, 0];
12335                 break;
12336                 case "r":
12337                     pt.by = [w, 0];
12338                 break;
12339                 case "b":
12340                     pt.by = [0, h];
12341                 break;
12342                 case "tl":
12343                     pt.by = [-w, -h];
12344                 break;
12345                 case "bl":
12346                     pt.by = [-w, h];
12347                 break;
12348                 case "br":
12349                     pt.by = [w, h];
12350                 break;
12351                 case "tr":
12352                     pt.by = [w, -h];
12353                 break;
12354             }
12355
12356             arguments.callee.anim = this.fxanim(a,
12357                 o,
12358                 'motion',
12359                 .5,
12360                 "easeOut", after);
12361         });
12362         return this;
12363     },
12364
12365         /**
12366          * Ensures that all effects queued after syncFx is called on the element are
12367          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12368          * @return {Roo.Element} The Element
12369          */
12370     syncFx : function(){
12371         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12372             block : false,
12373             concurrent : true,
12374             stopFx : false
12375         });
12376         return this;
12377     },
12378
12379         /**
12380          * Ensures that all effects queued after sequenceFx is called on the element are
12381          * run in sequence.  This is the opposite of {@link #syncFx}.
12382          * @return {Roo.Element} The Element
12383          */
12384     sequenceFx : function(){
12385         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12386             block : false,
12387             concurrent : false,
12388             stopFx : false
12389         });
12390         return this;
12391     },
12392
12393         /* @private */
12394     nextFx : function(){
12395         var ef = this.fxQueue[0];
12396         if(ef){
12397             ef.call(this);
12398         }
12399     },
12400
12401         /**
12402          * Returns true if the element has any effects actively running or queued, else returns false.
12403          * @return {Boolean} True if element has active effects, else false
12404          */
12405     hasActiveFx : function(){
12406         return this.fxQueue && this.fxQueue[0];
12407     },
12408
12409         /**
12410          * Stops any running effects and clears the element's internal effects queue if it contains
12411          * any additional effects that haven't started yet.
12412          * @return {Roo.Element} The Element
12413          */
12414     stopFx : function(){
12415         if(this.hasActiveFx()){
12416             var cur = this.fxQueue[0];
12417             if(cur && cur.anim && cur.anim.isAnimated()){
12418                 this.fxQueue = [cur]; // clear out others
12419                 cur.anim.stop(true);
12420             }
12421         }
12422         return this;
12423     },
12424
12425         /* @private */
12426     beforeFx : function(o){
12427         if(this.hasActiveFx() && !o.concurrent){
12428            if(o.stopFx){
12429                this.stopFx();
12430                return true;
12431            }
12432            return false;
12433         }
12434         return true;
12435     },
12436
12437         /**
12438          * Returns true if the element is currently blocking so that no other effect can be queued
12439          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12440          * used to ensure that an effect initiated by a user action runs to completion prior to the
12441          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12442          * @return {Boolean} True if blocking, else false
12443          */
12444     hasFxBlock : function(){
12445         var q = this.fxQueue;
12446         return q && q[0] && q[0].block;
12447     },
12448
12449         /* @private */
12450     queueFx : function(o, fn){
12451         if(!this.fxQueue){
12452             this.fxQueue = [];
12453         }
12454         if(!this.hasFxBlock()){
12455             Roo.applyIf(o, this.fxDefaults);
12456             if(!o.concurrent){
12457                 var run = this.beforeFx(o);
12458                 fn.block = o.block;
12459                 this.fxQueue.push(fn);
12460                 if(run){
12461                     this.nextFx();
12462                 }
12463             }else{
12464                 fn.call(this);
12465             }
12466         }
12467         return this;
12468     },
12469
12470         /* @private */
12471     fxWrap : function(pos, o, vis){
12472         var wrap;
12473         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12474             var wrapXY;
12475             if(o.fixPosition){
12476                 wrapXY = this.getXY();
12477             }
12478             var div = document.createElement("div");
12479             div.style.visibility = vis;
12480             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12481             wrap.setPositioning(pos);
12482             if(wrap.getStyle("position") == "static"){
12483                 wrap.position("relative");
12484             }
12485             this.clearPositioning('auto');
12486             wrap.clip();
12487             wrap.dom.appendChild(this.dom);
12488             if(wrapXY){
12489                 wrap.setXY(wrapXY);
12490             }
12491         }
12492         return wrap;
12493     },
12494
12495         /* @private */
12496     fxUnwrap : function(wrap, pos, o){
12497         this.clearPositioning();
12498         this.setPositioning(pos);
12499         if(!o.wrap){
12500             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12501             wrap.remove();
12502         }
12503     },
12504
12505         /* @private */
12506     getFxRestore : function(){
12507         var st = this.dom.style;
12508         return {pos: this.getPositioning(), width: st.width, height : st.height};
12509     },
12510
12511         /* @private */
12512     afterFx : function(o){
12513         if(o.afterStyle){
12514             this.applyStyles(o.afterStyle);
12515         }
12516         if(o.afterCls){
12517             this.addClass(o.afterCls);
12518         }
12519         if(o.remove === true){
12520             this.remove();
12521         }
12522         Roo.callback(o.callback, o.scope, [this]);
12523         if(!o.concurrent){
12524             this.fxQueue.shift();
12525             this.nextFx();
12526         }
12527     },
12528
12529         /* @private */
12530     getFxEl : function(){ // support for composite element fx
12531         return Roo.get(this.dom);
12532     },
12533
12534         /* @private */
12535     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12536         animType = animType || 'run';
12537         opt = opt || {};
12538         var anim = Roo.lib.Anim[animType](
12539             this.dom, args,
12540             (opt.duration || defaultDur) || .35,
12541             (opt.easing || defaultEase) || 'easeOut',
12542             function(){
12543                 Roo.callback(cb, this);
12544             },
12545             this
12546         );
12547         opt.anim = anim;
12548         return anim;
12549     }
12550 };
12551
12552 // backwords compat
12553 Roo.Fx.resize = Roo.Fx.scale;
12554
12555 //When included, Roo.Fx is automatically applied to Element so that all basic
12556 //effects are available directly via the Element API
12557 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12558  * Based on:
12559  * Ext JS Library 1.1.1
12560  * Copyright(c) 2006-2007, Ext JS, LLC.
12561  *
12562  * Originally Released Under LGPL - original licence link has changed is not relivant.
12563  *
12564  * Fork - LGPL
12565  * <script type="text/javascript">
12566  */
12567
12568
12569 /**
12570  * @class Roo.CompositeElement
12571  * Standard composite class. Creates a Roo.Element for every element in the collection.
12572  * <br><br>
12573  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12574  * actions will be performed on all the elements in this collection.</b>
12575  * <br><br>
12576  * All methods return <i>this</i> and can be chained.
12577  <pre><code>
12578  var els = Roo.select("#some-el div.some-class", true);
12579  // or select directly from an existing element
12580  var el = Roo.get('some-el');
12581  el.select('div.some-class', true);
12582
12583  els.setWidth(100); // all elements become 100 width
12584  els.hide(true); // all elements fade out and hide
12585  // or
12586  els.setWidth(100).hide(true);
12587  </code></pre>
12588  */
12589 Roo.CompositeElement = function(els){
12590     this.elements = [];
12591     this.addElements(els);
12592 };
12593 Roo.CompositeElement.prototype = {
12594     isComposite: true,
12595     addElements : function(els){
12596         if(!els) {
12597             return this;
12598         }
12599         if(typeof els == "string"){
12600             els = Roo.Element.selectorFunction(els);
12601         }
12602         var yels = this.elements;
12603         var index = yels.length-1;
12604         for(var i = 0, len = els.length; i < len; i++) {
12605                 yels[++index] = Roo.get(els[i]);
12606         }
12607         return this;
12608     },
12609
12610     /**
12611     * Clears this composite and adds the elements returned by the passed selector.
12612     * @param {String/Array} els A string CSS selector, an array of elements or an element
12613     * @return {CompositeElement} this
12614     */
12615     fill : function(els){
12616         this.elements = [];
12617         this.add(els);
12618         return this;
12619     },
12620
12621     /**
12622     * Filters this composite to only elements that match the passed selector.
12623     * @param {String} selector A string CSS selector
12624     * @param {Boolean} inverse return inverse filter (not matches)
12625     * @return {CompositeElement} this
12626     */
12627     filter : function(selector, inverse){
12628         var els = [];
12629         inverse = inverse || false;
12630         this.each(function(el){
12631             var match = inverse ? !el.is(selector) : el.is(selector);
12632             if(match){
12633                 els[els.length] = el.dom;
12634             }
12635         });
12636         this.fill(els);
12637         return this;
12638     },
12639
12640     invoke : function(fn, args){
12641         var els = this.elements;
12642         for(var i = 0, len = els.length; i < len; i++) {
12643                 Roo.Element.prototype[fn].apply(els[i], args);
12644         }
12645         return this;
12646     },
12647     /**
12648     * Adds elements to this composite.
12649     * @param {String/Array} els A string CSS selector, an array of elements or an element
12650     * @return {CompositeElement} this
12651     */
12652     add : function(els){
12653         if(typeof els == "string"){
12654             this.addElements(Roo.Element.selectorFunction(els));
12655         }else if(els.length !== undefined){
12656             this.addElements(els);
12657         }else{
12658             this.addElements([els]);
12659         }
12660         return this;
12661     },
12662     /**
12663     * Calls the passed function passing (el, this, index) for each element in this composite.
12664     * @param {Function} fn The function to call
12665     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12666     * @return {CompositeElement} this
12667     */
12668     each : function(fn, scope){
12669         var els = this.elements;
12670         for(var i = 0, len = els.length; i < len; i++){
12671             if(fn.call(scope || els[i], els[i], this, i) === false) {
12672                 break;
12673             }
12674         }
12675         return this;
12676     },
12677
12678     /**
12679      * Returns the Element object at the specified index
12680      * @param {Number} index
12681      * @return {Roo.Element}
12682      */
12683     item : function(index){
12684         return this.elements[index] || null;
12685     },
12686
12687     /**
12688      * Returns the first Element
12689      * @return {Roo.Element}
12690      */
12691     first : function(){
12692         return this.item(0);
12693     },
12694
12695     /**
12696      * Returns the last Element
12697      * @return {Roo.Element}
12698      */
12699     last : function(){
12700         return this.item(this.elements.length-1);
12701     },
12702
12703     /**
12704      * Returns the number of elements in this composite
12705      * @return Number
12706      */
12707     getCount : function(){
12708         return this.elements.length;
12709     },
12710
12711     /**
12712      * Returns true if this composite contains the passed element
12713      * @return Boolean
12714      */
12715     contains : function(el){
12716         return this.indexOf(el) !== -1;
12717     },
12718
12719     /**
12720      * Returns true if this composite contains the passed element
12721      * @return Boolean
12722      */
12723     indexOf : function(el){
12724         return this.elements.indexOf(Roo.get(el));
12725     },
12726
12727
12728     /**
12729     * Removes the specified element(s).
12730     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12731     * or an array of any of those.
12732     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12733     * @return {CompositeElement} this
12734     */
12735     removeElement : function(el, removeDom){
12736         if(el instanceof Array){
12737             for(var i = 0, len = el.length; i < len; i++){
12738                 this.removeElement(el[i]);
12739             }
12740             return this;
12741         }
12742         var index = typeof el == 'number' ? el : this.indexOf(el);
12743         if(index !== -1){
12744             if(removeDom){
12745                 var d = this.elements[index];
12746                 if(d.dom){
12747                     d.remove();
12748                 }else{
12749                     d.parentNode.removeChild(d);
12750                 }
12751             }
12752             this.elements.splice(index, 1);
12753         }
12754         return this;
12755     },
12756
12757     /**
12758     * Replaces the specified element with the passed element.
12759     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12760     * to replace.
12761     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12762     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12763     * @return {CompositeElement} this
12764     */
12765     replaceElement : function(el, replacement, domReplace){
12766         var index = typeof el == 'number' ? el : this.indexOf(el);
12767         if(index !== -1){
12768             if(domReplace){
12769                 this.elements[index].replaceWith(replacement);
12770             }else{
12771                 this.elements.splice(index, 1, Roo.get(replacement))
12772             }
12773         }
12774         return this;
12775     },
12776
12777     /**
12778      * Removes all elements.
12779      */
12780     clear : function(){
12781         this.elements = [];
12782     }
12783 };
12784 (function(){
12785     Roo.CompositeElement.createCall = function(proto, fnName){
12786         if(!proto[fnName]){
12787             proto[fnName] = function(){
12788                 return this.invoke(fnName, arguments);
12789             };
12790         }
12791     };
12792     for(var fnName in Roo.Element.prototype){
12793         if(typeof Roo.Element.prototype[fnName] == "function"){
12794             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12795         }
12796     };
12797 })();
12798 /*
12799  * Based on:
12800  * Ext JS Library 1.1.1
12801  * Copyright(c) 2006-2007, Ext JS, LLC.
12802  *
12803  * Originally Released Under LGPL - original licence link has changed is not relivant.
12804  *
12805  * Fork - LGPL
12806  * <script type="text/javascript">
12807  */
12808
12809 /**
12810  * @class Roo.CompositeElementLite
12811  * @extends Roo.CompositeElement
12812  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12813  <pre><code>
12814  var els = Roo.select("#some-el div.some-class");
12815  // or select directly from an existing element
12816  var el = Roo.get('some-el');
12817  el.select('div.some-class');
12818
12819  els.setWidth(100); // all elements become 100 width
12820  els.hide(true); // all elements fade out and hide
12821  // or
12822  els.setWidth(100).hide(true);
12823  </code></pre><br><br>
12824  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12825  * actions will be performed on all the elements in this collection.</b>
12826  */
12827 Roo.CompositeElementLite = function(els){
12828     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12829     this.el = new Roo.Element.Flyweight();
12830 };
12831 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12832     addElements : function(els){
12833         if(els){
12834             if(els instanceof Array){
12835                 this.elements = this.elements.concat(els);
12836             }else{
12837                 var yels = this.elements;
12838                 var index = yels.length-1;
12839                 for(var i = 0, len = els.length; i < len; i++) {
12840                     yels[++index] = els[i];
12841                 }
12842             }
12843         }
12844         return this;
12845     },
12846     invoke : function(fn, args){
12847         var els = this.elements;
12848         var el = this.el;
12849         for(var i = 0, len = els.length; i < len; i++) {
12850             el.dom = els[i];
12851                 Roo.Element.prototype[fn].apply(el, args);
12852         }
12853         return this;
12854     },
12855     /**
12856      * Returns a flyweight Element of the dom element object at the specified index
12857      * @param {Number} index
12858      * @return {Roo.Element}
12859      */
12860     item : function(index){
12861         if(!this.elements[index]){
12862             return null;
12863         }
12864         this.el.dom = this.elements[index];
12865         return this.el;
12866     },
12867
12868     // fixes scope with flyweight
12869     addListener : function(eventName, handler, scope, opt){
12870         var els = this.elements;
12871         for(var i = 0, len = els.length; i < len; i++) {
12872             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12873         }
12874         return this;
12875     },
12876
12877     /**
12878     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12879     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12880     * a reference to the dom node, use el.dom.</b>
12881     * @param {Function} fn The function to call
12882     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12883     * @return {CompositeElement} this
12884     */
12885     each : function(fn, scope){
12886         var els = this.elements;
12887         var el = this.el;
12888         for(var i = 0, len = els.length; i < len; i++){
12889             el.dom = els[i];
12890                 if(fn.call(scope || el, el, this, i) === false){
12891                 break;
12892             }
12893         }
12894         return this;
12895     },
12896
12897     indexOf : function(el){
12898         return this.elements.indexOf(Roo.getDom(el));
12899     },
12900
12901     replaceElement : function(el, replacement, domReplace){
12902         var index = typeof el == 'number' ? el : this.indexOf(el);
12903         if(index !== -1){
12904             replacement = Roo.getDom(replacement);
12905             if(domReplace){
12906                 var d = this.elements[index];
12907                 d.parentNode.insertBefore(replacement, d);
12908                 d.parentNode.removeChild(d);
12909             }
12910             this.elements.splice(index, 1, replacement);
12911         }
12912         return this;
12913     }
12914 });
12915 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12916
12917 /*
12918  * Based on:
12919  * Ext JS Library 1.1.1
12920  * Copyright(c) 2006-2007, Ext JS, LLC.
12921  *
12922  * Originally Released Under LGPL - original licence link has changed is not relivant.
12923  *
12924  * Fork - LGPL
12925  * <script type="text/javascript">
12926  */
12927
12928  
12929
12930 /**
12931  * @class Roo.data.Connection
12932  * @extends Roo.util.Observable
12933  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12934  * either to a configured URL, or to a URL specified at request time. 
12935  * 
12936  * Requests made by this class are asynchronous, and will return immediately. No data from
12937  * the server will be available to the statement immediately following the {@link #request} call.
12938  * To process returned data, use a callback in the request options object, or an event listener.
12939  * 
12940  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12941  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12942  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12943  * property and, if present, the IFRAME's XML document as the responseXML property.
12944  * 
12945  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12946  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12947  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12948  * standard DOM methods.
12949  * @constructor
12950  * @param {Object} config a configuration object.
12951  */
12952 Roo.data.Connection = function(config){
12953     Roo.apply(this, config);
12954     this.addEvents({
12955         /**
12956          * @event beforerequest
12957          * Fires before a network request is made to retrieve a data object.
12958          * @param {Connection} conn This Connection object.
12959          * @param {Object} options The options config object passed to the {@link #request} method.
12960          */
12961         "beforerequest" : true,
12962         /**
12963          * @event requestcomplete
12964          * Fires if the request was successfully completed.
12965          * @param {Connection} conn This Connection object.
12966          * @param {Object} response The XHR object containing the response data.
12967          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12968          * @param {Object} options The options config object passed to the {@link #request} method.
12969          */
12970         "requestcomplete" : true,
12971         /**
12972          * @event requestexception
12973          * Fires if an error HTTP status was returned from the server.
12974          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12975          * @param {Connection} conn This Connection object.
12976          * @param {Object} response The XHR object containing the response data.
12977          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12978          * @param {Object} options The options config object passed to the {@link #request} method.
12979          */
12980         "requestexception" : true
12981     });
12982     Roo.data.Connection.superclass.constructor.call(this);
12983 };
12984
12985 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12986     /**
12987      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12988      */
12989     /**
12990      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12991      * extra parameters to each request made by this object. (defaults to undefined)
12992      */
12993     /**
12994      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12995      *  to each request made by this object. (defaults to undefined)
12996      */
12997     /**
12998      * @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)
12999      */
13000     /**
13001      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13002      */
13003     timeout : 30000,
13004     /**
13005      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13006      * @type Boolean
13007      */
13008     autoAbort:false,
13009
13010     /**
13011      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13012      * @type Boolean
13013      */
13014     disableCaching: true,
13015
13016     /**
13017      * Sends an HTTP request to a remote server.
13018      * @param {Object} options An object which may contain the following properties:<ul>
13019      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
13020      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
13021      * request, a url encoded string or a function to call to get either.</li>
13022      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
13023      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
13024      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13025      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13026      * <li>options {Object} The parameter to the request call.</li>
13027      * <li>success {Boolean} True if the request succeeded.</li>
13028      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13029      * </ul></li>
13030      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13031      * The callback is passed the following parameters:<ul>
13032      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13033      * <li>options {Object} The parameter to the request call.</li>
13034      * </ul></li>
13035      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13036      * The callback is passed the following parameters:<ul>
13037      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13038      * <li>options {Object} The parameter to the request call.</li>
13039      * </ul></li>
13040      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13041      * for the callback function. Defaults to the browser window.</li>
13042      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13043      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13044      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13045      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13046      * params for the post data. Any params will be appended to the URL.</li>
13047      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13048      * </ul>
13049      * @return {Number} transactionId
13050      */
13051     request : function(o){
13052         if(this.fireEvent("beforerequest", this, o) !== false){
13053             var p = o.params;
13054
13055             if(typeof p == "function"){
13056                 p = p.call(o.scope||window, o);
13057             }
13058             if(typeof p == "object"){
13059                 p = Roo.urlEncode(o.params);
13060             }
13061             if(this.extraParams){
13062                 var extras = Roo.urlEncode(this.extraParams);
13063                 p = p ? (p + '&' + extras) : extras;
13064             }
13065
13066             var url = o.url || this.url;
13067             if(typeof url == 'function'){
13068                 url = url.call(o.scope||window, o);
13069             }
13070
13071             if(o.form){
13072                 var form = Roo.getDom(o.form);
13073                 url = url || form.action;
13074
13075                 var enctype = form.getAttribute("enctype");
13076                 
13077                 if (o.formData) {
13078                     return this.doFormDataUpload(o, url);
13079                 }
13080                 
13081                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13082                     return this.doFormUpload(o, p, url);
13083                 }
13084                 var f = Roo.lib.Ajax.serializeForm(form);
13085                 p = p ? (p + '&' + f) : f;
13086             }
13087             
13088             if (!o.form && o.formData) {
13089                 o.formData = o.formData === true ? new FormData() : o.formData;
13090                 for (var k in o.params) {
13091                     o.formData.append(k,o.params[k]);
13092                 }
13093                     
13094                 return this.doFormDataUpload(o, url);
13095             }
13096             
13097
13098             var hs = o.headers;
13099             if(this.defaultHeaders){
13100                 hs = Roo.apply(hs || {}, this.defaultHeaders);
13101                 if(!o.headers){
13102                     o.headers = hs;
13103                 }
13104             }
13105
13106             var cb = {
13107                 success: this.handleResponse,
13108                 failure: this.handleFailure,
13109                 scope: this,
13110                 argument: {options: o},
13111                 timeout : o.timeout || this.timeout
13112             };
13113
13114             var method = o.method||this.method||(p ? "POST" : "GET");
13115
13116             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13117                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13118             }
13119
13120             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13121                 if(o.autoAbort){
13122                     this.abort();
13123                 }
13124             }else if(this.autoAbort !== false){
13125                 this.abort();
13126             }
13127
13128             if((method == 'GET' && p) || o.xmlData){
13129                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13130                 p = '';
13131             }
13132             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13133             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13134             Roo.lib.Ajax.useDefaultHeader == true;
13135             return this.transId;
13136         }else{
13137             Roo.callback(o.callback, o.scope, [o, null, null]);
13138             return null;
13139         }
13140     },
13141
13142     /**
13143      * Determine whether this object has a request outstanding.
13144      * @param {Number} transactionId (Optional) defaults to the last transaction
13145      * @return {Boolean} True if there is an outstanding request.
13146      */
13147     isLoading : function(transId){
13148         if(transId){
13149             return Roo.lib.Ajax.isCallInProgress(transId);
13150         }else{
13151             return this.transId ? true : false;
13152         }
13153     },
13154
13155     /**
13156      * Aborts any outstanding request.
13157      * @param {Number} transactionId (Optional) defaults to the last transaction
13158      */
13159     abort : function(transId){
13160         if(transId || this.isLoading()){
13161             Roo.lib.Ajax.abort(transId || this.transId);
13162         }
13163     },
13164
13165     // private
13166     handleResponse : function(response){
13167         this.transId = false;
13168         var options = response.argument.options;
13169         response.argument = options ? options.argument : null;
13170         this.fireEvent("requestcomplete", this, response, options);
13171         Roo.callback(options.success, options.scope, [response, options]);
13172         Roo.callback(options.callback, options.scope, [options, true, response]);
13173     },
13174
13175     // private
13176     handleFailure : function(response, e){
13177         this.transId = false;
13178         var options = response.argument.options;
13179         response.argument = options ? options.argument : null;
13180         this.fireEvent("requestexception", this, response, options, e);
13181         Roo.callback(options.failure, options.scope, [response, options]);
13182         Roo.callback(options.callback, options.scope, [options, false, response]);
13183     },
13184
13185     // private
13186     doFormUpload : function(o, ps, url){
13187         var id = Roo.id();
13188         var frame = document.createElement('iframe');
13189         frame.id = id;
13190         frame.name = id;
13191         frame.className = 'x-hidden';
13192         if(Roo.isIE){
13193             frame.src = Roo.SSL_SECURE_URL;
13194         }
13195         document.body.appendChild(frame);
13196
13197         if(Roo.isIE){
13198            document.frames[id].name = id;
13199         }
13200
13201         var form = Roo.getDom(o.form);
13202         form.target = id;
13203         form.method = 'POST';
13204         form.enctype = form.encoding = 'multipart/form-data';
13205         if(url){
13206             form.action = url;
13207         }
13208
13209         var hiddens, hd;
13210         if(ps){ // add dynamic params
13211             hiddens = [];
13212             ps = Roo.urlDecode(ps, false);
13213             for(var k in ps){
13214                 if(ps.hasOwnProperty(k)){
13215                     hd = document.createElement('input');
13216                     hd.type = 'hidden';
13217                     hd.name = k;
13218                     hd.value = ps[k];
13219                     form.appendChild(hd);
13220                     hiddens.push(hd);
13221                 }
13222             }
13223         }
13224
13225         function cb(){
13226             var r = {  // bogus response object
13227                 responseText : '',
13228                 responseXML : null
13229             };
13230
13231             r.argument = o ? o.argument : null;
13232
13233             try { //
13234                 var doc;
13235                 if(Roo.isIE){
13236                     doc = frame.contentWindow.document;
13237                 }else {
13238                     doc = (frame.contentDocument || window.frames[id].document);
13239                 }
13240                 if(doc && doc.body){
13241                     r.responseText = doc.body.innerHTML;
13242                 }
13243                 if(doc && doc.XMLDocument){
13244                     r.responseXML = doc.XMLDocument;
13245                 }else {
13246                     r.responseXML = doc;
13247                 }
13248             }
13249             catch(e) {
13250                 // ignore
13251             }
13252
13253             Roo.EventManager.removeListener(frame, 'load', cb, this);
13254
13255             this.fireEvent("requestcomplete", this, r, o);
13256             Roo.callback(o.success, o.scope, [r, o]);
13257             Roo.callback(o.callback, o.scope, [o, true, r]);
13258
13259             setTimeout(function(){document.body.removeChild(frame);}, 100);
13260         }
13261
13262         Roo.EventManager.on(frame, 'load', cb, this);
13263         form.submit();
13264
13265         if(hiddens){ // remove dynamic params
13266             for(var i = 0, len = hiddens.length; i < len; i++){
13267                 form.removeChild(hiddens[i]);
13268             }
13269         }
13270     },
13271     // this is a 'formdata version???'
13272     
13273     
13274     doFormDataUpload : function(o,  url)
13275     {
13276         var formData;
13277         if (o.form) {
13278             var form =  Roo.getDom(o.form);
13279             form.enctype = form.encoding = 'multipart/form-data';
13280             formData = o.formData === true ? new FormData(form) : o.formData;
13281         } else {
13282             formData = o.formData === true ? new FormData() : o.formData;
13283         }
13284         
13285       
13286         var cb = {
13287             success: this.handleResponse,
13288             failure: this.handleFailure,
13289             scope: this,
13290             argument: {options: o},
13291             timeout : o.timeout || this.timeout
13292         };
13293  
13294         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13295             if(o.autoAbort){
13296                 this.abort();
13297             }
13298         }else if(this.autoAbort !== false){
13299             this.abort();
13300         }
13301
13302         //Roo.lib.Ajax.defaultPostHeader = null;
13303         Roo.lib.Ajax.useDefaultHeader = false;
13304         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13305         Roo.lib.Ajax.useDefaultHeader = true;
13306  
13307          
13308     }
13309     
13310 });
13311 /*
13312  * Based on:
13313  * Ext JS Library 1.1.1
13314  * Copyright(c) 2006-2007, Ext JS, LLC.
13315  *
13316  * Originally Released Under LGPL - original licence link has changed is not relivant.
13317  *
13318  * Fork - LGPL
13319  * <script type="text/javascript">
13320  */
13321  
13322 /**
13323  * Global Ajax request class.
13324  * 
13325  * @class Roo.Ajax
13326  * @extends Roo.data.Connection
13327  * @static
13328  * 
13329  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13330  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13331  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13332  * @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)
13333  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13334  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13335  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13336  */
13337 Roo.Ajax = new Roo.data.Connection({
13338     // fix up the docs
13339     /**
13340      * @scope Roo.Ajax
13341      * @type {Boolear} 
13342      */
13343     autoAbort : false,
13344
13345     /**
13346      * Serialize the passed form into a url encoded string
13347      * @scope Roo.Ajax
13348      * @param {String/HTMLElement} form
13349      * @return {String}
13350      */
13351     serializeForm : function(form){
13352         return Roo.lib.Ajax.serializeForm(form);
13353     }
13354 });/*
13355  * Based on:
13356  * Ext JS Library 1.1.1
13357  * Copyright(c) 2006-2007, Ext JS, LLC.
13358  *
13359  * Originally Released Under LGPL - original licence link has changed is not relivant.
13360  *
13361  * Fork - LGPL
13362  * <script type="text/javascript">
13363  */
13364
13365  
13366 /**
13367  * @class Roo.UpdateManager
13368  * @extends Roo.util.Observable
13369  * Provides AJAX-style update for Element object.<br><br>
13370  * Usage:<br>
13371  * <pre><code>
13372  * // Get it from a Roo.Element object
13373  * var el = Roo.get("foo");
13374  * var mgr = el.getUpdateManager();
13375  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13376  * ...
13377  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13378  * <br>
13379  * // or directly (returns the same UpdateManager instance)
13380  * var mgr = new Roo.UpdateManager("myElementId");
13381  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13382  * mgr.on("update", myFcnNeedsToKnow);
13383  * <br>
13384    // short handed call directly from the element object
13385    Roo.get("foo").load({
13386         url: "bar.php",
13387         scripts:true,
13388         params: "for=bar",
13389         text: "Loading Foo..."
13390    });
13391  * </code></pre>
13392  * @constructor
13393  * Create new UpdateManager directly.
13394  * @param {String/HTMLElement/Roo.Element} el The element to update
13395  * @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).
13396  */
13397 Roo.UpdateManager = function(el, forceNew){
13398     el = Roo.get(el);
13399     if(!forceNew && el.updateManager){
13400         return el.updateManager;
13401     }
13402     /**
13403      * The Element object
13404      * @type Roo.Element
13405      */
13406     this.el = el;
13407     /**
13408      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13409      * @type String
13410      */
13411     this.defaultUrl = null;
13412
13413     this.addEvents({
13414         /**
13415          * @event beforeupdate
13416          * Fired before an update is made, return false from your handler and the update is cancelled.
13417          * @param {Roo.Element} el
13418          * @param {String/Object/Function} url
13419          * @param {String/Object} params
13420          */
13421         "beforeupdate": true,
13422         /**
13423          * @event update
13424          * Fired after successful update is made.
13425          * @param {Roo.Element} el
13426          * @param {Object} oResponseObject The response Object
13427          */
13428         "update": true,
13429         /**
13430          * @event failure
13431          * Fired on update failure.
13432          * @param {Roo.Element} el
13433          * @param {Object} oResponseObject The response Object
13434          */
13435         "failure": true
13436     });
13437     var d = Roo.UpdateManager.defaults;
13438     /**
13439      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13440      * @type String
13441      */
13442     this.sslBlankUrl = d.sslBlankUrl;
13443     /**
13444      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13445      * @type Boolean
13446      */
13447     this.disableCaching = d.disableCaching;
13448     /**
13449      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13450      * @type String
13451      */
13452     this.indicatorText = d.indicatorText;
13453     /**
13454      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13455      * @type String
13456      */
13457     this.showLoadIndicator = d.showLoadIndicator;
13458     /**
13459      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13460      * @type Number
13461      */
13462     this.timeout = d.timeout;
13463
13464     /**
13465      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13466      * @type Boolean
13467      */
13468     this.loadScripts = d.loadScripts;
13469
13470     /**
13471      * Transaction object of current executing transaction
13472      */
13473     this.transaction = null;
13474
13475     /**
13476      * @private
13477      */
13478     this.autoRefreshProcId = null;
13479     /**
13480      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13481      * @type Function
13482      */
13483     this.refreshDelegate = this.refresh.createDelegate(this);
13484     /**
13485      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13486      * @type Function
13487      */
13488     this.updateDelegate = this.update.createDelegate(this);
13489     /**
13490      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13491      * @type Function
13492      */
13493     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13494     /**
13495      * @private
13496      */
13497     this.successDelegate = this.processSuccess.createDelegate(this);
13498     /**
13499      * @private
13500      */
13501     this.failureDelegate = this.processFailure.createDelegate(this);
13502
13503     if(!this.renderer){
13504      /**
13505       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13506       */
13507     this.renderer = new Roo.UpdateManager.BasicRenderer();
13508     }
13509     
13510     Roo.UpdateManager.superclass.constructor.call(this);
13511 };
13512
13513 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13514     /**
13515      * Get the Element this UpdateManager is bound to
13516      * @return {Roo.Element} The element
13517      */
13518     getEl : function(){
13519         return this.el;
13520     },
13521     /**
13522      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13523      * @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:
13524 <pre><code>
13525 um.update({<br/>
13526     url: "your-url.php",<br/>
13527     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13528     callback: yourFunction,<br/>
13529     scope: yourObject, //(optional scope)  <br/>
13530     discardUrl: false, <br/>
13531     nocache: false,<br/>
13532     text: "Loading...",<br/>
13533     timeout: 30,<br/>
13534     scripts: false<br/>
13535 });
13536 </code></pre>
13537      * The only required property is url. The optional properties nocache, text and scripts
13538      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13539      * @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}
13540      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13541      * @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.
13542      */
13543     update : function(url, params, callback, discardUrl){
13544         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13545             var method = this.method,
13546                 cfg;
13547             if(typeof url == "object"){ // must be config object
13548                 cfg = url;
13549                 url = cfg.url;
13550                 params = params || cfg.params;
13551                 callback = callback || cfg.callback;
13552                 discardUrl = discardUrl || cfg.discardUrl;
13553                 if(callback && cfg.scope){
13554                     callback = callback.createDelegate(cfg.scope);
13555                 }
13556                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13557                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13558                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13559                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13560                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13561             }
13562             this.showLoading();
13563             if(!discardUrl){
13564                 this.defaultUrl = url;
13565             }
13566             if(typeof url == "function"){
13567                 url = url.call(this);
13568             }
13569
13570             method = method || (params ? "POST" : "GET");
13571             if(method == "GET"){
13572                 url = this.prepareUrl(url);
13573             }
13574
13575             var o = Roo.apply(cfg ||{}, {
13576                 url : url,
13577                 params: params,
13578                 success: this.successDelegate,
13579                 failure: this.failureDelegate,
13580                 callback: undefined,
13581                 timeout: (this.timeout*1000),
13582                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13583             });
13584             Roo.log("updated manager called with timeout of " + o.timeout);
13585             this.transaction = Roo.Ajax.request(o);
13586         }
13587     },
13588
13589     /**
13590      * 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.
13591      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13592      * @param {String/HTMLElement} form The form Id or form element
13593      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13594      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13595      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13596      */
13597     formUpdate : function(form, url, reset, callback){
13598         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13599             if(typeof url == "function"){
13600                 url = url.call(this);
13601             }
13602             form = Roo.getDom(form);
13603             this.transaction = Roo.Ajax.request({
13604                 form: form,
13605                 url:url,
13606                 success: this.successDelegate,
13607                 failure: this.failureDelegate,
13608                 timeout: (this.timeout*1000),
13609                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13610             });
13611             this.showLoading.defer(1, this);
13612         }
13613     },
13614
13615     /**
13616      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13617      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13618      */
13619     refresh : function(callback){
13620         if(this.defaultUrl == null){
13621             return;
13622         }
13623         this.update(this.defaultUrl, null, callback, true);
13624     },
13625
13626     /**
13627      * Set this element to auto refresh.
13628      * @param {Number} interval How often to update (in seconds).
13629      * @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)
13630      * @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}
13631      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13632      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13633      */
13634     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13635         if(refreshNow){
13636             this.update(url || this.defaultUrl, params, callback, true);
13637         }
13638         if(this.autoRefreshProcId){
13639             clearInterval(this.autoRefreshProcId);
13640         }
13641         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13642     },
13643
13644     /**
13645      * Stop auto refresh on this element.
13646      */
13647      stopAutoRefresh : function(){
13648         if(this.autoRefreshProcId){
13649             clearInterval(this.autoRefreshProcId);
13650             delete this.autoRefreshProcId;
13651         }
13652     },
13653
13654     isAutoRefreshing : function(){
13655        return this.autoRefreshProcId ? true : false;
13656     },
13657     /**
13658      * Called to update the element to "Loading" state. Override to perform custom action.
13659      */
13660     showLoading : function(){
13661         if(this.showLoadIndicator){
13662             this.el.update(this.indicatorText);
13663         }
13664     },
13665
13666     /**
13667      * Adds unique parameter to query string if disableCaching = true
13668      * @private
13669      */
13670     prepareUrl : function(url){
13671         if(this.disableCaching){
13672             var append = "_dc=" + (new Date().getTime());
13673             if(url.indexOf("?") !== -1){
13674                 url += "&" + append;
13675             }else{
13676                 url += "?" + append;
13677             }
13678         }
13679         return url;
13680     },
13681
13682     /**
13683      * @private
13684      */
13685     processSuccess : function(response){
13686         this.transaction = null;
13687         if(response.argument.form && response.argument.reset){
13688             try{ // put in try/catch since some older FF releases had problems with this
13689                 response.argument.form.reset();
13690             }catch(e){}
13691         }
13692         if(this.loadScripts){
13693             this.renderer.render(this.el, response, this,
13694                 this.updateComplete.createDelegate(this, [response]));
13695         }else{
13696             this.renderer.render(this.el, response, this);
13697             this.updateComplete(response);
13698         }
13699     },
13700
13701     updateComplete : function(response){
13702         this.fireEvent("update", this.el, response);
13703         if(typeof response.argument.callback == "function"){
13704             response.argument.callback(this.el, true, response);
13705         }
13706     },
13707
13708     /**
13709      * @private
13710      */
13711     processFailure : function(response){
13712         this.transaction = null;
13713         this.fireEvent("failure", this.el, response);
13714         if(typeof response.argument.callback == "function"){
13715             response.argument.callback(this.el, false, response);
13716         }
13717     },
13718
13719     /**
13720      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13721      * @param {Object} renderer The object implementing the render() method
13722      */
13723     setRenderer : function(renderer){
13724         this.renderer = renderer;
13725     },
13726
13727     getRenderer : function(){
13728        return this.renderer;
13729     },
13730
13731     /**
13732      * Set the defaultUrl used for updates
13733      * @param {String/Function} defaultUrl The url or a function to call to get the url
13734      */
13735     setDefaultUrl : function(defaultUrl){
13736         this.defaultUrl = defaultUrl;
13737     },
13738
13739     /**
13740      * Aborts the executing transaction
13741      */
13742     abort : function(){
13743         if(this.transaction){
13744             Roo.Ajax.abort(this.transaction);
13745         }
13746     },
13747
13748     /**
13749      * Returns true if an update is in progress
13750      * @return {Boolean}
13751      */
13752     isUpdating : function(){
13753         if(this.transaction){
13754             return Roo.Ajax.isLoading(this.transaction);
13755         }
13756         return false;
13757     }
13758 });
13759
13760 /**
13761  * @class Roo.UpdateManager.defaults
13762  * @static (not really - but it helps the doc tool)
13763  * The defaults collection enables customizing the default properties of UpdateManager
13764  */
13765    Roo.UpdateManager.defaults = {
13766        /**
13767          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13768          * @type Number
13769          */
13770          timeout : 30,
13771
13772          /**
13773          * True to process scripts by default (Defaults to false).
13774          * @type Boolean
13775          */
13776         loadScripts : false,
13777
13778         /**
13779         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13780         * @type String
13781         */
13782         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13783         /**
13784          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13785          * @type Boolean
13786          */
13787         disableCaching : false,
13788         /**
13789          * Whether to show indicatorText when loading (Defaults to true).
13790          * @type Boolean
13791          */
13792         showLoadIndicator : true,
13793         /**
13794          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13795          * @type String
13796          */
13797         indicatorText : '<div class="loading-indicator">Loading...</div>'
13798    };
13799
13800 /**
13801  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13802  *Usage:
13803  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13804  * @param {String/HTMLElement/Roo.Element} el The element to update
13805  * @param {String} url The url
13806  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13807  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13808  * @static
13809  * @deprecated
13810  * @member Roo.UpdateManager
13811  */
13812 Roo.UpdateManager.updateElement = function(el, url, params, options){
13813     var um = Roo.get(el, true).getUpdateManager();
13814     Roo.apply(um, options);
13815     um.update(url, params, options ? options.callback : null);
13816 };
13817 // alias for backwards compat
13818 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13819 /**
13820  * @class Roo.UpdateManager.BasicRenderer
13821  * Default Content renderer. Updates the elements innerHTML with the responseText.
13822  */
13823 Roo.UpdateManager.BasicRenderer = function(){};
13824
13825 Roo.UpdateManager.BasicRenderer.prototype = {
13826     /**
13827      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13828      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13829      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13830      * @param {Roo.Element} el The element being rendered
13831      * @param {Object} response The YUI Connect response object
13832      * @param {UpdateManager} updateManager The calling update manager
13833      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13834      */
13835      render : function(el, response, updateManager, callback){
13836         el.update(response.responseText, updateManager.loadScripts, callback);
13837     }
13838 };
13839 /*
13840  * Based on:
13841  * Roo JS
13842  * (c)) Alan Knowles
13843  * Licence : LGPL
13844  */
13845
13846
13847 /**
13848  * @class Roo.DomTemplate
13849  * @extends Roo.Template
13850  * An effort at a dom based template engine..
13851  *
13852  * Similar to XTemplate, except it uses dom parsing to create the template..
13853  *
13854  * Supported features:
13855  *
13856  *  Tags:
13857
13858 <pre><code>
13859       {a_variable} - output encoded.
13860       {a_variable.format:("Y-m-d")} - call a method on the variable
13861       {a_variable:raw} - unencoded output
13862       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13863       {a_variable:this.method_on_template(...)} - call a method on the template object.
13864  
13865 </code></pre>
13866  *  The tpl tag:
13867 <pre><code>
13868         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13869         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13870         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13871         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13872   
13873 </code></pre>
13874  *      
13875  */
13876 Roo.DomTemplate = function()
13877 {
13878      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13879      if (this.html) {
13880         this.compile();
13881      }
13882 };
13883
13884
13885 Roo.extend(Roo.DomTemplate, Roo.Template, {
13886     /**
13887      * id counter for sub templates.
13888      */
13889     id : 0,
13890     /**
13891      * flag to indicate if dom parser is inside a pre,
13892      * it will strip whitespace if not.
13893      */
13894     inPre : false,
13895     
13896     /**
13897      * The various sub templates
13898      */
13899     tpls : false,
13900     
13901     
13902     
13903     /**
13904      *
13905      * basic tag replacing syntax
13906      * WORD:WORD()
13907      *
13908      * // you can fake an object call by doing this
13909      *  x.t:(test,tesT) 
13910      * 
13911      */
13912     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13913     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13914     
13915     iterChild : function (node, method) {
13916         
13917         var oldPre = this.inPre;
13918         if (node.tagName == 'PRE') {
13919             this.inPre = true;
13920         }
13921         for( var i = 0; i < node.childNodes.length; i++) {
13922             method.call(this, node.childNodes[i]);
13923         }
13924         this.inPre = oldPre;
13925     },
13926     
13927     
13928     
13929     /**
13930      * compile the template
13931      *
13932      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13933      *
13934      */
13935     compile: function()
13936     {
13937         var s = this.html;
13938         
13939         // covert the html into DOM...
13940         var doc = false;
13941         var div =false;
13942         try {
13943             doc = document.implementation.createHTMLDocument("");
13944             doc.documentElement.innerHTML =   this.html  ;
13945             div = doc.documentElement;
13946         } catch (e) {
13947             // old IE... - nasty -- it causes all sorts of issues.. with
13948             // images getting pulled from server..
13949             div = document.createElement('div');
13950             div.innerHTML = this.html;
13951         }
13952         //doc.documentElement.innerHTML = htmlBody
13953          
13954         
13955         
13956         this.tpls = [];
13957         var _t = this;
13958         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13959         
13960         var tpls = this.tpls;
13961         
13962         // create a top level template from the snippet..
13963         
13964         //Roo.log(div.innerHTML);
13965         
13966         var tpl = {
13967             uid : 'master',
13968             id : this.id++,
13969             attr : false,
13970             value : false,
13971             body : div.innerHTML,
13972             
13973             forCall : false,
13974             execCall : false,
13975             dom : div,
13976             isTop : true
13977             
13978         };
13979         tpls.unshift(tpl);
13980         
13981         
13982         // compile them...
13983         this.tpls = [];
13984         Roo.each(tpls, function(tp){
13985             this.compileTpl(tp);
13986             this.tpls[tp.id] = tp;
13987         }, this);
13988         
13989         this.master = tpls[0];
13990         return this;
13991         
13992         
13993     },
13994     
13995     compileNode : function(node, istop) {
13996         // test for
13997         //Roo.log(node);
13998         
13999         
14000         // skip anything not a tag..
14001         if (node.nodeType != 1) {
14002             if (node.nodeType == 3 && !this.inPre) {
14003                 // reduce white space..
14004                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
14005                 
14006             }
14007             return;
14008         }
14009         
14010         var tpl = {
14011             uid : false,
14012             id : false,
14013             attr : false,
14014             value : false,
14015             body : '',
14016             
14017             forCall : false,
14018             execCall : false,
14019             dom : false,
14020             isTop : istop
14021             
14022             
14023         };
14024         
14025         
14026         switch(true) {
14027             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14028             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14029             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14030             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14031             // no default..
14032         }
14033         
14034         
14035         if (!tpl.attr) {
14036             // just itterate children..
14037             this.iterChild(node,this.compileNode);
14038             return;
14039         }
14040         tpl.uid = this.id++;
14041         tpl.value = node.getAttribute('roo-' +  tpl.attr);
14042         node.removeAttribute('roo-'+ tpl.attr);
14043         if (tpl.attr != 'name') {
14044             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14045             node.parentNode.replaceChild(placeholder,  node);
14046         } else {
14047             
14048             var placeholder =  document.createElement('span');
14049             placeholder.className = 'roo-tpl-' + tpl.value;
14050             node.parentNode.replaceChild(placeholder,  node);
14051         }
14052         
14053         // parent now sees '{domtplXXXX}
14054         this.iterChild(node,this.compileNode);
14055         
14056         // we should now have node body...
14057         var div = document.createElement('div');
14058         div.appendChild(node);
14059         tpl.dom = node;
14060         // this has the unfortunate side effect of converting tagged attributes
14061         // eg. href="{...}" into %7C...%7D
14062         // this has been fixed by searching for those combo's although it's a bit hacky..
14063         
14064         
14065         tpl.body = div.innerHTML;
14066         
14067         
14068          
14069         tpl.id = tpl.uid;
14070         switch(tpl.attr) {
14071             case 'for' :
14072                 switch (tpl.value) {
14073                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14074                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14075                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14076                 }
14077                 break;
14078             
14079             case 'exec':
14080                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14081                 break;
14082             
14083             case 'if':     
14084                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14085                 break;
14086             
14087             case 'name':
14088                 tpl.id  = tpl.value; // replace non characters???
14089                 break;
14090             
14091         }
14092         
14093         
14094         this.tpls.push(tpl);
14095         
14096         
14097         
14098     },
14099     
14100     
14101     
14102     
14103     /**
14104      * Compile a segment of the template into a 'sub-template'
14105      *
14106      * 
14107      * 
14108      *
14109      */
14110     compileTpl : function(tpl)
14111     {
14112         var fm = Roo.util.Format;
14113         var useF = this.disableFormats !== true;
14114         
14115         var sep = Roo.isGecko ? "+\n" : ",\n";
14116         
14117         var undef = function(str) {
14118             Roo.debug && Roo.log("Property not found :"  + str);
14119             return '';
14120         };
14121           
14122         //Roo.log(tpl.body);
14123         
14124         
14125         
14126         var fn = function(m, lbrace, name, format, args)
14127         {
14128             //Roo.log("ARGS");
14129             //Roo.log(arguments);
14130             args = args ? args.replace(/\\'/g,"'") : args;
14131             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14132             if (typeof(format) == 'undefined') {
14133                 format =  'htmlEncode'; 
14134             }
14135             if (format == 'raw' ) {
14136                 format = false;
14137             }
14138             
14139             if(name.substr(0, 6) == 'domtpl'){
14140                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14141             }
14142             
14143             // build an array of options to determine if value is undefined..
14144             
14145             // basically get 'xxxx.yyyy' then do
14146             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14147             //    (function () { Roo.log("Property not found"); return ''; })() :
14148             //    ......
14149             
14150             var udef_ar = [];
14151             var lookfor = '';
14152             Roo.each(name.split('.'), function(st) {
14153                 lookfor += (lookfor.length ? '.': '') + st;
14154                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
14155             });
14156             
14157             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14158             
14159             
14160             if(format && useF){
14161                 
14162                 args = args ? ',' + args : "";
14163                  
14164                 if(format.substr(0, 5) != "this."){
14165                     format = "fm." + format + '(';
14166                 }else{
14167                     format = 'this.call("'+ format.substr(5) + '", ';
14168                     args = ", values";
14169                 }
14170                 
14171                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
14172             }
14173              
14174             if (args && args.length) {
14175                 // called with xxyx.yuu:(test,test)
14176                 // change to ()
14177                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
14178             }
14179             // raw.. - :raw modifier..
14180             return "'"+ sep + udef_st  + name + ")"+sep+"'";
14181             
14182         };
14183         var body;
14184         // branched to use + in gecko and [].join() in others
14185         if(Roo.isGecko){
14186             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
14187                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14188                     "';};};";
14189         }else{
14190             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
14191             body.push(tpl.body.replace(/(\r\n|\n)/g,
14192                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14193             body.push("'].join('');};};");
14194             body = body.join('');
14195         }
14196         
14197         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14198        
14199         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
14200         eval(body);
14201         
14202         return this;
14203     },
14204      
14205     /**
14206      * same as applyTemplate, except it's done to one of the subTemplates
14207      * when using named templates, you can do:
14208      *
14209      * var str = pl.applySubTemplate('your-name', values);
14210      *
14211      * 
14212      * @param {Number} id of the template
14213      * @param {Object} values to apply to template
14214      * @param {Object} parent (normaly the instance of this object)
14215      */
14216     applySubTemplate : function(id, values, parent)
14217     {
14218         
14219         
14220         var t = this.tpls[id];
14221         
14222         
14223         try { 
14224             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14225                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14226                 return '';
14227             }
14228         } catch(e) {
14229             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14230             Roo.log(values);
14231           
14232             return '';
14233         }
14234         try { 
14235             
14236             if(t.execCall && t.execCall.call(this, values, parent)){
14237                 return '';
14238             }
14239         } catch(e) {
14240             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14241             Roo.log(values);
14242             return '';
14243         }
14244         
14245         try {
14246             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14247             parent = t.target ? values : parent;
14248             if(t.forCall && vs instanceof Array){
14249                 var buf = [];
14250                 for(var i = 0, len = vs.length; i < len; i++){
14251                     try {
14252                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14253                     } catch (e) {
14254                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14255                         Roo.log(e.body);
14256                         //Roo.log(t.compiled);
14257                         Roo.log(vs[i]);
14258                     }   
14259                 }
14260                 return buf.join('');
14261             }
14262         } catch (e) {
14263             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14264             Roo.log(values);
14265             return '';
14266         }
14267         try {
14268             return t.compiled.call(this, vs, parent);
14269         } catch (e) {
14270             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14271             Roo.log(e.body);
14272             //Roo.log(t.compiled);
14273             Roo.log(values);
14274             return '';
14275         }
14276     },
14277
14278    
14279
14280     applyTemplate : function(values){
14281         return this.master.compiled.call(this, values, {});
14282         //var s = this.subs;
14283     },
14284
14285     apply : function(){
14286         return this.applyTemplate.apply(this, arguments);
14287     }
14288
14289  });
14290
14291 Roo.DomTemplate.from = function(el){
14292     el = Roo.getDom(el);
14293     return new Roo.Domtemplate(el.value || el.innerHTML);
14294 };/*
14295  * Based on:
14296  * Ext JS Library 1.1.1
14297  * Copyright(c) 2006-2007, Ext JS, LLC.
14298  *
14299  * Originally Released Under LGPL - original licence link has changed is not relivant.
14300  *
14301  * Fork - LGPL
14302  * <script type="text/javascript">
14303  */
14304
14305 /**
14306  * @class Roo.util.DelayedTask
14307  * Provides a convenient method of performing setTimeout where a new
14308  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14309  * You can use this class to buffer
14310  * the keypress events for a certain number of milliseconds, and perform only if they stop
14311  * for that amount of time.
14312  * @constructor The parameters to this constructor serve as defaults and are not required.
14313  * @param {Function} fn (optional) The default function to timeout
14314  * @param {Object} scope (optional) The default scope of that timeout
14315  * @param {Array} args (optional) The default Array of arguments
14316  */
14317 Roo.util.DelayedTask = function(fn, scope, args){
14318     var id = null, d, t;
14319
14320     var call = function(){
14321         var now = new Date().getTime();
14322         if(now - t >= d){
14323             clearInterval(id);
14324             id = null;
14325             fn.apply(scope, args || []);
14326         }
14327     };
14328     /**
14329      * Cancels any pending timeout and queues a new one
14330      * @param {Number} delay The milliseconds to delay
14331      * @param {Function} newFn (optional) Overrides function passed to constructor
14332      * @param {Object} newScope (optional) Overrides scope passed to constructor
14333      * @param {Array} newArgs (optional) Overrides args passed to constructor
14334      */
14335     this.delay = function(delay, newFn, newScope, newArgs){
14336         if(id && delay != d){
14337             this.cancel();
14338         }
14339         d = delay;
14340         t = new Date().getTime();
14341         fn = newFn || fn;
14342         scope = newScope || scope;
14343         args = newArgs || args;
14344         if(!id){
14345             id = setInterval(call, d);
14346         }
14347     };
14348
14349     /**
14350      * Cancel the last queued timeout
14351      */
14352     this.cancel = function(){
14353         if(id){
14354             clearInterval(id);
14355             id = null;
14356         }
14357     };
14358 };/*
14359  * Based on:
14360  * Ext JS Library 1.1.1
14361  * Copyright(c) 2006-2007, Ext JS, LLC.
14362  *
14363  * Originally Released Under LGPL - original licence link has changed is not relivant.
14364  *
14365  * Fork - LGPL
14366  * <script type="text/javascript">
14367  */
14368 /**
14369  * @class Roo.util.TaskRunner
14370  * Manage background tasks - not sure why this is better that setInterval?
14371  * @static
14372  *
14373  */
14374  
14375 Roo.util.TaskRunner = function(interval){
14376     interval = interval || 10;
14377     var tasks = [], removeQueue = [];
14378     var id = 0;
14379     var running = false;
14380
14381     var stopThread = function(){
14382         running = false;
14383         clearInterval(id);
14384         id = 0;
14385     };
14386
14387     var startThread = function(){
14388         if(!running){
14389             running = true;
14390             id = setInterval(runTasks, interval);
14391         }
14392     };
14393
14394     var removeTask = function(task){
14395         removeQueue.push(task);
14396         if(task.onStop){
14397             task.onStop();
14398         }
14399     };
14400
14401     var runTasks = function(){
14402         if(removeQueue.length > 0){
14403             for(var i = 0, len = removeQueue.length; i < len; i++){
14404                 tasks.remove(removeQueue[i]);
14405             }
14406             removeQueue = [];
14407             if(tasks.length < 1){
14408                 stopThread();
14409                 return;
14410             }
14411         }
14412         var now = new Date().getTime();
14413         for(var i = 0, len = tasks.length; i < len; ++i){
14414             var t = tasks[i];
14415             var itime = now - t.taskRunTime;
14416             if(t.interval <= itime){
14417                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14418                 t.taskRunTime = now;
14419                 if(rt === false || t.taskRunCount === t.repeat){
14420                     removeTask(t);
14421                     return;
14422                 }
14423             }
14424             if(t.duration && t.duration <= (now - t.taskStartTime)){
14425                 removeTask(t);
14426             }
14427         }
14428     };
14429
14430     /**
14431      * Queues a new task.
14432      * @param {Object} task
14433      *
14434      * Task property : interval = how frequent to run.
14435      * Task object should implement
14436      * function run()
14437      * Task object may implement
14438      * function onStop()
14439      */
14440     this.start = function(task){
14441         tasks.push(task);
14442         task.taskStartTime = new Date().getTime();
14443         task.taskRunTime = 0;
14444         task.taskRunCount = 0;
14445         startThread();
14446         return task;
14447     };
14448     /**
14449      * Stop  new task.
14450      * @param {Object} task
14451      */
14452     this.stop = function(task){
14453         removeTask(task);
14454         return task;
14455     };
14456     /**
14457      * Stop all Tasks
14458      */
14459     this.stopAll = function(){
14460         stopThread();
14461         for(var i = 0, len = tasks.length; i < len; i++){
14462             if(tasks[i].onStop){
14463                 tasks[i].onStop();
14464             }
14465         }
14466         tasks = [];
14467         removeQueue = [];
14468     };
14469 };
14470
14471 Roo.TaskMgr = new Roo.util.TaskRunner();/*
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  
14483 /**
14484  * @class Roo.util.MixedCollection
14485  * @extends Roo.util.Observable
14486  * A Collection class that maintains both numeric indexes and keys and exposes events.
14487  * @constructor
14488  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14489  * collection (defaults to false)
14490  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14491  * and return the key value for that item.  This is used when available to look up the key on items that
14492  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14493  * equivalent to providing an implementation for the {@link #getKey} method.
14494  */
14495 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14496     this.items = [];
14497     this.map = {};
14498     this.keys = [];
14499     this.length = 0;
14500     this.addEvents({
14501         /**
14502          * @event clear
14503          * Fires when the collection is cleared.
14504          */
14505         "clear" : true,
14506         /**
14507          * @event add
14508          * Fires when an item is added to the collection.
14509          * @param {Number} index The index at which the item was added.
14510          * @param {Object} o The item added.
14511          * @param {String} key The key associated with the added item.
14512          */
14513         "add" : true,
14514         /**
14515          * @event replace
14516          * Fires when an item is replaced in the collection.
14517          * @param {String} key he key associated with the new added.
14518          * @param {Object} old The item being replaced.
14519          * @param {Object} new The new item.
14520          */
14521         "replace" : true,
14522         /**
14523          * @event remove
14524          * Fires when an item is removed from the collection.
14525          * @param {Object} o The item being removed.
14526          * @param {String} key (optional) The key associated with the removed item.
14527          */
14528         "remove" : true,
14529         "sort" : true
14530     });
14531     this.allowFunctions = allowFunctions === true;
14532     if(keyFn){
14533         this.getKey = keyFn;
14534     }
14535     Roo.util.MixedCollection.superclass.constructor.call(this);
14536 };
14537
14538 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14539     allowFunctions : false,
14540     
14541 /**
14542  * Adds an item to the collection.
14543  * @param {String} key The key to associate with the item
14544  * @param {Object} o The item to add.
14545  * @return {Object} The item added.
14546  */
14547     add : function(key, o){
14548         if(arguments.length == 1){
14549             o = arguments[0];
14550             key = this.getKey(o);
14551         }
14552         if(typeof key == "undefined" || key === null){
14553             this.length++;
14554             this.items.push(o);
14555             this.keys.push(null);
14556         }else{
14557             var old = this.map[key];
14558             if(old){
14559                 return this.replace(key, o);
14560             }
14561             this.length++;
14562             this.items.push(o);
14563             this.map[key] = o;
14564             this.keys.push(key);
14565         }
14566         this.fireEvent("add", this.length-1, o, key);
14567         return o;
14568     },
14569        
14570 /**
14571   * MixedCollection has a generic way to fetch keys if you implement getKey.
14572 <pre><code>
14573 // normal way
14574 var mc = new Roo.util.MixedCollection();
14575 mc.add(someEl.dom.id, someEl);
14576 mc.add(otherEl.dom.id, otherEl);
14577 //and so on
14578
14579 // using getKey
14580 var mc = new Roo.util.MixedCollection();
14581 mc.getKey = function(el){
14582    return el.dom.id;
14583 };
14584 mc.add(someEl);
14585 mc.add(otherEl);
14586
14587 // or via the constructor
14588 var mc = new Roo.util.MixedCollection(false, function(el){
14589    return el.dom.id;
14590 });
14591 mc.add(someEl);
14592 mc.add(otherEl);
14593 </code></pre>
14594  * @param o {Object} The item for which to find the key.
14595  * @return {Object} The key for the passed item.
14596  */
14597     getKey : function(o){
14598          return o.id; 
14599     },
14600    
14601 /**
14602  * Replaces an item in the collection.
14603  * @param {String} key The key associated with the item to replace, or the item to replace.
14604  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14605  * @return {Object}  The new item.
14606  */
14607     replace : function(key, o){
14608         if(arguments.length == 1){
14609             o = arguments[0];
14610             key = this.getKey(o);
14611         }
14612         var old = this.item(key);
14613         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14614              return this.add(key, o);
14615         }
14616         var index = this.indexOfKey(key);
14617         this.items[index] = o;
14618         this.map[key] = o;
14619         this.fireEvent("replace", key, old, o);
14620         return o;
14621     },
14622    
14623 /**
14624  * Adds all elements of an Array or an Object to the collection.
14625  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14626  * an Array of values, each of which are added to the collection.
14627  */
14628     addAll : function(objs){
14629         if(arguments.length > 1 || objs instanceof Array){
14630             var args = arguments.length > 1 ? arguments : objs;
14631             for(var i = 0, len = args.length; i < len; i++){
14632                 this.add(args[i]);
14633             }
14634         }else{
14635             for(var key in objs){
14636                 if(this.allowFunctions || typeof objs[key] != "function"){
14637                     this.add(key, objs[key]);
14638                 }
14639             }
14640         }
14641     },
14642    
14643 /**
14644  * Executes the specified function once for every item in the collection, passing each
14645  * item as the first and only parameter. returning false from the function will stop the iteration.
14646  * @param {Function} fn The function to execute for each item.
14647  * @param {Object} scope (optional) The scope in which to execute the function.
14648  */
14649     each : function(fn, scope){
14650         var items = [].concat(this.items); // each safe for removal
14651         for(var i = 0, len = items.length; i < len; i++){
14652             if(fn.call(scope || items[i], items[i], i, len) === false){
14653                 break;
14654             }
14655         }
14656     },
14657    
14658 /**
14659  * Executes the specified function once for every key in the collection, passing each
14660  * key, and its associated item as the first two parameters.
14661  * @param {Function} fn The function to execute for each item.
14662  * @param {Object} scope (optional) The scope in which to execute the function.
14663  */
14664     eachKey : function(fn, scope){
14665         for(var i = 0, len = this.keys.length; i < len; i++){
14666             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14667         }
14668     },
14669    
14670 /**
14671  * Returns the first item in the collection which elicits a true return value from the
14672  * passed selection function.
14673  * @param {Function} fn The selection function to execute for each item.
14674  * @param {Object} scope (optional) The scope in which to execute the function.
14675  * @return {Object} The first item in the collection which returned true from the selection function.
14676  */
14677     find : function(fn, scope){
14678         for(var i = 0, len = this.items.length; i < len; i++){
14679             if(fn.call(scope || window, this.items[i], this.keys[i])){
14680                 return this.items[i];
14681             }
14682         }
14683         return null;
14684     },
14685    
14686 /**
14687  * Inserts an item at the specified index in the collection.
14688  * @param {Number} index The index to insert the item at.
14689  * @param {String} key The key to associate with the new item, or the item itself.
14690  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14691  * @return {Object} The item inserted.
14692  */
14693     insert : function(index, key, o){
14694         if(arguments.length == 2){
14695             o = arguments[1];
14696             key = this.getKey(o);
14697         }
14698         if(index >= this.length){
14699             return this.add(key, o);
14700         }
14701         this.length++;
14702         this.items.splice(index, 0, o);
14703         if(typeof key != "undefined" && key != null){
14704             this.map[key] = o;
14705         }
14706         this.keys.splice(index, 0, key);
14707         this.fireEvent("add", index, o, key);
14708         return o;
14709     },
14710    
14711 /**
14712  * Removed an item from the collection.
14713  * @param {Object} o The item to remove.
14714  * @return {Object} The item removed.
14715  */
14716     remove : function(o){
14717         return this.removeAt(this.indexOf(o));
14718     },
14719    
14720 /**
14721  * Remove an item from a specified index in the collection.
14722  * @param {Number} index The index within the collection of the item to remove.
14723  */
14724     removeAt : function(index){
14725         if(index < this.length && index >= 0){
14726             this.length--;
14727             var o = this.items[index];
14728             this.items.splice(index, 1);
14729             var key = this.keys[index];
14730             if(typeof key != "undefined"){
14731                 delete this.map[key];
14732             }
14733             this.keys.splice(index, 1);
14734             this.fireEvent("remove", o, key);
14735         }
14736     },
14737    
14738 /**
14739  * Removed an item associated with the passed key fom the collection.
14740  * @param {String} key The key of the item to remove.
14741  */
14742     removeKey : function(key){
14743         return this.removeAt(this.indexOfKey(key));
14744     },
14745    
14746 /**
14747  * Returns the number of items in the collection.
14748  * @return {Number} the number of items in the collection.
14749  */
14750     getCount : function(){
14751         return this.length; 
14752     },
14753    
14754 /**
14755  * Returns index within the collection of the passed Object.
14756  * @param {Object} o The item to find the index of.
14757  * @return {Number} index of the item.
14758  */
14759     indexOf : function(o){
14760         if(!this.items.indexOf){
14761             for(var i = 0, len = this.items.length; i < len; i++){
14762                 if(this.items[i] == o) {
14763                     return i;
14764                 }
14765             }
14766             return -1;
14767         }else{
14768             return this.items.indexOf(o);
14769         }
14770     },
14771    
14772 /**
14773  * Returns index within the collection of the passed key.
14774  * @param {String} key The key to find the index of.
14775  * @return {Number} index of the key.
14776  */
14777     indexOfKey : function(key){
14778         if(!this.keys.indexOf){
14779             for(var i = 0, len = this.keys.length; i < len; i++){
14780                 if(this.keys[i] == key) {
14781                     return i;
14782                 }
14783             }
14784             return -1;
14785         }else{
14786             return this.keys.indexOf(key);
14787         }
14788     },
14789    
14790 /**
14791  * Returns the item associated with the passed key OR index. Key has priority over index.
14792  * @param {String/Number} key The key or index of the item.
14793  * @return {Object} The item associated with the passed key.
14794  */
14795     item : function(key){
14796         if (key === 'length') {
14797             return null;
14798         }
14799         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14800         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14801     },
14802     
14803 /**
14804  * Returns the item at the specified index.
14805  * @param {Number} index The index of the item.
14806  * @return {Object}
14807  */
14808     itemAt : function(index){
14809         return this.items[index];
14810     },
14811     
14812 /**
14813  * Returns the item associated with the passed key.
14814  * @param {String/Number} key The key of the item.
14815  * @return {Object} The item associated with the passed key.
14816  */
14817     key : function(key){
14818         return this.map[key];
14819     },
14820    
14821 /**
14822  * Returns true if the collection contains the passed Object as an item.
14823  * @param {Object} o  The Object to look for in the collection.
14824  * @return {Boolean} True if the collection contains the Object as an item.
14825  */
14826     contains : function(o){
14827         return this.indexOf(o) != -1;
14828     },
14829    
14830 /**
14831  * Returns true if the collection contains the passed Object as a key.
14832  * @param {String} key The key to look for in the collection.
14833  * @return {Boolean} True if the collection contains the Object as a key.
14834  */
14835     containsKey : function(key){
14836         return typeof this.map[key] != "undefined";
14837     },
14838    
14839 /**
14840  * Removes all items from the collection.
14841  */
14842     clear : function(){
14843         this.length = 0;
14844         this.items = [];
14845         this.keys = [];
14846         this.map = {};
14847         this.fireEvent("clear");
14848     },
14849    
14850 /**
14851  * Returns the first item in the collection.
14852  * @return {Object} the first item in the collection..
14853  */
14854     first : function(){
14855         return this.items[0]; 
14856     },
14857    
14858 /**
14859  * Returns the last item in the collection.
14860  * @return {Object} the last item in the collection..
14861  */
14862     last : function(){
14863         return this.items[this.length-1];   
14864     },
14865     
14866     _sort : function(property, dir, fn){
14867         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14868         fn = fn || function(a, b){
14869             return a-b;
14870         };
14871         var c = [], k = this.keys, items = this.items;
14872         for(var i = 0, len = items.length; i < len; i++){
14873             c[c.length] = {key: k[i], value: items[i], index: i};
14874         }
14875         c.sort(function(a, b){
14876             var v = fn(a[property], b[property]) * dsc;
14877             if(v == 0){
14878                 v = (a.index < b.index ? -1 : 1);
14879             }
14880             return v;
14881         });
14882         for(var i = 0, len = c.length; i < len; i++){
14883             items[i] = c[i].value;
14884             k[i] = c[i].key;
14885         }
14886         this.fireEvent("sort", this);
14887     },
14888     
14889     /**
14890      * Sorts this collection with the passed comparison function
14891      * @param {String} direction (optional) "ASC" or "DESC"
14892      * @param {Function} fn (optional) comparison function
14893      */
14894     sort : function(dir, fn){
14895         this._sort("value", dir, fn);
14896     },
14897     
14898     /**
14899      * Sorts this collection by keys
14900      * @param {String} direction (optional) "ASC" or "DESC"
14901      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14902      */
14903     keySort : function(dir, fn){
14904         this._sort("key", dir, fn || function(a, b){
14905             return String(a).toUpperCase()-String(b).toUpperCase();
14906         });
14907     },
14908     
14909     /**
14910      * Returns a range of items in this collection
14911      * @param {Number} startIndex (optional) defaults to 0
14912      * @param {Number} endIndex (optional) default to the last item
14913      * @return {Array} An array of items
14914      */
14915     getRange : function(start, end){
14916         var items = this.items;
14917         if(items.length < 1){
14918             return [];
14919         }
14920         start = start || 0;
14921         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14922         var r = [];
14923         if(start <= end){
14924             for(var i = start; i <= end; i++) {
14925                     r[r.length] = items[i];
14926             }
14927         }else{
14928             for(var i = start; i >= end; i--) {
14929                     r[r.length] = items[i];
14930             }
14931         }
14932         return r;
14933     },
14934         
14935     /**
14936      * Filter the <i>objects</i> in this collection by a specific property. 
14937      * Returns a new collection that has been filtered.
14938      * @param {String} property A property on your objects
14939      * @param {String/RegExp} value Either string that the property values 
14940      * should start with or a RegExp to test against the property
14941      * @return {MixedCollection} The new filtered collection
14942      */
14943     filter : function(property, value){
14944         if(!value.exec){ // not a regex
14945             value = String(value);
14946             if(value.length == 0){
14947                 return this.clone();
14948             }
14949             value = new RegExp("^" + Roo.escapeRe(value), "i");
14950         }
14951         return this.filterBy(function(o){
14952             return o && value.test(o[property]);
14953         });
14954         },
14955     
14956     /**
14957      * Filter by a function. * Returns a new collection that has been filtered.
14958      * The passed function will be called with each 
14959      * object in the collection. If the function returns true, the value is included 
14960      * otherwise it is filtered.
14961      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14962      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14963      * @return {MixedCollection} The new filtered collection
14964      */
14965     filterBy : function(fn, scope){
14966         var r = new Roo.util.MixedCollection();
14967         r.getKey = this.getKey;
14968         var k = this.keys, it = this.items;
14969         for(var i = 0, len = it.length; i < len; i++){
14970             if(fn.call(scope||this, it[i], k[i])){
14971                                 r.add(k[i], it[i]);
14972                         }
14973         }
14974         return r;
14975     },
14976     
14977     /**
14978      * Creates a duplicate of this collection
14979      * @return {MixedCollection}
14980      */
14981     clone : function(){
14982         var r = new Roo.util.MixedCollection();
14983         var k = this.keys, it = this.items;
14984         for(var i = 0, len = it.length; i < len; i++){
14985             r.add(k[i], it[i]);
14986         }
14987         r.getKey = this.getKey;
14988         return r;
14989     }
14990 });
14991 /**
14992  * Returns the item associated with the passed key or index.
14993  * @method
14994  * @param {String/Number} key The key or index of the item.
14995  * @return {Object} The item associated with the passed key.
14996  */
14997 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14998  * Based on:
14999  * Ext JS Library 1.1.1
15000  * Copyright(c) 2006-2007, Ext JS, LLC.
15001  *
15002  * Originally Released Under LGPL - original licence link has changed is not relivant.
15003  *
15004  * Fork - LGPL
15005  * <script type="text/javascript">
15006  */
15007 /**
15008  * @class Roo.util.JSON
15009  * Modified version of Douglas Crockford"s json.js that doesn"t
15010  * mess with the Object prototype 
15011  * http://www.json.org/js.html
15012  * @static
15013  */
15014 Roo.util.JSON = new (function(){
15015     var useHasOwn = {}.hasOwnProperty ? true : false;
15016     
15017     // crashes Safari in some instances
15018     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
15019     
15020     var pad = function(n) {
15021         return n < 10 ? "0" + n : n;
15022     };
15023     
15024     var m = {
15025         "\b": '\\b',
15026         "\t": '\\t',
15027         "\n": '\\n',
15028         "\f": '\\f',
15029         "\r": '\\r',
15030         '"' : '\\"',
15031         "\\": '\\\\'
15032     };
15033
15034     var encodeString = function(s){
15035         if (/["\\\x00-\x1f]/.test(s)) {
15036             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15037                 var c = m[b];
15038                 if(c){
15039                     return c;
15040                 }
15041                 c = b.charCodeAt();
15042                 return "\\u00" +
15043                     Math.floor(c / 16).toString(16) +
15044                     (c % 16).toString(16);
15045             }) + '"';
15046         }
15047         return '"' + s + '"';
15048     };
15049     
15050     var encodeArray = function(o){
15051         var a = ["["], b, i, l = o.length, v;
15052             for (i = 0; i < l; i += 1) {
15053                 v = o[i];
15054                 switch (typeof v) {
15055                     case "undefined":
15056                     case "function":
15057                     case "unknown":
15058                         break;
15059                     default:
15060                         if (b) {
15061                             a.push(',');
15062                         }
15063                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15064                         b = true;
15065                 }
15066             }
15067             a.push("]");
15068             return a.join("");
15069     };
15070     
15071     var encodeDate = function(o){
15072         return '"' + o.getFullYear() + "-" +
15073                 pad(o.getMonth() + 1) + "-" +
15074                 pad(o.getDate()) + "T" +
15075                 pad(o.getHours()) + ":" +
15076                 pad(o.getMinutes()) + ":" +
15077                 pad(o.getSeconds()) + '"';
15078     };
15079     
15080     /**
15081      * Encodes an Object, Array or other value
15082      * @param {Mixed} o The variable to encode
15083      * @return {String} The JSON string
15084      */
15085     this.encode = function(o)
15086     {
15087         // should this be extended to fully wrap stringify..
15088         
15089         if(typeof o == "undefined" || o === null){
15090             return "null";
15091         }else if(o instanceof Array){
15092             return encodeArray(o);
15093         }else if(o instanceof Date){
15094             return encodeDate(o);
15095         }else if(typeof o == "string"){
15096             return encodeString(o);
15097         }else if(typeof o == "number"){
15098             return isFinite(o) ? String(o) : "null";
15099         }else if(typeof o == "boolean"){
15100             return String(o);
15101         }else {
15102             var a = ["{"], b, i, v;
15103             for (i in o) {
15104                 if(!useHasOwn || o.hasOwnProperty(i)) {
15105                     v = o[i];
15106                     switch (typeof v) {
15107                     case "undefined":
15108                     case "function":
15109                     case "unknown":
15110                         break;
15111                     default:
15112                         if(b){
15113                             a.push(',');
15114                         }
15115                         a.push(this.encode(i), ":",
15116                                 v === null ? "null" : this.encode(v));
15117                         b = true;
15118                     }
15119                 }
15120             }
15121             a.push("}");
15122             return a.join("");
15123         }
15124     };
15125     
15126     /**
15127      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15128      * @param {String} json The JSON string
15129      * @return {Object} The resulting object
15130      */
15131     this.decode = function(json){
15132         
15133         return  /** eval:var:json */ eval("(" + json + ')');
15134     };
15135 })();
15136 /** 
15137  * Shorthand for {@link Roo.util.JSON#encode}
15138  * @member Roo encode 
15139  * @method */
15140 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15141 /** 
15142  * Shorthand for {@link Roo.util.JSON#decode}
15143  * @member Roo decode 
15144  * @method */
15145 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15146 /*
15147  * Based on:
15148  * Ext JS Library 1.1.1
15149  * Copyright(c) 2006-2007, Ext JS, LLC.
15150  *
15151  * Originally Released Under LGPL - original licence link has changed is not relivant.
15152  *
15153  * Fork - LGPL
15154  * <script type="text/javascript">
15155  */
15156  
15157 /**
15158  * @class Roo.util.Format
15159  * Reusable data formatting functions
15160  * @static
15161  */
15162 Roo.util.Format = function(){
15163     var trimRe = /^\s+|\s+$/g;
15164     return {
15165         /**
15166          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15167          * @param {String} value The string to truncate
15168          * @param {Number} length The maximum length to allow before truncating
15169          * @return {String} The converted text
15170          */
15171         ellipsis : function(value, len){
15172             if(value && value.length > len){
15173                 return value.substr(0, len-3)+"...";
15174             }
15175             return value;
15176         },
15177
15178         /**
15179          * Checks a reference and converts it to empty string if it is undefined
15180          * @param {Mixed} value Reference to check
15181          * @return {Mixed} Empty string if converted, otherwise the original value
15182          */
15183         undef : function(value){
15184             return typeof value != "undefined" ? value : "";
15185         },
15186
15187         /**
15188          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15189          * @param {String} value The string to encode
15190          * @return {String} The encoded text
15191          */
15192         htmlEncode : function(value){
15193             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
15194         },
15195
15196         /**
15197          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15198          * @param {String} value The string to decode
15199          * @return {String} The decoded text
15200          */
15201         htmlDecode : function(value){
15202             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15203         },
15204
15205         /**
15206          * Trims any whitespace from either side of a string
15207          * @param {String} value The text to trim
15208          * @return {String} The trimmed text
15209          */
15210         trim : function(value){
15211             return String(value).replace(trimRe, "");
15212         },
15213
15214         /**
15215          * Returns a substring from within an original string
15216          * @param {String} value The original text
15217          * @param {Number} start The start index of the substring
15218          * @param {Number} length The length of the substring
15219          * @return {String} The substring
15220          */
15221         substr : function(value, start, length){
15222             return String(value).substr(start, length);
15223         },
15224
15225         /**
15226          * Converts a string to all lower case letters
15227          * @param {String} value The text to convert
15228          * @return {String} The converted text
15229          */
15230         lowercase : function(value){
15231             return String(value).toLowerCase();
15232         },
15233
15234         /**
15235          * Converts a string to all upper case letters
15236          * @param {String} value The text to convert
15237          * @return {String} The converted text
15238          */
15239         uppercase : function(value){
15240             return String(value).toUpperCase();
15241         },
15242
15243         /**
15244          * Converts the first character only of a string to upper case
15245          * @param {String} value The text to convert
15246          * @return {String} The converted text
15247          */
15248         capitalize : function(value){
15249             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15250         },
15251
15252         // private
15253         call : function(value, fn){
15254             if(arguments.length > 2){
15255                 var args = Array.prototype.slice.call(arguments, 2);
15256                 args.unshift(value);
15257                  
15258                 return /** eval:var:value */  eval(fn).apply(window, args);
15259             }else{
15260                 /** eval:var:value */
15261                 return /** eval:var:value */ eval(fn).call(window, value);
15262             }
15263         },
15264
15265        
15266         /**
15267          * safer version of Math.toFixed..??/
15268          * @param {Number/String} value The numeric value to format
15269          * @param {Number/String} value Decimal places 
15270          * @return {String} The formatted currency string
15271          */
15272         toFixed : function(v, n)
15273         {
15274             // why not use to fixed - precision is buggered???
15275             if (!n) {
15276                 return Math.round(v-0);
15277             }
15278             var fact = Math.pow(10,n+1);
15279             v = (Math.round((v-0)*fact))/fact;
15280             var z = (''+fact).substring(2);
15281             if (v == Math.floor(v)) {
15282                 return Math.floor(v) + '.' + z;
15283             }
15284             
15285             // now just padd decimals..
15286             var ps = String(v).split('.');
15287             var fd = (ps[1] + z);
15288             var r = fd.substring(0,n); 
15289             var rm = fd.substring(n); 
15290             if (rm < 5) {
15291                 return ps[0] + '.' + r;
15292             }
15293             r*=1; // turn it into a number;
15294             r++;
15295             if (String(r).length != n) {
15296                 ps[0]*=1;
15297                 ps[0]++;
15298                 r = String(r).substring(1); // chop the end off.
15299             }
15300             
15301             return ps[0] + '.' + r;
15302              
15303         },
15304         
15305         /**
15306          * Format a number as US currency
15307          * @param {Number/String} value The numeric value to format
15308          * @return {String} The formatted currency string
15309          */
15310         usMoney : function(v){
15311             return '$' + Roo.util.Format.number(v);
15312         },
15313         
15314         /**
15315          * Format a number
15316          * eventually this should probably emulate php's number_format
15317          * @param {Number/String} value The numeric value to format
15318          * @param {Number} decimals number of decimal places
15319          * @param {String} delimiter for thousands (default comma)
15320          * @return {String} The formatted currency string
15321          */
15322         number : function(v, decimals, thousandsDelimiter)
15323         {
15324             // multiply and round.
15325             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15326             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15327             
15328             var mul = Math.pow(10, decimals);
15329             var zero = String(mul).substring(1);
15330             v = (Math.round((v-0)*mul))/mul;
15331             
15332             // if it's '0' number.. then
15333             
15334             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15335             v = String(v);
15336             var ps = v.split('.');
15337             var whole = ps[0];
15338             
15339             var r = /(\d+)(\d{3})/;
15340             // add comma's
15341             
15342             if(thousandsDelimiter.length != 0) {
15343                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15344             } 
15345             
15346             var sub = ps[1] ?
15347                     // has decimals..
15348                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15349                     // does not have decimals
15350                     (decimals ? ('.' + zero) : '');
15351             
15352             
15353             return whole + sub ;
15354         },
15355         
15356         /**
15357          * Parse a value into a formatted date using the specified format pattern.
15358          * @param {Mixed} value The value to format
15359          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15360          * @return {String} The formatted date string
15361          */
15362         date : function(v, format){
15363             if(!v){
15364                 return "";
15365             }
15366             if(!(v instanceof Date)){
15367                 v = new Date(Date.parse(v));
15368             }
15369             return v.dateFormat(format || Roo.util.Format.defaults.date);
15370         },
15371
15372         /**
15373          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15374          * @param {String} format Any valid date format string
15375          * @return {Function} The date formatting function
15376          */
15377         dateRenderer : function(format){
15378             return function(v){
15379                 return Roo.util.Format.date(v, format);  
15380             };
15381         },
15382
15383         // private
15384         stripTagsRE : /<\/?[^>]+>/gi,
15385         
15386         /**
15387          * Strips all HTML tags
15388          * @param {Mixed} value The text from which to strip tags
15389          * @return {String} The stripped text
15390          */
15391         stripTags : function(v){
15392             return !v ? v : String(v).replace(this.stripTagsRE, "");
15393         },
15394         
15395         /**
15396          * Size in Mb,Gb etc.
15397          * @param {Number} value The number to be formated
15398          * @param {number} decimals how many decimal places
15399          * @return {String} the formated string
15400          */
15401         size : function(value, decimals)
15402         {
15403             var sizes = ['b', 'k', 'M', 'G', 'T'];
15404             if (value == 0) {
15405                 return 0;
15406             }
15407             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15408             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15409         }
15410         
15411         
15412         
15413     };
15414 }();
15415 Roo.util.Format.defaults = {
15416     date : 'd/M/Y'
15417 };/*
15418  * Based on:
15419  * Ext JS Library 1.1.1
15420  * Copyright(c) 2006-2007, Ext JS, LLC.
15421  *
15422  * Originally Released Under LGPL - original licence link has changed is not relivant.
15423  *
15424  * Fork - LGPL
15425  * <script type="text/javascript">
15426  */
15427
15428
15429  
15430
15431 /**
15432  * @class Roo.MasterTemplate
15433  * @extends Roo.Template
15434  * Provides a template that can have child templates. The syntax is:
15435 <pre><code>
15436 var t = new Roo.MasterTemplate(
15437         '&lt;select name="{name}"&gt;',
15438                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15439         '&lt;/select&gt;'
15440 );
15441 t.add('options', {value: 'foo', text: 'bar'});
15442 // or you can add multiple child elements in one shot
15443 t.addAll('options', [
15444     {value: 'foo', text: 'bar'},
15445     {value: 'foo2', text: 'bar2'},
15446     {value: 'foo3', text: 'bar3'}
15447 ]);
15448 // then append, applying the master template values
15449 t.append('my-form', {name: 'my-select'});
15450 </code></pre>
15451 * A name attribute for the child template is not required if you have only one child
15452 * template or you want to refer to them by index.
15453  */
15454 Roo.MasterTemplate = function(){
15455     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15456     this.originalHtml = this.html;
15457     var st = {};
15458     var m, re = this.subTemplateRe;
15459     re.lastIndex = 0;
15460     var subIndex = 0;
15461     while(m = re.exec(this.html)){
15462         var name = m[1], content = m[2];
15463         st[subIndex] = {
15464             name: name,
15465             index: subIndex,
15466             buffer: [],
15467             tpl : new Roo.Template(content)
15468         };
15469         if(name){
15470             st[name] = st[subIndex];
15471         }
15472         st[subIndex].tpl.compile();
15473         st[subIndex].tpl.call = this.call.createDelegate(this);
15474         subIndex++;
15475     }
15476     this.subCount = subIndex;
15477     this.subs = st;
15478 };
15479 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15480     /**
15481     * The regular expression used to match sub templates
15482     * @type RegExp
15483     * @property
15484     */
15485     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15486
15487     /**
15488      * Applies the passed values to a child template.
15489      * @param {String/Number} name (optional) The name or index of the child template
15490      * @param {Array/Object} values The values to be applied to the template
15491      * @return {MasterTemplate} this
15492      */
15493      add : function(name, values){
15494         if(arguments.length == 1){
15495             values = arguments[0];
15496             name = 0;
15497         }
15498         var s = this.subs[name];
15499         s.buffer[s.buffer.length] = s.tpl.apply(values);
15500         return this;
15501     },
15502
15503     /**
15504      * Applies all the passed values to a child template.
15505      * @param {String/Number} name (optional) The name or index of the child template
15506      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15507      * @param {Boolean} reset (optional) True to reset the template first
15508      * @return {MasterTemplate} this
15509      */
15510     fill : function(name, values, reset){
15511         var a = arguments;
15512         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15513             values = a[0];
15514             name = 0;
15515             reset = a[1];
15516         }
15517         if(reset){
15518             this.reset();
15519         }
15520         for(var i = 0, len = values.length; i < len; i++){
15521             this.add(name, values[i]);
15522         }
15523         return this;
15524     },
15525
15526     /**
15527      * Resets the template for reuse
15528      * @return {MasterTemplate} this
15529      */
15530      reset : function(){
15531         var s = this.subs;
15532         for(var i = 0; i < this.subCount; i++){
15533             s[i].buffer = [];
15534         }
15535         return this;
15536     },
15537
15538     applyTemplate : function(values){
15539         var s = this.subs;
15540         var replaceIndex = -1;
15541         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15542             return s[++replaceIndex].buffer.join("");
15543         });
15544         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15545     },
15546
15547     apply : function(){
15548         return this.applyTemplate.apply(this, arguments);
15549     },
15550
15551     compile : function(){return this;}
15552 });
15553
15554 /**
15555  * Alias for fill().
15556  * @method
15557  */
15558 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15559  /**
15560  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15561  * var tpl = Roo.MasterTemplate.from('element-id');
15562  * @param {String/HTMLElement} el
15563  * @param {Object} config
15564  * @static
15565  */
15566 Roo.MasterTemplate.from = function(el, config){
15567     el = Roo.getDom(el);
15568     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15569 };/*
15570  * Based on:
15571  * Ext JS Library 1.1.1
15572  * Copyright(c) 2006-2007, Ext JS, LLC.
15573  *
15574  * Originally Released Under LGPL - original licence link has changed is not relivant.
15575  *
15576  * Fork - LGPL
15577  * <script type="text/javascript">
15578  */
15579
15580  
15581 /**
15582  * @class Roo.util.CSS
15583  * Utility class for manipulating CSS rules
15584  * @static
15585
15586  */
15587 Roo.util.CSS = function(){
15588         var rules = null;
15589         var doc = document;
15590
15591     var camelRe = /(-[a-z])/gi;
15592     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15593
15594    return {
15595    /**
15596     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15597     * tag and appended to the HEAD of the document.
15598     * @param {String|Object} cssText The text containing the css rules
15599     * @param {String} id An id to add to the stylesheet for later removal
15600     * @return {StyleSheet}
15601     */
15602     createStyleSheet : function(cssText, id){
15603         var ss;
15604         var head = doc.getElementsByTagName("head")[0];
15605         var nrules = doc.createElement("style");
15606         nrules.setAttribute("type", "text/css");
15607         if(id){
15608             nrules.setAttribute("id", id);
15609         }
15610         if (typeof(cssText) != 'string') {
15611             // support object maps..
15612             // not sure if this a good idea.. 
15613             // perhaps it should be merged with the general css handling
15614             // and handle js style props.
15615             var cssTextNew = [];
15616             for(var n in cssText) {
15617                 var citems = [];
15618                 for(var k in cssText[n]) {
15619                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15620                 }
15621                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15622                 
15623             }
15624             cssText = cssTextNew.join("\n");
15625             
15626         }
15627        
15628        
15629        if(Roo.isIE){
15630            head.appendChild(nrules);
15631            ss = nrules.styleSheet;
15632            ss.cssText = cssText;
15633        }else{
15634            try{
15635                 nrules.appendChild(doc.createTextNode(cssText));
15636            }catch(e){
15637                nrules.cssText = cssText; 
15638            }
15639            head.appendChild(nrules);
15640            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15641        }
15642        this.cacheStyleSheet(ss);
15643        return ss;
15644    },
15645
15646    /**
15647     * Removes a style or link tag by id
15648     * @param {String} id The id of the tag
15649     */
15650    removeStyleSheet : function(id){
15651        var existing = doc.getElementById(id);
15652        if(existing){
15653            existing.parentNode.removeChild(existing);
15654        }
15655    },
15656
15657    /**
15658     * Dynamically swaps an existing stylesheet reference for a new one
15659     * @param {String} id The id of an existing link tag to remove
15660     * @param {String} url The href of the new stylesheet to include
15661     */
15662    swapStyleSheet : function(id, url){
15663        this.removeStyleSheet(id);
15664        var ss = doc.createElement("link");
15665        ss.setAttribute("rel", "stylesheet");
15666        ss.setAttribute("type", "text/css");
15667        ss.setAttribute("id", id);
15668        ss.setAttribute("href", url);
15669        doc.getElementsByTagName("head")[0].appendChild(ss);
15670    },
15671    
15672    /**
15673     * Refresh the rule cache if you have dynamically added stylesheets
15674     * @return {Object} An object (hash) of rules indexed by selector
15675     */
15676    refreshCache : function(){
15677        return this.getRules(true);
15678    },
15679
15680    // private
15681    cacheStyleSheet : function(stylesheet){
15682        if(!rules){
15683            rules = {};
15684        }
15685        try{// try catch for cross domain access issue
15686            var ssRules = stylesheet.cssRules || stylesheet.rules;
15687            for(var j = ssRules.length-1; j >= 0; --j){
15688                rules[ssRules[j].selectorText] = ssRules[j];
15689            }
15690        }catch(e){}
15691    },
15692    
15693    /**
15694     * Gets all css rules for the document
15695     * @param {Boolean} refreshCache true to refresh the internal cache
15696     * @return {Object} An object (hash) of rules indexed by selector
15697     */
15698    getRules : function(refreshCache){
15699                 if(rules == null || refreshCache){
15700                         rules = {};
15701                         var ds = doc.styleSheets;
15702                         for(var i =0, len = ds.length; i < len; i++){
15703                             try{
15704                         this.cacheStyleSheet(ds[i]);
15705                     }catch(e){} 
15706                 }
15707                 }
15708                 return rules;
15709         },
15710         
15711         /**
15712     * Gets an an individual CSS rule by selector(s)
15713     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15714     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15715     * @return {CSSRule} The CSS rule or null if one is not found
15716     */
15717    getRule : function(selector, refreshCache){
15718                 var rs = this.getRules(refreshCache);
15719                 if(!(selector instanceof Array)){
15720                     return rs[selector];
15721                 }
15722                 for(var i = 0; i < selector.length; i++){
15723                         if(rs[selector[i]]){
15724                                 return rs[selector[i]];
15725                         }
15726                 }
15727                 return null;
15728         },
15729         
15730         
15731         /**
15732     * Updates a rule property
15733     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15734     * @param {String} property The css property
15735     * @param {String} value The new value for the property
15736     * @return {Boolean} true If a rule was found and updated
15737     */
15738    updateRule : function(selector, property, value){
15739                 if(!(selector instanceof Array)){
15740                         var rule = this.getRule(selector);
15741                         if(rule){
15742                                 rule.style[property.replace(camelRe, camelFn)] = value;
15743                                 return true;
15744                         }
15745                 }else{
15746                         for(var i = 0; i < selector.length; i++){
15747                                 if(this.updateRule(selector[i], property, value)){
15748                                         return true;
15749                                 }
15750                         }
15751                 }
15752                 return false;
15753         }
15754    };   
15755 }();/*
15756  * Based on:
15757  * Ext JS Library 1.1.1
15758  * Copyright(c) 2006-2007, Ext JS, LLC.
15759  *
15760  * Originally Released Under LGPL - original licence link has changed is not relivant.
15761  *
15762  * Fork - LGPL
15763  * <script type="text/javascript">
15764  */
15765
15766  
15767
15768 /**
15769  * @class Roo.util.ClickRepeater
15770  * @extends Roo.util.Observable
15771  * 
15772  * A wrapper class which can be applied to any element. Fires a "click" event while the
15773  * mouse is pressed. The interval between firings may be specified in the config but
15774  * defaults to 10 milliseconds.
15775  * 
15776  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15777  * 
15778  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15779  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15780  * Similar to an autorepeat key delay.
15781  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15782  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15783  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15784  *           "interval" and "delay" are ignored. "immediate" is honored.
15785  * @cfg {Boolean} preventDefault True to prevent the default click event
15786  * @cfg {Boolean} stopDefault True to stop the default click event
15787  * 
15788  * @history
15789  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15790  *     2007-02-02 jvs Renamed to ClickRepeater
15791  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15792  *
15793  *  @constructor
15794  * @param {String/HTMLElement/Element} el The element to listen on
15795  * @param {Object} config
15796  **/
15797 Roo.util.ClickRepeater = function(el, config)
15798 {
15799     this.el = Roo.get(el);
15800     this.el.unselectable();
15801
15802     Roo.apply(this, config);
15803
15804     this.addEvents({
15805     /**
15806      * @event mousedown
15807      * Fires when the mouse button is depressed.
15808      * @param {Roo.util.ClickRepeater} this
15809      */
15810         "mousedown" : true,
15811     /**
15812      * @event click
15813      * Fires on a specified interval during the time the element is pressed.
15814      * @param {Roo.util.ClickRepeater} this
15815      */
15816         "click" : true,
15817     /**
15818      * @event mouseup
15819      * Fires when the mouse key is released.
15820      * @param {Roo.util.ClickRepeater} this
15821      */
15822         "mouseup" : true
15823     });
15824
15825     this.el.on("mousedown", this.handleMouseDown, this);
15826     if(this.preventDefault || this.stopDefault){
15827         this.el.on("click", function(e){
15828             if(this.preventDefault){
15829                 e.preventDefault();
15830             }
15831             if(this.stopDefault){
15832                 e.stopEvent();
15833             }
15834         }, this);
15835     }
15836
15837     // allow inline handler
15838     if(this.handler){
15839         this.on("click", this.handler,  this.scope || this);
15840     }
15841
15842     Roo.util.ClickRepeater.superclass.constructor.call(this);
15843 };
15844
15845 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15846     interval : 20,
15847     delay: 250,
15848     preventDefault : true,
15849     stopDefault : false,
15850     timer : 0,
15851
15852     // private
15853     handleMouseDown : function(){
15854         clearTimeout(this.timer);
15855         this.el.blur();
15856         if(this.pressClass){
15857             this.el.addClass(this.pressClass);
15858         }
15859         this.mousedownTime = new Date();
15860
15861         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15862         this.el.on("mouseout", this.handleMouseOut, this);
15863
15864         this.fireEvent("mousedown", this);
15865         this.fireEvent("click", this);
15866         
15867         this.timer = this.click.defer(this.delay || this.interval, this);
15868     },
15869
15870     // private
15871     click : function(){
15872         this.fireEvent("click", this);
15873         this.timer = this.click.defer(this.getInterval(), this);
15874     },
15875
15876     // private
15877     getInterval: function(){
15878         if(!this.accelerate){
15879             return this.interval;
15880         }
15881         var pressTime = this.mousedownTime.getElapsed();
15882         if(pressTime < 500){
15883             return 400;
15884         }else if(pressTime < 1700){
15885             return 320;
15886         }else if(pressTime < 2600){
15887             return 250;
15888         }else if(pressTime < 3500){
15889             return 180;
15890         }else if(pressTime < 4400){
15891             return 140;
15892         }else if(pressTime < 5300){
15893             return 80;
15894         }else if(pressTime < 6200){
15895             return 50;
15896         }else{
15897             return 10;
15898         }
15899     },
15900
15901     // private
15902     handleMouseOut : function(){
15903         clearTimeout(this.timer);
15904         if(this.pressClass){
15905             this.el.removeClass(this.pressClass);
15906         }
15907         this.el.on("mouseover", this.handleMouseReturn, this);
15908     },
15909
15910     // private
15911     handleMouseReturn : function(){
15912         this.el.un("mouseover", this.handleMouseReturn);
15913         if(this.pressClass){
15914             this.el.addClass(this.pressClass);
15915         }
15916         this.click();
15917     },
15918
15919     // private
15920     handleMouseUp : function(){
15921         clearTimeout(this.timer);
15922         this.el.un("mouseover", this.handleMouseReturn);
15923         this.el.un("mouseout", this.handleMouseOut);
15924         Roo.get(document).un("mouseup", this.handleMouseUp);
15925         this.el.removeClass(this.pressClass);
15926         this.fireEvent("mouseup", this);
15927     }
15928 });/**
15929  * @class Roo.util.Clipboard
15930  * @static
15931  * 
15932  * Clipboard UTILS
15933  * 
15934  **/
15935 Roo.util.Clipboard = {
15936     /**
15937      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15938      * @param {String} text to copy to clipboard
15939      */
15940     write : function(text) {
15941         // navigator clipboard api needs a secure context (https)
15942         if (navigator.clipboard && window.isSecureContext) {
15943             // navigator clipboard api method'
15944             navigator.clipboard.writeText(text);
15945             return ;
15946         } 
15947         // text area method
15948         var ta = document.createElement("textarea");
15949         ta.value = text;
15950         // make the textarea out of viewport
15951         ta.style.position = "fixed";
15952         ta.style.left = "-999999px";
15953         ta.style.top = "-999999px";
15954         document.body.appendChild(ta);
15955         ta.focus();
15956         ta.select();
15957         document.execCommand('copy');
15958         (function() {
15959             ta.remove();
15960         }).defer(100);
15961         
15962     }
15963         
15964 }
15965     /*
15966  * Based on:
15967  * Ext JS Library 1.1.1
15968  * Copyright(c) 2006-2007, Ext JS, LLC.
15969  *
15970  * Originally Released Under LGPL - original licence link has changed is not relivant.
15971  *
15972  * Fork - LGPL
15973  * <script type="text/javascript">
15974  */
15975
15976  
15977 /**
15978  * @class Roo.KeyNav
15979  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15980  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15981  * way to implement custom navigation schemes for any UI component.</p>
15982  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15983  * pageUp, pageDown, del, home, end.  Usage:</p>
15984  <pre><code>
15985 var nav = new Roo.KeyNav("my-element", {
15986     "left" : function(e){
15987         this.moveLeft(e.ctrlKey);
15988     },
15989     "right" : function(e){
15990         this.moveRight(e.ctrlKey);
15991     },
15992     "enter" : function(e){
15993         this.save();
15994     },
15995     scope : this
15996 });
15997 </code></pre>
15998  * @constructor
15999  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16000  * @param {Object} config The config
16001  */
16002 Roo.KeyNav = function(el, config){
16003     this.el = Roo.get(el);
16004     Roo.apply(this, config);
16005     if(!this.disabled){
16006         this.disabled = true;
16007         this.enable();
16008     }
16009 };
16010
16011 Roo.KeyNav.prototype = {
16012     /**
16013      * @cfg {Boolean} disabled
16014      * True to disable this KeyNav instance (defaults to false)
16015      */
16016     disabled : false,
16017     /**
16018      * @cfg {String} defaultEventAction
16019      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
16020      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
16021      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
16022      */
16023     defaultEventAction: "stopEvent",
16024     /**
16025      * @cfg {Boolean} forceKeyDown
16026      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
16027      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16028      * handle keydown instead of keypress.
16029      */
16030     forceKeyDown : false,
16031
16032     // private
16033     prepareEvent : function(e){
16034         var k = e.getKey();
16035         var h = this.keyToHandler[k];
16036         //if(h && this[h]){
16037         //    e.stopPropagation();
16038         //}
16039         if(Roo.isSafari && h && k >= 37 && k <= 40){
16040             e.stopEvent();
16041         }
16042     },
16043
16044     // private
16045     relay : function(e){
16046         var k = e.getKey();
16047         var h = this.keyToHandler[k];
16048         if(h && this[h]){
16049             if(this.doRelay(e, this[h], h) !== true){
16050                 e[this.defaultEventAction]();
16051             }
16052         }
16053     },
16054
16055     // private
16056     doRelay : function(e, h, hname){
16057         return h.call(this.scope || this, e);
16058     },
16059
16060     // possible handlers
16061     enter : false,
16062     left : false,
16063     right : false,
16064     up : false,
16065     down : false,
16066     tab : false,
16067     esc : false,
16068     pageUp : false,
16069     pageDown : false,
16070     del : false,
16071     home : false,
16072     end : false,
16073
16074     // quick lookup hash
16075     keyToHandler : {
16076         37 : "left",
16077         39 : "right",
16078         38 : "up",
16079         40 : "down",
16080         33 : "pageUp",
16081         34 : "pageDown",
16082         46 : "del",
16083         36 : "home",
16084         35 : "end",
16085         13 : "enter",
16086         27 : "esc",
16087         9  : "tab"
16088     },
16089
16090         /**
16091          * Enable this KeyNav
16092          */
16093         enable: function(){
16094                 if(this.disabled){
16095             // ie won't do special keys on keypress, no one else will repeat keys with keydown
16096             // the EventObject will normalize Safari automatically
16097             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16098                 this.el.on("keydown", this.relay,  this);
16099             }else{
16100                 this.el.on("keydown", this.prepareEvent,  this);
16101                 this.el.on("keypress", this.relay,  this);
16102             }
16103                     this.disabled = false;
16104                 }
16105         },
16106
16107         /**
16108          * Disable this KeyNav
16109          */
16110         disable: function(){
16111                 if(!this.disabled){
16112                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16113                 this.el.un("keydown", this.relay);
16114             }else{
16115                 this.el.un("keydown", this.prepareEvent);
16116                 this.el.un("keypress", this.relay);
16117             }
16118                     this.disabled = true;
16119                 }
16120         }
16121 };/*
16122  * Based on:
16123  * Ext JS Library 1.1.1
16124  * Copyright(c) 2006-2007, Ext JS, LLC.
16125  *
16126  * Originally Released Under LGPL - original licence link has changed is not relivant.
16127  *
16128  * Fork - LGPL
16129  * <script type="text/javascript">
16130  */
16131
16132  
16133 /**
16134  * @class Roo.KeyMap
16135  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16136  * The constructor accepts the same config object as defined by {@link #addBinding}.
16137  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16138  * combination it will call the function with this signature (if the match is a multi-key
16139  * combination the callback will still be called only once): (String key, Roo.EventObject e)
16140  * A KeyMap can also handle a string representation of keys.<br />
16141  * Usage:
16142  <pre><code>
16143 // map one key by key code
16144 var map = new Roo.KeyMap("my-element", {
16145     key: 13, // or Roo.EventObject.ENTER
16146     fn: myHandler,
16147     scope: myObject
16148 });
16149
16150 // map multiple keys to one action by string
16151 var map = new Roo.KeyMap("my-element", {
16152     key: "a\r\n\t",
16153     fn: myHandler,
16154     scope: myObject
16155 });
16156
16157 // map multiple keys to multiple actions by strings and array of codes
16158 var map = new Roo.KeyMap("my-element", [
16159     {
16160         key: [10,13],
16161         fn: function(){ alert("Return was pressed"); }
16162     }, {
16163         key: "abc",
16164         fn: function(){ alert('a, b or c was pressed'); }
16165     }, {
16166         key: "\t",
16167         ctrl:true,
16168         shift:true,
16169         fn: function(){ alert('Control + shift + tab was pressed.'); }
16170     }
16171 ]);
16172 </code></pre>
16173  * <b>Note: A KeyMap starts enabled</b>
16174  * @constructor
16175  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16176  * @param {Object} config The config (see {@link #addBinding})
16177  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16178  */
16179 Roo.KeyMap = function(el, config, eventName){
16180     this.el  = Roo.get(el);
16181     this.eventName = eventName || "keydown";
16182     this.bindings = [];
16183     if(config){
16184         this.addBinding(config);
16185     }
16186     this.enable();
16187 };
16188
16189 Roo.KeyMap.prototype = {
16190     /**
16191      * True to stop the event from bubbling and prevent the default browser action if the
16192      * key was handled by the KeyMap (defaults to false)
16193      * @type Boolean
16194      */
16195     stopEvent : false,
16196
16197     /**
16198      * Add a new binding to this KeyMap. The following config object properties are supported:
16199      * <pre>
16200 Property    Type             Description
16201 ----------  ---------------  ----------------------------------------------------------------------
16202 key         String/Array     A single keycode or an array of keycodes to handle
16203 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16204 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16205 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16206 fn          Function         The function to call when KeyMap finds the expected key combination
16207 scope       Object           The scope of the callback function
16208 </pre>
16209      *
16210      * Usage:
16211      * <pre><code>
16212 // Create a KeyMap
16213 var map = new Roo.KeyMap(document, {
16214     key: Roo.EventObject.ENTER,
16215     fn: handleKey,
16216     scope: this
16217 });
16218
16219 //Add a new binding to the existing KeyMap later
16220 map.addBinding({
16221     key: 'abc',
16222     shift: true,
16223     fn: handleKey,
16224     scope: this
16225 });
16226 </code></pre>
16227      * @param {Object/Array} config A single KeyMap config or an array of configs
16228      */
16229         addBinding : function(config){
16230         if(config instanceof Array){
16231             for(var i = 0, len = config.length; i < len; i++){
16232                 this.addBinding(config[i]);
16233             }
16234             return;
16235         }
16236         var keyCode = config.key,
16237             shift = config.shift, 
16238             ctrl = config.ctrl, 
16239             alt = config.alt,
16240             fn = config.fn,
16241             scope = config.scope;
16242         if(typeof keyCode == "string"){
16243             var ks = [];
16244             var keyString = keyCode.toUpperCase();
16245             for(var j = 0, len = keyString.length; j < len; j++){
16246                 ks.push(keyString.charCodeAt(j));
16247             }
16248             keyCode = ks;
16249         }
16250         var keyArray = keyCode instanceof Array;
16251         var handler = function(e){
16252             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16253                 var k = e.getKey();
16254                 if(keyArray){
16255                     for(var i = 0, len = keyCode.length; i < len; i++){
16256                         if(keyCode[i] == k){
16257                           if(this.stopEvent){
16258                               e.stopEvent();
16259                           }
16260                           fn.call(scope || window, k, e);
16261                           return;
16262                         }
16263                     }
16264                 }else{
16265                     if(k == keyCode){
16266                         if(this.stopEvent){
16267                            e.stopEvent();
16268                         }
16269                         fn.call(scope || window, k, e);
16270                     }
16271                 }
16272             }
16273         };
16274         this.bindings.push(handler);  
16275         },
16276
16277     /**
16278      * Shorthand for adding a single key listener
16279      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16280      * following options:
16281      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16282      * @param {Function} fn The function to call
16283      * @param {Object} scope (optional) The scope of the function
16284      */
16285     on : function(key, fn, scope){
16286         var keyCode, shift, ctrl, alt;
16287         if(typeof key == "object" && !(key instanceof Array)){
16288             keyCode = key.key;
16289             shift = key.shift;
16290             ctrl = key.ctrl;
16291             alt = key.alt;
16292         }else{
16293             keyCode = key;
16294         }
16295         this.addBinding({
16296             key: keyCode,
16297             shift: shift,
16298             ctrl: ctrl,
16299             alt: alt,
16300             fn: fn,
16301             scope: scope
16302         })
16303     },
16304
16305     // private
16306     handleKeyDown : function(e){
16307             if(this.enabled){ //just in case
16308             var b = this.bindings;
16309             for(var i = 0, len = b.length; i < len; i++){
16310                 b[i].call(this, e);
16311             }
16312             }
16313         },
16314         
16315         /**
16316          * Returns true if this KeyMap is enabled
16317          * @return {Boolean} 
16318          */
16319         isEnabled : function(){
16320             return this.enabled;  
16321         },
16322         
16323         /**
16324          * Enables this KeyMap
16325          */
16326         enable: function(){
16327                 if(!this.enabled){
16328                     this.el.on(this.eventName, this.handleKeyDown, this);
16329                     this.enabled = true;
16330                 }
16331         },
16332
16333         /**
16334          * Disable this KeyMap
16335          */
16336         disable: function(){
16337                 if(this.enabled){
16338                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16339                     this.enabled = false;
16340                 }
16341         }
16342 };/*
16343  * Based on:
16344  * Ext JS Library 1.1.1
16345  * Copyright(c) 2006-2007, Ext JS, LLC.
16346  *
16347  * Originally Released Under LGPL - original licence link has changed is not relivant.
16348  *
16349  * Fork - LGPL
16350  * <script type="text/javascript">
16351  */
16352
16353  
16354 /**
16355  * @class Roo.util.TextMetrics
16356  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16357  * wide, in pixels, a given block of text will be.
16358  * @static
16359  */
16360 Roo.util.TextMetrics = function(){
16361     var shared;
16362     return {
16363         /**
16364          * Measures the size of the specified text
16365          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16366          * that can affect the size of the rendered text
16367          * @param {String} text The text to measure
16368          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16369          * in order to accurately measure the text height
16370          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16371          */
16372         measure : function(el, text, fixedWidth){
16373             if(!shared){
16374                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16375             }
16376             shared.bind(el);
16377             shared.setFixedWidth(fixedWidth || 'auto');
16378             return shared.getSize(text);
16379         },
16380
16381         /**
16382          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16383          * the overhead of multiple calls to initialize the style properties on each measurement.
16384          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16385          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16386          * in order to accurately measure the text height
16387          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16388          */
16389         createInstance : function(el, fixedWidth){
16390             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16391         }
16392     };
16393 }();
16394
16395 /**
16396  * @class Roo.util.TextMetrics.Instance
16397  * Instance of  TextMetrics Calcuation
16398  * @constructor
16399  * Create a new TextMetrics Instance
16400  * @param {Object} bindto
16401  * @param {Boolean} fixedWidth
16402  */
16403
16404 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16405 {
16406     var ml = new Roo.Element(document.createElement('div'));
16407     document.body.appendChild(ml.dom);
16408     ml.position('absolute');
16409     ml.setLeftTop(-1000, -1000);
16410     ml.hide();
16411
16412     if(fixedWidth){
16413         ml.setWidth(fixedWidth);
16414     }
16415      
16416     var instance = {
16417         /**
16418          * Returns the size of the specified text based on the internal element's style and width properties
16419          * @param {String} text The text to measure
16420          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16421          */
16422         getSize : function(text){
16423             ml.update(text);
16424             var s = ml.getSize();
16425             ml.update('');
16426             return s;
16427         },
16428
16429         /**
16430          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16431          * that can affect the size of the rendered text
16432          * @param {String/HTMLElement} el The element, dom node or id
16433          */
16434         bind : function(el){
16435             ml.setStyle(
16436                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16437             );
16438         },
16439
16440         /**
16441          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16442          * to set a fixed width in order to accurately measure the text height.
16443          * @param {Number} width The width to set on the element
16444          */
16445         setFixedWidth : function(width){
16446             ml.setWidth(width);
16447         },
16448
16449         /**
16450          * Returns the measured width of the specified text
16451          * @param {String} text The text to measure
16452          * @return {Number} width The width in pixels
16453          */
16454         getWidth : function(text){
16455             ml.dom.style.width = 'auto';
16456             return this.getSize(text).width;
16457         },
16458
16459         /**
16460          * Returns the measured height of the specified text.  For multiline text, be sure to call
16461          * {@link #setFixedWidth} if necessary.
16462          * @param {String} text The text to measure
16463          * @return {Number} height The height in pixels
16464          */
16465         getHeight : function(text){
16466             return this.getSize(text).height;
16467         }
16468     };
16469
16470     instance.bind(bindTo);
16471
16472     return instance;
16473 };
16474
16475 // backwards compat
16476 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16477  * Based on:
16478  * Ext JS Library 1.1.1
16479  * Copyright(c) 2006-2007, Ext JS, LLC.
16480  *
16481  * Originally Released Under LGPL - original licence link has changed is not relivant.
16482  *
16483  * Fork - LGPL
16484  * <script type="text/javascript">
16485  */
16486
16487 /**
16488  * @class Roo.state.Provider
16489  * Abstract base class for state provider implementations. This class provides methods
16490  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16491  * Provider interface.
16492  */
16493 Roo.state.Provider = function(){
16494     /**
16495      * @event statechange
16496      * Fires when a state change occurs.
16497      * @param {Provider} this This state provider
16498      * @param {String} key The state key which was changed
16499      * @param {String} value The encoded value for the state
16500      */
16501     this.addEvents({
16502         "statechange": true
16503     });
16504     this.state = {};
16505     Roo.state.Provider.superclass.constructor.call(this);
16506 };
16507 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16508     /**
16509      * Returns the current value for a key
16510      * @param {String} name The key name
16511      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16512      * @return {Mixed} The state data
16513      */
16514     get : function(name, defaultValue){
16515         return typeof this.state[name] == "undefined" ?
16516             defaultValue : this.state[name];
16517     },
16518     
16519     /**
16520      * Clears a value from the state
16521      * @param {String} name The key name
16522      */
16523     clear : function(name){
16524         delete this.state[name];
16525         this.fireEvent("statechange", this, name, null);
16526     },
16527     
16528     /**
16529      * Sets the value for a key
16530      * @param {String} name The key name
16531      * @param {Mixed} value The value to set
16532      */
16533     set : function(name, value){
16534         this.state[name] = value;
16535         this.fireEvent("statechange", this, name, value);
16536     },
16537     
16538     /**
16539      * Decodes a string previously encoded with {@link #encodeValue}.
16540      * @param {String} value The value to decode
16541      * @return {Mixed} The decoded value
16542      */
16543     decodeValue : function(cookie){
16544         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16545         var matches = re.exec(unescape(cookie));
16546         if(!matches || !matches[1]) {
16547             return; // non state cookie
16548         }
16549         var type = matches[1];
16550         var v = matches[2];
16551         switch(type){
16552             case "n":
16553                 return parseFloat(v);
16554             case "d":
16555                 return new Date(Date.parse(v));
16556             case "b":
16557                 return (v == "1");
16558             case "a":
16559                 var all = [];
16560                 var values = v.split("^");
16561                 for(var i = 0, len = values.length; i < len; i++){
16562                     all.push(this.decodeValue(values[i]));
16563                 }
16564                 return all;
16565            case "o":
16566                 var all = {};
16567                 var values = v.split("^");
16568                 for(var i = 0, len = values.length; i < len; i++){
16569                     var kv = values[i].split("=");
16570                     all[kv[0]] = this.decodeValue(kv[1]);
16571                 }
16572                 return all;
16573            default:
16574                 return v;
16575         }
16576     },
16577     
16578     /**
16579      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16580      * @param {Mixed} value The value to encode
16581      * @return {String} The encoded value
16582      */
16583     encodeValue : function(v){
16584         var enc;
16585         if(typeof v == "number"){
16586             enc = "n:" + v;
16587         }else if(typeof v == "boolean"){
16588             enc = "b:" + (v ? "1" : "0");
16589         }else if(v instanceof Date){
16590             enc = "d:" + v.toGMTString();
16591         }else if(v instanceof Array){
16592             var flat = "";
16593             for(var i = 0, len = v.length; i < len; i++){
16594                 flat += this.encodeValue(v[i]);
16595                 if(i != len-1) {
16596                     flat += "^";
16597                 }
16598             }
16599             enc = "a:" + flat;
16600         }else if(typeof v == "object"){
16601             var flat = "";
16602             for(var key in v){
16603                 if(typeof v[key] != "function"){
16604                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16605                 }
16606             }
16607             enc = "o:" + flat.substring(0, flat.length-1);
16608         }else{
16609             enc = "s:" + v;
16610         }
16611         return escape(enc);        
16612     }
16613 });
16614
16615 /*
16616  * Based on:
16617  * Ext JS Library 1.1.1
16618  * Copyright(c) 2006-2007, Ext JS, LLC.
16619  *
16620  * Originally Released Under LGPL - original licence link has changed is not relivant.
16621  *
16622  * Fork - LGPL
16623  * <script type="text/javascript">
16624  */
16625 /**
16626  * @class Roo.state.Manager
16627  * This is the global state manager. By default all components that are "state aware" check this class
16628  * for state information if you don't pass them a custom state provider. In order for this class
16629  * to be useful, it must be initialized with a provider when your application initializes.
16630  <pre><code>
16631 // in your initialization function
16632 init : function(){
16633    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16634    ...
16635    // supposed you have a {@link Roo.BorderLayout}
16636    var layout = new Roo.BorderLayout(...);
16637    layout.restoreState();
16638    // or a {Roo.BasicDialog}
16639    var dialog = new Roo.BasicDialog(...);
16640    dialog.restoreState();
16641  </code></pre>
16642  * @static
16643  */
16644 Roo.state.Manager = function(){
16645     var provider = new Roo.state.Provider();
16646     
16647     return {
16648         /**
16649          * Configures the default state provider for your application
16650          * @param {Provider} stateProvider The state provider to set
16651          */
16652         setProvider : function(stateProvider){
16653             provider = stateProvider;
16654         },
16655         
16656         /**
16657          * Returns the current value for a key
16658          * @param {String} name The key name
16659          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16660          * @return {Mixed} The state data
16661          */
16662         get : function(key, defaultValue){
16663             return provider.get(key, defaultValue);
16664         },
16665         
16666         /**
16667          * Sets the value for a key
16668          * @param {String} name The key name
16669          * @param {Mixed} value The state data
16670          */
16671          set : function(key, value){
16672             provider.set(key, value);
16673         },
16674         
16675         /**
16676          * Clears a value from the state
16677          * @param {String} name The key name
16678          */
16679         clear : function(key){
16680             provider.clear(key);
16681         },
16682         
16683         /**
16684          * Gets the currently configured state provider
16685          * @return {Provider} The state provider
16686          */
16687         getProvider : function(){
16688             return provider;
16689         }
16690     };
16691 }();
16692 /*
16693  * Based on:
16694  * Ext JS Library 1.1.1
16695  * Copyright(c) 2006-2007, Ext JS, LLC.
16696  *
16697  * Originally Released Under LGPL - original licence link has changed is not relivant.
16698  *
16699  * Fork - LGPL
16700  * <script type="text/javascript">
16701  */
16702 /**
16703  * @class Roo.state.CookieProvider
16704  * @extends Roo.state.Provider
16705  * The default Provider implementation which saves state via cookies.
16706  * <br />Usage:
16707  <pre><code>
16708    var cp = new Roo.state.CookieProvider({
16709        path: "/cgi-bin/",
16710        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16711        domain: "roojs.com"
16712    })
16713    Roo.state.Manager.setProvider(cp);
16714  </code></pre>
16715  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16716  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16717  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16718  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16719  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16720  * domain the page is running on including the 'www' like 'www.roojs.com')
16721  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16722  * @constructor
16723  * Create a new CookieProvider
16724  * @param {Object} config The configuration object
16725  */
16726 Roo.state.CookieProvider = function(config){
16727     Roo.state.CookieProvider.superclass.constructor.call(this);
16728     this.path = "/";
16729     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16730     this.domain = null;
16731     this.secure = false;
16732     Roo.apply(this, config);
16733     this.state = this.readCookies();
16734 };
16735
16736 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16737     // private
16738     set : function(name, value){
16739         if(typeof value == "undefined" || value === null){
16740             this.clear(name);
16741             return;
16742         }
16743         this.setCookie(name, value);
16744         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16745     },
16746
16747     // private
16748     clear : function(name){
16749         this.clearCookie(name);
16750         Roo.state.CookieProvider.superclass.clear.call(this, name);
16751     },
16752
16753     // private
16754     readCookies : function(){
16755         var cookies = {};
16756         var c = document.cookie + ";";
16757         var re = /\s?(.*?)=(.*?);/g;
16758         var matches;
16759         while((matches = re.exec(c)) != null){
16760             var name = matches[1];
16761             var value = matches[2];
16762             if(name && name.substring(0,3) == "ys-"){
16763                 cookies[name.substr(3)] = this.decodeValue(value);
16764             }
16765         }
16766         return cookies;
16767     },
16768
16769     // private
16770     setCookie : function(name, value){
16771         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16772            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16773            ((this.path == null) ? "" : ("; path=" + this.path)) +
16774            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16775            ((this.secure == true) ? "; secure" : "");
16776     },
16777
16778     // private
16779     clearCookie : function(name){
16780         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16781            ((this.path == null) ? "" : ("; path=" + this.path)) +
16782            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16783            ((this.secure == true) ? "; secure" : "");
16784     }
16785 });/*
16786  * Based on:
16787  * Ext JS Library 1.1.1
16788  * Copyright(c) 2006-2007, Ext JS, LLC.
16789  *
16790  * Originally Released Under LGPL - original licence link has changed is not relivant.
16791  *
16792  * Fork - LGPL
16793  * <script type="text/javascript">
16794  */
16795  
16796
16797 /**
16798  * @class Roo.ComponentMgr
16799  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16800  * @static
16801  */
16802 Roo.ComponentMgr = function(){
16803     var all = new Roo.util.MixedCollection();
16804
16805     return {
16806         /**
16807          * Registers a component.
16808          * @param {Roo.Component} c The component
16809          */
16810         register : function(c){
16811             all.add(c);
16812         },
16813
16814         /**
16815          * Unregisters a component.
16816          * @param {Roo.Component} c The component
16817          */
16818         unregister : function(c){
16819             all.remove(c);
16820         },
16821
16822         /**
16823          * Returns a component by id
16824          * @param {String} id The component id
16825          */
16826         get : function(id){
16827             return all.get(id);
16828         },
16829
16830         /**
16831          * Registers a function that will be called when a specified component is added to ComponentMgr
16832          * @param {String} id The component id
16833          * @param {Funtction} fn The callback function
16834          * @param {Object} scope The scope of the callback
16835          */
16836         onAvailable : function(id, fn, scope){
16837             all.on("add", function(index, o){
16838                 if(o.id == id){
16839                     fn.call(scope || o, o);
16840                     all.un("add", fn, scope);
16841                 }
16842             });
16843         }
16844     };
16845 }();/*
16846  * Based on:
16847  * Ext JS Library 1.1.1
16848  * Copyright(c) 2006-2007, Ext JS, LLC.
16849  *
16850  * Originally Released Under LGPL - original licence link has changed is not relivant.
16851  *
16852  * Fork - LGPL
16853  * <script type="text/javascript">
16854  */
16855  
16856 /**
16857  * @class Roo.Component
16858  * @extends Roo.util.Observable
16859  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16860  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16861  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16862  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16863  * All visual components (widgets) that require rendering into a layout should subclass Component.
16864  * @constructor
16865  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16866  * 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
16867  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16868  */
16869 Roo.Component = function(config){
16870     console.log("COMPONENT CONSTRUCTOR");
16871     console.log(config);
16872     config = config || {};
16873     if(config.tagName || config.dom || typeof config == "string"){ // element object
16874         config = {el: config, id: config.id || config};
16875     }
16876     this.initialConfig = config;
16877
16878     Roo.apply(this, config);
16879     this.addEvents({
16880         /**
16881          * @event disable
16882          * Fires after the component is disabled.
16883              * @param {Roo.Component} this
16884              */
16885         disable : true,
16886         /**
16887          * @event enable
16888          * Fires after the component is enabled.
16889              * @param {Roo.Component} this
16890              */
16891         enable : true,
16892         /**
16893          * @event beforeshow
16894          * Fires before the component is shown.  Return false to stop the show.
16895              * @param {Roo.Component} this
16896              */
16897         beforeshow : true,
16898         /**
16899          * @event show
16900          * Fires after the component is shown.
16901              * @param {Roo.Component} this
16902              */
16903         show : true,
16904         /**
16905          * @event beforehide
16906          * Fires before the component is hidden. Return false to stop the hide.
16907              * @param {Roo.Component} this
16908              */
16909         beforehide : true,
16910         /**
16911          * @event hide
16912          * Fires after the component is hidden.
16913              * @param {Roo.Component} this
16914              */
16915         hide : true,
16916         /**
16917          * @event beforerender
16918          * Fires before the component is rendered. Return false to stop the render.
16919              * @param {Roo.Component} this
16920              */
16921         beforerender : true,
16922         /**
16923          * @event render
16924          * Fires after the component is rendered.
16925              * @param {Roo.Component} this
16926              */
16927         render : true,
16928         /**
16929          * @event beforedestroy
16930          * Fires before the component is destroyed. Return false to stop the destroy.
16931              * @param {Roo.Component} this
16932              */
16933         beforedestroy : true,
16934         /**
16935          * @event destroy
16936          * Fires after the component is destroyed.
16937              * @param {Roo.Component} this
16938              */
16939         destroy : true
16940     });
16941     if(!this.id){
16942         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16943     }
16944     Roo.ComponentMgr.register(this);
16945     Roo.Component.superclass.constructor.call(this);
16946     this.initComponent();
16947     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16948         this.render(this.renderTo);
16949         delete this.renderTo;
16950     }
16951 };
16952
16953 /** @private */
16954 Roo.Component.AUTO_ID = 1000;
16955
16956 Roo.extend(Roo.Component, Roo.util.Observable, {
16957     /**
16958      * @scope Roo.Component.prototype
16959      * @type {Boolean}
16960      * true if this component is hidden. Read-only.
16961      */
16962     hidden : false,
16963     /**
16964      * @type {Boolean}
16965      * true if this component is disabled. Read-only.
16966      */
16967     disabled : false,
16968     /**
16969      * @type {Boolean}
16970      * true if this component has been rendered. Read-only.
16971      */
16972     rendered : false,
16973     
16974     /** @cfg {String} disableClass
16975      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16976      */
16977     disabledClass : "x-item-disabled",
16978         /** @cfg {Boolean} allowDomMove
16979          * Whether the component can move the Dom node when rendering (defaults to true).
16980          */
16981     allowDomMove : true,
16982     /** @cfg {String} hideMode (display|visibility)
16983      * How this component should hidden. Supported values are
16984      * "visibility" (css visibility), "offsets" (negative offset position) and
16985      * "display" (css display) - defaults to "display".
16986      */
16987     hideMode: 'display',
16988
16989     /** @private */
16990     ctype : "Roo.Component",
16991
16992     /**
16993      * @cfg {String} actionMode 
16994      * which property holds the element that used for  hide() / show() / disable() / enable()
16995      * default is 'el' for forms you probably want to set this to fieldEl 
16996      */
16997     actionMode : "el",
16998
16999     /** @private */
17000     getActionEl : function(){
17001         return this[this.actionMode];
17002     },
17003
17004     initComponent : Roo.emptyFn,
17005     /**
17006      * If this is a lazy rendering component, render it to its container element.
17007      * @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.
17008      */
17009     render : function(container, position){
17010         
17011         if(this.rendered){
17012             return this;
17013         }
17014         
17015         if(this.fireEvent("beforerender", this) === false){
17016             return false;
17017         }
17018         
17019         if(!container && this.el){
17020             this.el = Roo.get(this.el);
17021             container = this.el.dom.parentNode;
17022             this.allowDomMove = false;
17023         }
17024         this.container = Roo.get(container);
17025         this.rendered = true;
17026         if(position !== undefined){
17027             if(typeof position == 'number'){
17028                 position = this.container.dom.childNodes[position];
17029             }else{
17030                 position = Roo.getDom(position);
17031             }
17032         }
17033         this.onRender(this.container, position || null);
17034         if(this.cls){
17035             this.el.addClass(this.cls);
17036             delete this.cls;
17037         }
17038         if(this.style){
17039             this.el.applyStyles(this.style);
17040             delete this.style;
17041         }
17042         this.fireEvent("render", this);
17043         this.afterRender(this.container);
17044         if(this.hidden){
17045             this.hide();
17046         }
17047         if(this.disabled){
17048             this.disable();
17049         }
17050
17051         return this;
17052         
17053     },
17054
17055     /** @private */
17056     // default function is not really useful
17057     onRender : function(ct, position){
17058         if(this.el){
17059             this.el = Roo.get(this.el);
17060             if(this.allowDomMove !== false){
17061                 ct.dom.insertBefore(this.el.dom, position);
17062             }
17063         }
17064     },
17065
17066     /** @private */
17067     getAutoCreate : function(){
17068         var cfg = typeof this.autoCreate == "object" ?
17069                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17070         if(this.id && !cfg.id){
17071             cfg.id = this.id;
17072         }
17073         return cfg;
17074     },
17075
17076     /** @private */
17077     afterRender : Roo.emptyFn,
17078
17079     /**
17080      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17081      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17082      */
17083     destroy : function(){
17084         if(this.fireEvent("beforedestroy", this) !== false){
17085             this.purgeListeners();
17086             this.beforeDestroy();
17087             if(this.rendered){
17088                 this.el.removeAllListeners();
17089                 this.el.remove();
17090                 if(this.actionMode == "container"){
17091                     this.container.remove();
17092                 }
17093             }
17094             this.onDestroy();
17095             Roo.ComponentMgr.unregister(this);
17096             this.fireEvent("destroy", this);
17097         }
17098     },
17099
17100         /** @private */
17101     beforeDestroy : function(){
17102
17103     },
17104
17105         /** @private */
17106         onDestroy : function(){
17107
17108     },
17109
17110     /**
17111      * Returns the underlying {@link Roo.Element}.
17112      * @return {Roo.Element} The element
17113      */
17114     getEl : function(){
17115         return this.el;
17116     },
17117
17118     /**
17119      * Returns the id of this component.
17120      * @return {String}
17121      */
17122     getId : function(){
17123         return this.id;
17124     },
17125
17126     /**
17127      * Try to focus this component.
17128      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17129      * @return {Roo.Component} this
17130      */
17131     focus : function(selectText){
17132         if(this.rendered){
17133             this.el.focus();
17134             if(selectText === true){
17135                 this.el.dom.select();
17136             }
17137         }
17138         return this;
17139     },
17140
17141     /** @private */
17142     blur : function(){
17143         if(this.rendered){
17144             this.el.blur();
17145         }
17146         return this;
17147     },
17148
17149     /**
17150      * Disable this component.
17151      * @return {Roo.Component} this
17152      */
17153     disable : function(){
17154         if(this.rendered){
17155             this.onDisable();
17156         }
17157         this.disabled = true;
17158         this.fireEvent("disable", this);
17159         return this;
17160     },
17161
17162         // private
17163     onDisable : function(){
17164         this.getActionEl().addClass(this.disabledClass);
17165         this.el.dom.disabled = true;
17166     },
17167
17168     /**
17169      * Enable this component.
17170      * @return {Roo.Component} this
17171      */
17172     enable : function(){
17173         if(this.rendered){
17174             this.onEnable();
17175         }
17176         this.disabled = false;
17177         this.fireEvent("enable", this);
17178         return this;
17179     },
17180
17181         // private
17182     onEnable : function(){
17183         this.getActionEl().removeClass(this.disabledClass);
17184         this.el.dom.disabled = false;
17185     },
17186
17187     /**
17188      * Convenience function for setting disabled/enabled by boolean.
17189      * @param {Boolean} disabled
17190      */
17191     setDisabled : function(disabled){
17192         this[disabled ? "disable" : "enable"]();
17193     },
17194
17195     /**
17196      * Show this component.
17197      * @return {Roo.Component} this
17198      */
17199     show: function(){
17200         if(this.fireEvent("beforeshow", this) !== false){
17201             this.hidden = false;
17202             if(this.rendered){
17203                 this.onShow();
17204             }
17205             this.fireEvent("show", this);
17206         }
17207         return this;
17208     },
17209
17210     // private
17211     onShow : function(){
17212         var ae = this.getActionEl();
17213         if(this.hideMode == 'visibility'){
17214             ae.dom.style.visibility = "visible";
17215         }else if(this.hideMode == 'offsets'){
17216             ae.removeClass('x-hidden');
17217         }else{
17218             ae.dom.style.display = "";
17219         }
17220     },
17221
17222     /**
17223      * Hide this component.
17224      * @return {Roo.Component} this
17225      */
17226     hide: function(){
17227         if(this.fireEvent("beforehide", this) !== false){
17228             this.hidden = true;
17229             if(this.rendered){
17230                 this.onHide();
17231             }
17232             this.fireEvent("hide", this);
17233         }
17234         return this;
17235     },
17236
17237     // private
17238     onHide : function(){
17239         var ae = this.getActionEl();
17240         if(this.hideMode == 'visibility'){
17241             ae.dom.style.visibility = "hidden";
17242         }else if(this.hideMode == 'offsets'){
17243             ae.addClass('x-hidden');
17244         }else{
17245             ae.dom.style.display = "none";
17246         }
17247     },
17248
17249     /**
17250      * Convenience function to hide or show this component by boolean.
17251      * @param {Boolean} visible True to show, false to hide
17252      * @return {Roo.Component} this
17253      */
17254     setVisible: function(visible){
17255         if(visible) {
17256             this.show();
17257         }else{
17258             this.hide();
17259         }
17260         return this;
17261     },
17262
17263     /**
17264      * Returns true if this component is visible.
17265      */
17266     isVisible : function(){
17267         return this.getActionEl().isVisible();
17268     },
17269
17270     cloneConfig : function(overrides){
17271         overrides = overrides || {};
17272         var id = overrides.id || Roo.id();
17273         var cfg = Roo.applyIf(overrides, this.initialConfig);
17274         cfg.id = id; // prevent dup id
17275         return new this.constructor(cfg);
17276     }
17277 });/*
17278  * Based on:
17279  * Ext JS Library 1.1.1
17280  * Copyright(c) 2006-2007, Ext JS, LLC.
17281  *
17282  * Originally Released Under LGPL - original licence link has changed is not relivant.
17283  *
17284  * Fork - LGPL
17285  * <script type="text/javascript">
17286  */
17287
17288 /**
17289  * @class Roo.BoxComponent
17290  * @extends Roo.Component
17291  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17292  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17293  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17294  * layout containers.
17295  * @constructor
17296  * @param {Roo.Element/String/Object} config The configuration options.
17297  */
17298 Roo.BoxComponent = function(config){
17299     Roo.Component.call(this, config);
17300     this.addEvents({
17301         /**
17302          * @event resize
17303          * Fires after the component is resized.
17304              * @param {Roo.Component} this
17305              * @param {Number} adjWidth The box-adjusted width that was set
17306              * @param {Number} adjHeight The box-adjusted height that was set
17307              * @param {Number} rawWidth The width that was originally specified
17308              * @param {Number} rawHeight The height that was originally specified
17309              */
17310         resize : true,
17311         /**
17312          * @event move
17313          * Fires after the component is moved.
17314              * @param {Roo.Component} this
17315              * @param {Number} x The new x position
17316              * @param {Number} y The new y position
17317              */
17318         move : true
17319     });
17320 };
17321
17322 Roo.extend(Roo.BoxComponent, Roo.Component, {
17323     // private, set in afterRender to signify that the component has been rendered
17324     boxReady : false,
17325     // private, used to defer height settings to subclasses
17326     deferHeight: false,
17327     /** @cfg {Number} width
17328      * width (optional) size of component
17329      */
17330      /** @cfg {Number} height
17331      * height (optional) size of component
17332      */
17333      
17334     /**
17335      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17336      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17337      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17338      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17339      * @return {Roo.BoxComponent} this
17340      */
17341     setSize : function(w, h){
17342         // support for standard size objects
17343         if(typeof w == 'object'){
17344             h = w.height;
17345             w = w.width;
17346         }
17347         // not rendered
17348         if(!this.boxReady){
17349             this.width = w;
17350             this.height = h;
17351             return this;
17352         }
17353
17354         // prevent recalcs when not needed
17355         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17356             return this;
17357         }
17358         this.lastSize = {width: w, height: h};
17359
17360         var adj = this.adjustSize(w, h);
17361         var aw = adj.width, ah = adj.height;
17362         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17363             var rz = this.getResizeEl();
17364             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17365                 rz.setSize(aw, ah);
17366             }else if(!this.deferHeight && ah !== undefined){
17367                 rz.setHeight(ah);
17368             }else if(aw !== undefined){
17369                 rz.setWidth(aw);
17370             }
17371             this.onResize(aw, ah, w, h);
17372             this.fireEvent('resize', this, aw, ah, w, h);
17373         }
17374         return this;
17375     },
17376
17377     /**
17378      * Gets the current size of the component's underlying element.
17379      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17380      */
17381     getSize : function(){
17382         return this.el.getSize();
17383     },
17384
17385     /**
17386      * Gets the current XY position of the component's underlying element.
17387      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17388      * @return {Array} The XY position of the element (e.g., [100, 200])
17389      */
17390     getPosition : function(local){
17391         if(local === true){
17392             return [this.el.getLeft(true), this.el.getTop(true)];
17393         }
17394         return this.xy || this.el.getXY();
17395     },
17396
17397     /**
17398      * Gets the current box measurements of the component's underlying element.
17399      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17400      * @returns {Object} box An object in the format {x, y, width, height}
17401      */
17402     getBox : function(local){
17403         var s = this.el.getSize();
17404         if(local){
17405             s.x = this.el.getLeft(true);
17406             s.y = this.el.getTop(true);
17407         }else{
17408             var xy = this.xy || this.el.getXY();
17409             s.x = xy[0];
17410             s.y = xy[1];
17411         }
17412         return s;
17413     },
17414
17415     /**
17416      * Sets the current box measurements of the component's underlying element.
17417      * @param {Object} box An object in the format {x, y, width, height}
17418      * @returns {Roo.BoxComponent} this
17419      */
17420     updateBox : function(box){
17421         this.setSize(box.width, box.height);
17422         this.setPagePosition(box.x, box.y);
17423         return this;
17424     },
17425
17426     // protected
17427     getResizeEl : function(){
17428         return this.resizeEl || this.el;
17429     },
17430
17431     // protected
17432     getPositionEl : function(){
17433         return this.positionEl || this.el;
17434     },
17435
17436     /**
17437      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17438      * This method fires the move event.
17439      * @param {Number} left The new left
17440      * @param {Number} top The new top
17441      * @returns {Roo.BoxComponent} this
17442      */
17443     setPosition : function(x, y){
17444         this.x = x;
17445         this.y = y;
17446         if(!this.boxReady){
17447             return this;
17448         }
17449         var adj = this.adjustPosition(x, y);
17450         var ax = adj.x, ay = adj.y;
17451
17452         var el = this.getPositionEl();
17453         if(ax !== undefined || ay !== undefined){
17454             if(ax !== undefined && ay !== undefined){
17455                 el.setLeftTop(ax, ay);
17456             }else if(ax !== undefined){
17457                 el.setLeft(ax);
17458             }else if(ay !== undefined){
17459                 el.setTop(ay);
17460             }
17461             this.onPosition(ax, ay);
17462             this.fireEvent('move', this, ax, ay);
17463         }
17464         return this;
17465     },
17466
17467     /**
17468      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17469      * This method fires the move event.
17470      * @param {Number} x The new x position
17471      * @param {Number} y The new y position
17472      * @returns {Roo.BoxComponent} this
17473      */
17474     setPagePosition : function(x, y){
17475         this.pageX = x;
17476         this.pageY = y;
17477         if(!this.boxReady){
17478             return;
17479         }
17480         if(x === undefined || y === undefined){ // cannot translate undefined points
17481             return;
17482         }
17483         var p = this.el.translatePoints(x, y);
17484         this.setPosition(p.left, p.top);
17485         return this;
17486     },
17487
17488     // private
17489     onRender : function(ct, position){
17490         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17491         if(this.resizeEl){
17492             this.resizeEl = Roo.get(this.resizeEl);
17493         }
17494         if(this.positionEl){
17495             this.positionEl = Roo.get(this.positionEl);
17496         }
17497     },
17498
17499     // private
17500     afterRender : function(){
17501         Roo.BoxComponent.superclass.afterRender.call(this);
17502         this.boxReady = true;
17503         this.setSize(this.width, this.height);
17504         if(this.x || this.y){
17505             this.setPosition(this.x, this.y);
17506         }
17507         if(this.pageX || this.pageY){
17508             this.setPagePosition(this.pageX, this.pageY);
17509         }
17510     },
17511
17512     /**
17513      * Force the component's size to recalculate based on the underlying element's current height and width.
17514      * @returns {Roo.BoxComponent} this
17515      */
17516     syncSize : function(){
17517         delete this.lastSize;
17518         this.setSize(this.el.getWidth(), this.el.getHeight());
17519         return this;
17520     },
17521
17522     /**
17523      * Called after the component is resized, this method is empty by default but can be implemented by any
17524      * subclass that needs to perform custom logic after a resize occurs.
17525      * @param {Number} adjWidth The box-adjusted width that was set
17526      * @param {Number} adjHeight The box-adjusted height that was set
17527      * @param {Number} rawWidth The width that was originally specified
17528      * @param {Number} rawHeight The height that was originally specified
17529      */
17530     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17531
17532     },
17533
17534     /**
17535      * Called after the component is moved, this method is empty by default but can be implemented by any
17536      * subclass that needs to perform custom logic after a move occurs.
17537      * @param {Number} x The new x position
17538      * @param {Number} y The new y position
17539      */
17540     onPosition : function(x, y){
17541
17542     },
17543
17544     // private
17545     adjustSize : function(w, h){
17546         if(this.autoWidth){
17547             w = 'auto';
17548         }
17549         if(this.autoHeight){
17550             h = 'auto';
17551         }
17552         return {width : w, height: h};
17553     },
17554
17555     // private
17556     adjustPosition : function(x, y){
17557         return {x : x, y: y};
17558     }
17559 });/*
17560  * Based on:
17561  * Ext JS Library 1.1.1
17562  * Copyright(c) 2006-2007, Ext JS, LLC.
17563  *
17564  * Originally Released Under LGPL - original licence link has changed is not relivant.
17565  *
17566  * Fork - LGPL
17567  * <script type="text/javascript">
17568  */
17569  (function(){ 
17570 /**
17571  * @class Roo.Layer
17572  * @extends Roo.Element
17573  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17574  * automatic maintaining of shadow/shim positions.
17575  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17576  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17577  * you can pass a string with a CSS class name. False turns off the shadow.
17578  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17579  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17580  * @cfg {String} cls CSS class to add to the element
17581  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17582  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17583  * @constructor
17584  * @param {Object} config An object with config options.
17585  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17586  */
17587
17588 Roo.Layer = function(config, existingEl){
17589     config = config || {};
17590     var dh = Roo.DomHelper;
17591     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17592     if(existingEl){
17593         this.dom = Roo.getDom(existingEl);
17594     }
17595     if(!this.dom){
17596         var o = config.dh || {tag: "div", cls: "x-layer"};
17597         this.dom = dh.append(pel, o);
17598     }
17599     if(config.cls){
17600         this.addClass(config.cls);
17601     }
17602     this.constrain = config.constrain !== false;
17603     this.visibilityMode = Roo.Element.VISIBILITY;
17604     if(config.id){
17605         this.id = this.dom.id = config.id;
17606     }else{
17607         this.id = Roo.id(this.dom);
17608     }
17609     this.zindex = config.zindex || this.getZIndex();
17610     this.position("absolute", this.zindex);
17611     if(config.shadow){
17612         this.shadowOffset = config.shadowOffset || 4;
17613         this.shadow = new Roo.Shadow({
17614             offset : this.shadowOffset,
17615             mode : config.shadow
17616         });
17617     }else{
17618         this.shadowOffset = 0;
17619     }
17620     this.useShim = config.shim !== false && Roo.useShims;
17621     this.useDisplay = config.useDisplay;
17622     this.hide();
17623 };
17624
17625 var supr = Roo.Element.prototype;
17626
17627 // shims are shared among layer to keep from having 100 iframes
17628 var shims = [];
17629
17630 Roo.extend(Roo.Layer, Roo.Element, {
17631
17632     getZIndex : function(){
17633         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17634     },
17635
17636     getShim : function(){
17637         if(!this.useShim){
17638             return null;
17639         }
17640         if(this.shim){
17641             return this.shim;
17642         }
17643         var shim = shims.shift();
17644         if(!shim){
17645             shim = this.createShim();
17646             shim.enableDisplayMode('block');
17647             shim.dom.style.display = 'none';
17648             shim.dom.style.visibility = 'visible';
17649         }
17650         var pn = this.dom.parentNode;
17651         if(shim.dom.parentNode != pn){
17652             pn.insertBefore(shim.dom, this.dom);
17653         }
17654         shim.setStyle('z-index', this.getZIndex()-2);
17655         this.shim = shim;
17656         return shim;
17657     },
17658
17659     hideShim : function(){
17660         if(this.shim){
17661             this.shim.setDisplayed(false);
17662             shims.push(this.shim);
17663             delete this.shim;
17664         }
17665     },
17666
17667     disableShadow : function(){
17668         if(this.shadow){
17669             this.shadowDisabled = true;
17670             this.shadow.hide();
17671             this.lastShadowOffset = this.shadowOffset;
17672             this.shadowOffset = 0;
17673         }
17674     },
17675
17676     enableShadow : function(show){
17677         if(this.shadow){
17678             this.shadowDisabled = false;
17679             this.shadowOffset = this.lastShadowOffset;
17680             delete this.lastShadowOffset;
17681             if(show){
17682                 this.sync(true);
17683             }
17684         }
17685     },
17686
17687     // private
17688     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17689     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17690     sync : function(doShow){
17691         var sw = this.shadow;
17692         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17693             var sh = this.getShim();
17694
17695             var w = this.getWidth(),
17696                 h = this.getHeight();
17697
17698             var l = this.getLeft(true),
17699                 t = this.getTop(true);
17700
17701             if(sw && !this.shadowDisabled){
17702                 if(doShow && !sw.isVisible()){
17703                     sw.show(this);
17704                 }else{
17705                     sw.realign(l, t, w, h);
17706                 }
17707                 if(sh){
17708                     if(doShow){
17709                        sh.show();
17710                     }
17711                     // fit the shim behind the shadow, so it is shimmed too
17712                     var a = sw.adjusts, s = sh.dom.style;
17713                     s.left = (Math.min(l, l+a.l))+"px";
17714                     s.top = (Math.min(t, t+a.t))+"px";
17715                     s.width = (w+a.w)+"px";
17716                     s.height = (h+a.h)+"px";
17717                 }
17718             }else if(sh){
17719                 if(doShow){
17720                    sh.show();
17721                 }
17722                 sh.setSize(w, h);
17723                 sh.setLeftTop(l, t);
17724             }
17725             
17726         }
17727     },
17728
17729     // private
17730     destroy : function(){
17731         this.hideShim();
17732         if(this.shadow){
17733             this.shadow.hide();
17734         }
17735         this.removeAllListeners();
17736         var pn = this.dom.parentNode;
17737         if(pn){
17738             pn.removeChild(this.dom);
17739         }
17740         Roo.Element.uncache(this.id);
17741     },
17742
17743     remove : function(){
17744         this.destroy();
17745     },
17746
17747     // private
17748     beginUpdate : function(){
17749         this.updating = true;
17750     },
17751
17752     // private
17753     endUpdate : function(){
17754         this.updating = false;
17755         this.sync(true);
17756     },
17757
17758     // private
17759     hideUnders : function(negOffset){
17760         if(this.shadow){
17761             this.shadow.hide();
17762         }
17763         this.hideShim();
17764     },
17765
17766     // private
17767     constrainXY : function(){
17768         if(this.constrain){
17769             var vw = Roo.lib.Dom.getViewWidth(),
17770                 vh = Roo.lib.Dom.getViewHeight();
17771             var s = Roo.get(document).getScroll();
17772
17773             var xy = this.getXY();
17774             var x = xy[0], y = xy[1];   
17775             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17776             // only move it if it needs it
17777             var moved = false;
17778             // first validate right/bottom
17779             if((x + w) > vw+s.left){
17780                 x = vw - w - this.shadowOffset;
17781                 moved = true;
17782             }
17783             if((y + h) > vh+s.top){
17784                 y = vh - h - this.shadowOffset;
17785                 moved = true;
17786             }
17787             // then make sure top/left isn't negative
17788             if(x < s.left){
17789                 x = s.left;
17790                 moved = true;
17791             }
17792             if(y < s.top){
17793                 y = s.top;
17794                 moved = true;
17795             }
17796             if(moved){
17797                 if(this.avoidY){
17798                     var ay = this.avoidY;
17799                     if(y <= ay && (y+h) >= ay){
17800                         y = ay-h-5;   
17801                     }
17802                 }
17803                 xy = [x, y];
17804                 this.storeXY(xy);
17805                 supr.setXY.call(this, xy);
17806                 this.sync();
17807             }
17808         }
17809     },
17810
17811     isVisible : function(){
17812         return this.visible;    
17813     },
17814
17815     // private
17816     showAction : function(){
17817         this.visible = true; // track visibility to prevent getStyle calls
17818         if(this.useDisplay === true){
17819             this.setDisplayed("");
17820         }else if(this.lastXY){
17821             supr.setXY.call(this, this.lastXY);
17822         }else if(this.lastLT){
17823             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17824         }
17825     },
17826
17827     // private
17828     hideAction : function(){
17829         this.visible = false;
17830         if(this.useDisplay === true){
17831             this.setDisplayed(false);
17832         }else{
17833             this.setLeftTop(-10000,-10000);
17834         }
17835     },
17836
17837     // overridden Element method
17838     setVisible : function(v, a, d, c, e){
17839         if(v){
17840             this.showAction();
17841         }
17842         if(a && v){
17843             var cb = function(){
17844                 this.sync(true);
17845                 if(c){
17846                     c();
17847                 }
17848             }.createDelegate(this);
17849             supr.setVisible.call(this, true, true, d, cb, e);
17850         }else{
17851             if(!v){
17852                 this.hideUnders(true);
17853             }
17854             var cb = c;
17855             if(a){
17856                 cb = function(){
17857                     this.hideAction();
17858                     if(c){
17859                         c();
17860                     }
17861                 }.createDelegate(this);
17862             }
17863             supr.setVisible.call(this, v, a, d, cb, e);
17864             if(v){
17865                 this.sync(true);
17866             }else if(!a){
17867                 this.hideAction();
17868             }
17869         }
17870     },
17871
17872     storeXY : function(xy){
17873         delete this.lastLT;
17874         this.lastXY = xy;
17875     },
17876
17877     storeLeftTop : function(left, top){
17878         delete this.lastXY;
17879         this.lastLT = [left, top];
17880     },
17881
17882     // private
17883     beforeFx : function(){
17884         this.beforeAction();
17885         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17886     },
17887
17888     // private
17889     afterFx : function(){
17890         Roo.Layer.superclass.afterFx.apply(this, arguments);
17891         this.sync(this.isVisible());
17892     },
17893
17894     // private
17895     beforeAction : function(){
17896         if(!this.updating && this.shadow){
17897             this.shadow.hide();
17898         }
17899     },
17900
17901     // overridden Element method
17902     setLeft : function(left){
17903         this.storeLeftTop(left, this.getTop(true));
17904         supr.setLeft.apply(this, arguments);
17905         this.sync();
17906     },
17907
17908     setTop : function(top){
17909         this.storeLeftTop(this.getLeft(true), top);
17910         supr.setTop.apply(this, arguments);
17911         this.sync();
17912     },
17913
17914     setLeftTop : function(left, top){
17915         this.storeLeftTop(left, top);
17916         supr.setLeftTop.apply(this, arguments);
17917         this.sync();
17918     },
17919
17920     setXY : function(xy, a, d, c, e){
17921         this.fixDisplay();
17922         this.beforeAction();
17923         this.storeXY(xy);
17924         var cb = this.createCB(c);
17925         supr.setXY.call(this, xy, a, d, cb, e);
17926         if(!a){
17927             cb();
17928         }
17929     },
17930
17931     // private
17932     createCB : function(c){
17933         var el = this;
17934         return function(){
17935             el.constrainXY();
17936             el.sync(true);
17937             if(c){
17938                 c();
17939             }
17940         };
17941     },
17942
17943     // overridden Element method
17944     setX : function(x, a, d, c, e){
17945         this.setXY([x, this.getY()], a, d, c, e);
17946     },
17947
17948     // overridden Element method
17949     setY : function(y, a, d, c, e){
17950         this.setXY([this.getX(), y], a, d, c, e);
17951     },
17952
17953     // overridden Element method
17954     setSize : function(w, h, a, d, c, e){
17955         this.beforeAction();
17956         var cb = this.createCB(c);
17957         supr.setSize.call(this, w, h, a, d, cb, e);
17958         if(!a){
17959             cb();
17960         }
17961     },
17962
17963     // overridden Element method
17964     setWidth : function(w, a, d, c, e){
17965         this.beforeAction();
17966         var cb = this.createCB(c);
17967         supr.setWidth.call(this, w, a, d, cb, e);
17968         if(!a){
17969             cb();
17970         }
17971     },
17972
17973     // overridden Element method
17974     setHeight : function(h, a, d, c, e){
17975         this.beforeAction();
17976         var cb = this.createCB(c);
17977         supr.setHeight.call(this, h, a, d, cb, e);
17978         if(!a){
17979             cb();
17980         }
17981     },
17982
17983     // overridden Element method
17984     setBounds : function(x, y, w, h, a, d, c, e){
17985         this.beforeAction();
17986         var cb = this.createCB(c);
17987         if(!a){
17988             this.storeXY([x, y]);
17989             supr.setXY.call(this, [x, y]);
17990             supr.setSize.call(this, w, h, a, d, cb, e);
17991             cb();
17992         }else{
17993             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17994         }
17995         return this;
17996     },
17997     
17998     /**
17999      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
18000      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
18001      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18002      * @param {Number} zindex The new z-index to set
18003      * @return {this} The Layer
18004      */
18005     setZIndex : function(zindex){
18006         this.zindex = zindex;
18007         this.setStyle("z-index", zindex + 2);
18008         if(this.shadow){
18009             this.shadow.setZIndex(zindex + 1);
18010         }
18011         if(this.shim){
18012             this.shim.setStyle("z-index", zindex);
18013         }
18014     }
18015 });
18016 })();/*
18017  * Original code for Roojs - LGPL
18018  * <script type="text/javascript">
18019  */
18020  
18021 /**
18022  * @class Roo.XComponent
18023  * A delayed Element creator...
18024  * Or a way to group chunks of interface together.
18025  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18026  *  used in conjunction with XComponent.build() it will create an instance of each element,
18027  *  then call addxtype() to build the User interface.
18028  * 
18029  * Mypart.xyx = new Roo.XComponent({
18030
18031     parent : 'Mypart.xyz', // empty == document.element.!!
18032     order : '001',
18033     name : 'xxxx'
18034     region : 'xxxx'
18035     disabled : function() {} 
18036      
18037     tree : function() { // return an tree of xtype declared components
18038         var MODULE = this;
18039         return 
18040         {
18041             xtype : 'NestedLayoutPanel',
18042             // technicall
18043         }
18044      ]
18045  *})
18046  *
18047  *
18048  * It can be used to build a big heiracy, with parent etc.
18049  * or you can just use this to render a single compoent to a dom element
18050  * MYPART.render(Roo.Element | String(id) | dom_element )
18051  *
18052  *
18053  * Usage patterns.
18054  *
18055  * Classic Roo
18056  *
18057  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18058  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18059  *
18060  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18061  *
18062  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18063  * - if mulitple topModules exist, the last one is defined as the top module.
18064  *
18065  * Embeded Roo
18066  * 
18067  * When the top level or multiple modules are to embedded into a existing HTML page,
18068  * the parent element can container '#id' of the element where the module will be drawn.
18069  *
18070  * Bootstrap Roo
18071  *
18072  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18073  * it relies more on a include mechanism, where sub modules are included into an outer page.
18074  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18075  * 
18076  * Bootstrap Roo Included elements
18077  *
18078  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18079  * hence confusing the component builder as it thinks there are multiple top level elements. 
18080  *
18081  * String Over-ride & Translations
18082  *
18083  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18084  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18085  * are needed. @see Roo.XComponent.overlayString  
18086  * 
18087  * 
18088  * 
18089  * @extends Roo.util.Observable
18090  * @constructor
18091  * @param cfg {Object} configuration of component
18092  * 
18093  */
18094 Roo.XComponent = function(cfg) {
18095     Roo.apply(this, cfg);
18096     this.addEvents({ 
18097         /**
18098              * @event built
18099              * Fires when this the componnt is built
18100              * @param {Roo.XComponent} c the component
18101              */
18102         'built' : true
18103         
18104     });
18105     this.region = this.region || 'center'; // default..
18106     Roo.XComponent.register(this);
18107     this.modules = false;
18108     this.el = false; // where the layout goes..
18109     
18110     
18111 }
18112 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18113     /**
18114      * @property el
18115      * The created element (with Roo.factory())
18116      * @type {Roo.Layout}
18117      */
18118     el  : false,
18119     
18120     /**
18121      * @property el
18122      * for BC  - use el in new code
18123      * @type {Roo.Layout}
18124      */
18125     panel : false,
18126     
18127     /**
18128      * @property layout
18129      * for BC  - use el in new code
18130      * @type {Roo.Layout}
18131      */
18132     layout : false,
18133     
18134      /**
18135      * @cfg {Function|boolean} disabled
18136      * If this module is disabled by some rule, return true from the funtion
18137      */
18138     disabled : false,
18139     
18140     /**
18141      * @cfg {String} parent 
18142      * Name of parent element which it get xtype added to..
18143      */
18144     parent: false,
18145     
18146     /**
18147      * @cfg {String} order
18148      * Used to set the order in which elements are created (usefull for multiple tabs)
18149      */
18150     
18151     order : false,
18152     /**
18153      * @cfg {String} name
18154      * String to display while loading.
18155      */
18156     name : false,
18157     /**
18158      * @cfg {String} region
18159      * Region to render component to (defaults to center)
18160      */
18161     region : 'center',
18162     
18163     /**
18164      * @cfg {Array} items
18165      * A single item array - the first element is the root of the tree..
18166      * It's done this way to stay compatible with the Xtype system...
18167      */
18168     items : false,
18169     
18170     /**
18171      * @property _tree
18172      * The method that retuns the tree of parts that make up this compoennt 
18173      * @type {function}
18174      */
18175     _tree  : false,
18176     
18177      /**
18178      * render
18179      * render element to dom or tree
18180      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18181      */
18182     
18183     render : function(el)
18184     {
18185         
18186         el = el || false;
18187         var hp = this.parent ? 1 : 0;
18188         Roo.debug &&  Roo.log(this);
18189         
18190         var tree = this._tree ? this._tree() : this.tree();
18191
18192         
18193         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18194             // if parent is a '#.....' string, then let's use that..
18195             var ename = this.parent.substr(1);
18196             this.parent = false;
18197             Roo.debug && Roo.log(ename);
18198             switch (ename) {
18199                 case 'bootstrap-body':
18200                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18201                         // this is the BorderLayout standard?
18202                        this.parent = { el : true };
18203                        break;
18204                     }
18205                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18206                         // need to insert stuff...
18207                         this.parent =  {
18208                              el : new Roo.bootstrap.layout.Border({
18209                                  el : document.body, 
18210                      
18211                                  center: {
18212                                     titlebar: false,
18213                                     autoScroll:false,
18214                                     closeOnTab: true,
18215                                     tabPosition: 'top',
18216                                       //resizeTabs: true,
18217                                     alwaysShowTabs: true,
18218                                     hideTabs: false
18219                                      //minTabWidth: 140
18220                                  }
18221                              })
18222                         
18223                          };
18224                          break;
18225                     }
18226                          
18227                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18228                         this.parent = { el :  new  Roo.bootstrap.Body() };
18229                         Roo.debug && Roo.log("setting el to doc body");
18230                          
18231                     } else {
18232                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18233                     }
18234                     break;
18235                 case 'bootstrap':
18236                     this.parent = { el : true};
18237                     // fall through
18238                 default:
18239                     el = Roo.get(ename);
18240                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18241                         this.parent = { el : true};
18242                     }
18243                     
18244                     break;
18245             }
18246                 
18247             
18248             if (!el && !this.parent) {
18249                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18250                 return;
18251             }
18252         }
18253         
18254         Roo.debug && Roo.log("EL:");
18255         Roo.debug && Roo.log(el);
18256         Roo.debug && Roo.log("this.parent.el:");
18257         Roo.debug && Roo.log(this.parent.el);
18258         
18259
18260         // altertive root elements ??? - we need a better way to indicate these.
18261         var is_alt = Roo.XComponent.is_alt ||
18262                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18263                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18264                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18265         
18266         
18267         
18268         if (!this.parent && is_alt) {
18269             //el = Roo.get(document.body);
18270             this.parent = { el : true };
18271         }
18272             
18273             
18274         
18275         if (!this.parent) {
18276             
18277             Roo.debug && Roo.log("no parent - creating one");
18278             
18279             el = el ? Roo.get(el) : false;      
18280             
18281             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18282                 
18283                 this.parent =  {
18284                     el : new Roo.bootstrap.layout.Border({
18285                         el: el || document.body,
18286                     
18287                         center: {
18288                             titlebar: false,
18289                             autoScroll:false,
18290                             closeOnTab: true,
18291                             tabPosition: 'top',
18292                              //resizeTabs: true,
18293                             alwaysShowTabs: false,
18294                             hideTabs: true,
18295                             minTabWidth: 140,
18296                             overflow: 'visible'
18297                          }
18298                      })
18299                 };
18300             } else {
18301             
18302                 // it's a top level one..
18303                 this.parent =  {
18304                     el : new Roo.BorderLayout(el || document.body, {
18305                         center: {
18306                             titlebar: false,
18307                             autoScroll:false,
18308                             closeOnTab: true,
18309                             tabPosition: 'top',
18310                              //resizeTabs: true,
18311                             alwaysShowTabs: el && hp? false :  true,
18312                             hideTabs: el || !hp ? true :  false,
18313                             minTabWidth: 140
18314                          }
18315                     })
18316                 };
18317             }
18318         }
18319         
18320         if (!this.parent.el) {
18321                 // probably an old style ctor, which has been disabled.
18322                 return;
18323
18324         }
18325                 // The 'tree' method is  '_tree now' 
18326             
18327         tree.region = tree.region || this.region;
18328         var is_body = false;
18329         if (this.parent.el === true) {
18330             // bootstrap... - body..
18331             if (el) {
18332                 tree.el = el;
18333             }
18334             this.parent.el = Roo.factory(tree);
18335             is_body = true;
18336         }
18337         
18338         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18339         this.fireEvent('built', this);
18340         
18341         this.panel = this.el;
18342         this.layout = this.panel.layout;
18343         this.parentLayout = this.parent.layout  || false;  
18344          
18345     }
18346     
18347 });
18348
18349 Roo.apply(Roo.XComponent, {
18350     /**
18351      * @property  hideProgress
18352      * true to disable the building progress bar.. usefull on single page renders.
18353      * @type Boolean
18354      */
18355     hideProgress : false,
18356     /**
18357      * @property  buildCompleted
18358      * True when the builder has completed building the interface.
18359      * @type Boolean
18360      */
18361     buildCompleted : false,
18362      
18363     /**
18364      * @property  topModule
18365      * the upper most module - uses document.element as it's constructor.
18366      * @type Object
18367      */
18368      
18369     topModule  : false,
18370       
18371     /**
18372      * @property  modules
18373      * array of modules to be created by registration system.
18374      * @type {Array} of Roo.XComponent
18375      */
18376     
18377     modules : [],
18378     /**
18379      * @property  elmodules
18380      * array of modules to be created by which use #ID 
18381      * @type {Array} of Roo.XComponent
18382      */
18383      
18384     elmodules : [],
18385
18386      /**
18387      * @property  is_alt
18388      * Is an alternative Root - normally used by bootstrap or other systems,
18389      *    where the top element in the tree can wrap 'body' 
18390      * @type {boolean}  (default false)
18391      */
18392      
18393     is_alt : false,
18394     /**
18395      * @property  build_from_html
18396      * Build elements from html - used by bootstrap HTML stuff 
18397      *    - this is cleared after build is completed
18398      * @type {boolean}    (default false)
18399      */
18400      
18401     build_from_html : false,
18402     /**
18403      * Register components to be built later.
18404      *
18405      * This solves the following issues
18406      * - Building is not done on page load, but after an authentication process has occured.
18407      * - Interface elements are registered on page load
18408      * - Parent Interface elements may not be loaded before child, so this handles that..
18409      * 
18410      *
18411      * example:
18412      * 
18413      * MyApp.register({
18414           order : '000001',
18415           module : 'Pman.Tab.projectMgr',
18416           region : 'center',
18417           parent : 'Pman.layout',
18418           disabled : false,  // or use a function..
18419         })
18420      
18421      * * @param {Object} details about module
18422      */
18423     register : function(obj) {
18424                 
18425         Roo.XComponent.event.fireEvent('register', obj);
18426         switch(typeof(obj.disabled) ) {
18427                 
18428             case 'undefined':
18429                 break;
18430             
18431             case 'function':
18432                 if ( obj.disabled() ) {
18433                         return;
18434                 }
18435                 break;
18436             
18437             default:
18438                 if (obj.disabled || obj.region == '#disabled') {
18439                         return;
18440                 }
18441                 break;
18442         }
18443                 
18444         this.modules.push(obj);
18445          
18446     },
18447     /**
18448      * convert a string to an object..
18449      * eg. 'AAA.BBB' -> finds AAA.BBB
18450
18451      */
18452     
18453     toObject : function(str)
18454     {
18455         if (!str || typeof(str) == 'object') {
18456             return str;
18457         }
18458         if (str.substring(0,1) == '#') {
18459             return str;
18460         }
18461
18462         var ar = str.split('.');
18463         var rt, o;
18464         rt = ar.shift();
18465             /** eval:var:o */
18466         try {
18467             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18468         } catch (e) {
18469             throw "Module not found : " + str;
18470         }
18471         
18472         if (o === false) {
18473             throw "Module not found : " + str;
18474         }
18475         Roo.each(ar, function(e) {
18476             if (typeof(o[e]) == 'undefined') {
18477                 throw "Module not found : " + str;
18478             }
18479             o = o[e];
18480         });
18481         
18482         return o;
18483         
18484     },
18485     
18486     
18487     /**
18488      * move modules into their correct place in the tree..
18489      * 
18490      */
18491     preBuild : function ()
18492     {
18493         var _t = this;
18494         Roo.each(this.modules , function (obj)
18495         {
18496             Roo.XComponent.event.fireEvent('beforebuild', obj);
18497             
18498             var opar = obj.parent;
18499             try { 
18500                 obj.parent = this.toObject(opar);
18501             } catch(e) {
18502                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18503                 return;
18504             }
18505             
18506             if (!obj.parent) {
18507                 Roo.debug && Roo.log("GOT top level module");
18508                 Roo.debug && Roo.log(obj);
18509                 obj.modules = new Roo.util.MixedCollection(false, 
18510                     function(o) { return o.order + '' }
18511                 );
18512                 this.topModule = obj;
18513                 return;
18514             }
18515                         // parent is a string (usually a dom element name..)
18516             if (typeof(obj.parent) == 'string') {
18517                 this.elmodules.push(obj);
18518                 return;
18519             }
18520             if (obj.parent.constructor != Roo.XComponent) {
18521                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18522             }
18523             if (!obj.parent.modules) {
18524                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18525                     function(o) { return o.order + '' }
18526                 );
18527             }
18528             if (obj.parent.disabled) {
18529                 obj.disabled = true;
18530             }
18531             obj.parent.modules.add(obj);
18532         }, this);
18533     },
18534     
18535      /**
18536      * make a list of modules to build.
18537      * @return {Array} list of modules. 
18538      */ 
18539     
18540     buildOrder : function()
18541     {
18542         var _this = this;
18543         var cmp = function(a,b) {   
18544             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18545         };
18546         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18547             throw "No top level modules to build";
18548         }
18549         
18550         // make a flat list in order of modules to build.
18551         var mods = this.topModule ? [ this.topModule ] : [];
18552                 
18553         
18554         // elmodules (is a list of DOM based modules )
18555         Roo.each(this.elmodules, function(e) {
18556             mods.push(e);
18557             if (!this.topModule &&
18558                 typeof(e.parent) == 'string' &&
18559                 e.parent.substring(0,1) == '#' &&
18560                 Roo.get(e.parent.substr(1))
18561                ) {
18562                 
18563                 _this.topModule = e;
18564             }
18565             
18566         });
18567
18568         
18569         // add modules to their parents..
18570         var addMod = function(m) {
18571             Roo.debug && Roo.log("build Order: add: " + m.name);
18572                 
18573             mods.push(m);
18574             if (m.modules && !m.disabled) {
18575                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18576                 m.modules.keySort('ASC',  cmp );
18577                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18578     
18579                 m.modules.each(addMod);
18580             } else {
18581                 Roo.debug && Roo.log("build Order: no child modules");
18582             }
18583             // not sure if this is used any more..
18584             if (m.finalize) {
18585                 m.finalize.name = m.name + " (clean up) ";
18586                 mods.push(m.finalize);
18587             }
18588             
18589         }
18590         if (this.topModule && this.topModule.modules) { 
18591             this.topModule.modules.keySort('ASC',  cmp );
18592             this.topModule.modules.each(addMod);
18593         } 
18594         return mods;
18595     },
18596     
18597      /**
18598      * Build the registered modules.
18599      * @param {Object} parent element.
18600      * @param {Function} optional method to call after module has been added.
18601      * 
18602      */ 
18603    
18604     build : function(opts) 
18605     {
18606         
18607         if (typeof(opts) != 'undefined') {
18608             Roo.apply(this,opts);
18609         }
18610         
18611         this.preBuild();
18612         var mods = this.buildOrder();
18613       
18614         //this.allmods = mods;
18615         //Roo.debug && Roo.log(mods);
18616         //return;
18617         if (!mods.length) { // should not happen
18618             throw "NO modules!!!";
18619         }
18620         
18621         
18622         var msg = "Building Interface...";
18623         // flash it up as modal - so we store the mask!?
18624         if (!this.hideProgress && Roo.MessageBox) {
18625             Roo.MessageBox.show({ title: 'loading' });
18626             Roo.MessageBox.show({
18627                title: "Please wait...",
18628                msg: msg,
18629                width:450,
18630                progress:true,
18631                buttons : false,
18632                closable:false,
18633                modal: false
18634               
18635             });
18636         }
18637         var total = mods.length;
18638         
18639         var _this = this;
18640         var progressRun = function() {
18641             if (!mods.length) {
18642                 Roo.debug && Roo.log('hide?');
18643                 if (!this.hideProgress && Roo.MessageBox) {
18644                     Roo.MessageBox.hide();
18645                 }
18646                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18647                 
18648                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18649                 
18650                 // THE END...
18651                 return false;   
18652             }
18653             
18654             var m = mods.shift();
18655             
18656             
18657             Roo.debug && Roo.log(m);
18658             // not sure if this is supported any more.. - modules that are are just function
18659             if (typeof(m) == 'function') { 
18660                 m.call(this);
18661                 return progressRun.defer(10, _this);
18662             } 
18663             
18664             
18665             msg = "Building Interface " + (total  - mods.length) + 
18666                     " of " + total + 
18667                     (m.name ? (' - ' + m.name) : '');
18668                         Roo.debug && Roo.log(msg);
18669             if (!_this.hideProgress &&  Roo.MessageBox) { 
18670                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18671             }
18672             
18673          
18674             // is the module disabled?
18675             var disabled = (typeof(m.disabled) == 'function') ?
18676                 m.disabled.call(m.module.disabled) : m.disabled;    
18677             
18678             
18679             if (disabled) {
18680                 return progressRun(); // we do not update the display!
18681             }
18682             
18683             // now build 
18684             
18685                         
18686                         
18687             m.render();
18688             // it's 10 on top level, and 1 on others??? why...
18689             return progressRun.defer(10, _this);
18690              
18691         }
18692         progressRun.defer(1, _this);
18693      
18694         
18695         
18696     },
18697     /**
18698      * Overlay a set of modified strings onto a component
18699      * This is dependant on our builder exporting the strings and 'named strings' elements.
18700      * 
18701      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18702      * @param {Object} associative array of 'named' string and it's new value.
18703      * 
18704      */
18705         overlayStrings : function( component, strings )
18706     {
18707         if (typeof(component['_named_strings']) == 'undefined') {
18708             throw "ERROR: component does not have _named_strings";
18709         }
18710         for ( var k in strings ) {
18711             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18712             if (md !== false) {
18713                 component['_strings'][md] = strings[k];
18714             } else {
18715                 Roo.log('could not find named string: ' + k + ' in');
18716                 Roo.log(component);
18717             }
18718             
18719         }
18720         
18721     },
18722     
18723         
18724         /**
18725          * Event Object.
18726          *
18727          *
18728          */
18729         event: false, 
18730     /**
18731          * wrapper for event.on - aliased later..  
18732          * Typically use to register a event handler for register:
18733          *
18734          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18735          *
18736          */
18737     on : false
18738    
18739     
18740     
18741 });
18742
18743 Roo.XComponent.event = new Roo.util.Observable({
18744                 events : { 
18745                         /**
18746                          * @event register
18747                          * Fires when an Component is registered,
18748                          * set the disable property on the Component to stop registration.
18749                          * @param {Roo.XComponent} c the component being registerd.
18750                          * 
18751                          */
18752                         'register' : true,
18753             /**
18754                          * @event beforebuild
18755                          * Fires before each Component is built
18756                          * can be used to apply permissions.
18757                          * @param {Roo.XComponent} c the component being registerd.
18758                          * 
18759                          */
18760                         'beforebuild' : true,
18761                         /**
18762                          * @event buildcomplete
18763                          * Fires on the top level element when all elements have been built
18764                          * @param {Roo.XComponent} the top level component.
18765                          */
18766                         'buildcomplete' : true
18767                         
18768                 }
18769 });
18770
18771 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18772  //
18773  /**
18774  * marked - a markdown parser
18775  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18776  * https://github.com/chjj/marked
18777  */
18778
18779
18780 /**
18781  *
18782  * Roo.Markdown - is a very crude wrapper around marked..
18783  *
18784  * usage:
18785  * 
18786  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18787  * 
18788  * Note: move the sample code to the bottom of this
18789  * file before uncommenting it.
18790  *
18791  */
18792
18793 Roo.Markdown = {};
18794 Roo.Markdown.toHtml = function(text) {
18795     
18796     var c = new Roo.Markdown.marked.setOptions({
18797             renderer: new Roo.Markdown.marked.Renderer(),
18798             gfm: true,
18799             tables: true,
18800             breaks: false,
18801             pedantic: false,
18802             sanitize: false,
18803             smartLists: true,
18804             smartypants: false
18805           });
18806     // A FEW HACKS!!?
18807     
18808     text = text.replace(/\\\n/g,' ');
18809     return Roo.Markdown.marked(text);
18810 };
18811 //
18812 // converter
18813 //
18814 // Wraps all "globals" so that the only thing
18815 // exposed is makeHtml().
18816 //
18817 (function() {
18818     
18819      /**
18820          * eval:var:escape
18821          * eval:var:unescape
18822          * eval:var:replace
18823          */
18824       
18825     /**
18826      * Helpers
18827      */
18828     
18829     var escape = function (html, encode) {
18830       return html
18831         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18832         .replace(/</g, '&lt;')
18833         .replace(/>/g, '&gt;')
18834         .replace(/"/g, '&quot;')
18835         .replace(/'/g, '&#39;');
18836     }
18837     
18838     var unescape = function (html) {
18839         // explicitly match decimal, hex, and named HTML entities 
18840       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18841         n = n.toLowerCase();
18842         if (n === 'colon') { return ':'; }
18843         if (n.charAt(0) === '#') {
18844           return n.charAt(1) === 'x'
18845             ? String.fromCharCode(parseInt(n.substring(2), 16))
18846             : String.fromCharCode(+n.substring(1));
18847         }
18848         return '';
18849       });
18850     }
18851     
18852     var replace = function (regex, opt) {
18853       regex = regex.source;
18854       opt = opt || '';
18855       return function self(name, val) {
18856         if (!name) { return new RegExp(regex, opt); }
18857         val = val.source || val;
18858         val = val.replace(/(^|[^\[])\^/g, '$1');
18859         regex = regex.replace(name, val);
18860         return self;
18861       };
18862     }
18863
18864
18865          /**
18866          * eval:var:noop
18867     */
18868     var noop = function () {}
18869     noop.exec = noop;
18870     
18871          /**
18872          * eval:var:merge
18873     */
18874     var merge = function (obj) {
18875       var i = 1
18876         , target
18877         , key;
18878     
18879       for (; i < arguments.length; i++) {
18880         target = arguments[i];
18881         for (key in target) {
18882           if (Object.prototype.hasOwnProperty.call(target, key)) {
18883             obj[key] = target[key];
18884           }
18885         }
18886       }
18887     
18888       return obj;
18889     }
18890     
18891     
18892     /**
18893      * Block-Level Grammar
18894      */
18895     
18896     
18897     
18898     
18899     var block = {
18900       newline: /^\n+/,
18901       code: /^( {4}[^\n]+\n*)+/,
18902       fences: noop,
18903       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18904       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18905       nptable: noop,
18906       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18907       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18908       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18909       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18910       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18911       table: noop,
18912       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18913       text: /^[^\n]+/
18914     };
18915     
18916     block.bullet = /(?:[*+-]|\d+\.)/;
18917     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18918     block.item = replace(block.item, 'gm')
18919       (/bull/g, block.bullet)
18920       ();
18921     
18922     block.list = replace(block.list)
18923       (/bull/g, block.bullet)
18924       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18925       ('def', '\\n+(?=' + block.def.source + ')')
18926       ();
18927     
18928     block.blockquote = replace(block.blockquote)
18929       ('def', block.def)
18930       ();
18931     
18932     block._tag = '(?!(?:'
18933       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18934       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18935       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18936     
18937     block.html = replace(block.html)
18938       ('comment', /<!--[\s\S]*?-->/)
18939       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18940       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18941       (/tag/g, block._tag)
18942       ();
18943     
18944     block.paragraph = replace(block.paragraph)
18945       ('hr', block.hr)
18946       ('heading', block.heading)
18947       ('lheading', block.lheading)
18948       ('blockquote', block.blockquote)
18949       ('tag', '<' + block._tag)
18950       ('def', block.def)
18951       ();
18952     
18953     /**
18954      * Normal Block Grammar
18955      */
18956     
18957     block.normal = merge({}, block);
18958     
18959     /**
18960      * GFM Block Grammar
18961      */
18962     
18963     block.gfm = merge({}, block.normal, {
18964       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18965       paragraph: /^/,
18966       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18967     });
18968     
18969     block.gfm.paragraph = replace(block.paragraph)
18970       ('(?!', '(?!'
18971         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18972         + block.list.source.replace('\\1', '\\3') + '|')
18973       ();
18974     
18975     /**
18976      * GFM + Tables Block Grammar
18977      */
18978     
18979     block.tables = merge({}, block.gfm, {
18980       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18981       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18982     });
18983     
18984     /**
18985      * Block Lexer
18986      */
18987     
18988     var Lexer = function (options) {
18989       this.tokens = [];
18990       this.tokens.links = {};
18991       this.options = options || marked.defaults;
18992       this.rules = block.normal;
18993     
18994       if (this.options.gfm) {
18995         if (this.options.tables) {
18996           this.rules = block.tables;
18997         } else {
18998           this.rules = block.gfm;
18999         }
19000       }
19001     }
19002     
19003     /**
19004      * Expose Block Rules
19005      */
19006     
19007     Lexer.rules = block;
19008     
19009     /**
19010      * Static Lex Method
19011      */
19012     
19013     Lexer.lex = function(src, options) {
19014       var lexer = new Lexer(options);
19015       return lexer.lex(src);
19016     };
19017     
19018     /**
19019      * Preprocessing
19020      */
19021     
19022     Lexer.prototype.lex = function(src) {
19023       src = src
19024         .replace(/\r\n|\r/g, '\n')
19025         .replace(/\t/g, '    ')
19026         .replace(/\u00a0/g, ' ')
19027         .replace(/\u2424/g, '\n');
19028     
19029       return this.token(src, true);
19030     };
19031     
19032     /**
19033      * Lexing
19034      */
19035     
19036     Lexer.prototype.token = function(src, top, bq) {
19037       var src = src.replace(/^ +$/gm, '')
19038         , next
19039         , loose
19040         , cap
19041         , bull
19042         , b
19043         , item
19044         , space
19045         , i
19046         , l;
19047     
19048       while (src) {
19049         // newline
19050         if (cap = this.rules.newline.exec(src)) {
19051           src = src.substring(cap[0].length);
19052           if (cap[0].length > 1) {
19053             this.tokens.push({
19054               type: 'space'
19055             });
19056           }
19057         }
19058     
19059         // code
19060         if (cap = this.rules.code.exec(src)) {
19061           src = src.substring(cap[0].length);
19062           cap = cap[0].replace(/^ {4}/gm, '');
19063           this.tokens.push({
19064             type: 'code',
19065             text: !this.options.pedantic
19066               ? cap.replace(/\n+$/, '')
19067               : cap
19068           });
19069           continue;
19070         }
19071     
19072         // fences (gfm)
19073         if (cap = this.rules.fences.exec(src)) {
19074           src = src.substring(cap[0].length);
19075           this.tokens.push({
19076             type: 'code',
19077             lang: cap[2],
19078             text: cap[3] || ''
19079           });
19080           continue;
19081         }
19082     
19083         // heading
19084         if (cap = this.rules.heading.exec(src)) {
19085           src = src.substring(cap[0].length);
19086           this.tokens.push({
19087             type: 'heading',
19088             depth: cap[1].length,
19089             text: cap[2]
19090           });
19091           continue;
19092         }
19093     
19094         // table no leading pipe (gfm)
19095         if (top && (cap = this.rules.nptable.exec(src))) {
19096           src = src.substring(cap[0].length);
19097     
19098           item = {
19099             type: 'table',
19100             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19101             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19102             cells: cap[3].replace(/\n$/, '').split('\n')
19103           };
19104     
19105           for (i = 0; i < item.align.length; i++) {
19106             if (/^ *-+: *$/.test(item.align[i])) {
19107               item.align[i] = 'right';
19108             } else if (/^ *:-+: *$/.test(item.align[i])) {
19109               item.align[i] = 'center';
19110             } else if (/^ *:-+ *$/.test(item.align[i])) {
19111               item.align[i] = 'left';
19112             } else {
19113               item.align[i] = null;
19114             }
19115           }
19116     
19117           for (i = 0; i < item.cells.length; i++) {
19118             item.cells[i] = item.cells[i].split(/ *\| */);
19119           }
19120     
19121           this.tokens.push(item);
19122     
19123           continue;
19124         }
19125     
19126         // lheading
19127         if (cap = this.rules.lheading.exec(src)) {
19128           src = src.substring(cap[0].length);
19129           this.tokens.push({
19130             type: 'heading',
19131             depth: cap[2] === '=' ? 1 : 2,
19132             text: cap[1]
19133           });
19134           continue;
19135         }
19136     
19137         // hr
19138         if (cap = this.rules.hr.exec(src)) {
19139           src = src.substring(cap[0].length);
19140           this.tokens.push({
19141             type: 'hr'
19142           });
19143           continue;
19144         }
19145     
19146         // blockquote
19147         if (cap = this.rules.blockquote.exec(src)) {
19148           src = src.substring(cap[0].length);
19149     
19150           this.tokens.push({
19151             type: 'blockquote_start'
19152           });
19153     
19154           cap = cap[0].replace(/^ *> ?/gm, '');
19155     
19156           // Pass `top` to keep the current
19157           // "toplevel" state. This is exactly
19158           // how markdown.pl works.
19159           this.token(cap, top, true);
19160     
19161           this.tokens.push({
19162             type: 'blockquote_end'
19163           });
19164     
19165           continue;
19166         }
19167     
19168         // list
19169         if (cap = this.rules.list.exec(src)) {
19170           src = src.substring(cap[0].length);
19171           bull = cap[2];
19172     
19173           this.tokens.push({
19174             type: 'list_start',
19175             ordered: bull.length > 1
19176           });
19177     
19178           // Get each top-level item.
19179           cap = cap[0].match(this.rules.item);
19180     
19181           next = false;
19182           l = cap.length;
19183           i = 0;
19184     
19185           for (; i < l; i++) {
19186             item = cap[i];
19187     
19188             // Remove the list item's bullet
19189             // so it is seen as the next token.
19190             space = item.length;
19191             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19192     
19193             // Outdent whatever the
19194             // list item contains. Hacky.
19195             if (~item.indexOf('\n ')) {
19196               space -= item.length;
19197               item = !this.options.pedantic
19198                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19199                 : item.replace(/^ {1,4}/gm, '');
19200             }
19201     
19202             // Determine whether the next list item belongs here.
19203             // Backpedal if it does not belong in this list.
19204             if (this.options.smartLists && i !== l - 1) {
19205               b = block.bullet.exec(cap[i + 1])[0];
19206               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19207                 src = cap.slice(i + 1).join('\n') + src;
19208                 i = l - 1;
19209               }
19210             }
19211     
19212             // Determine whether item is loose or not.
19213             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19214             // for discount behavior.
19215             loose = next || /\n\n(?!\s*$)/.test(item);
19216             if (i !== l - 1) {
19217               next = item.charAt(item.length - 1) === '\n';
19218               if (!loose) { loose = next; }
19219             }
19220     
19221             this.tokens.push({
19222               type: loose
19223                 ? 'loose_item_start'
19224                 : 'list_item_start'
19225             });
19226     
19227             // Recurse.
19228             this.token(item, false, bq);
19229     
19230             this.tokens.push({
19231               type: 'list_item_end'
19232             });
19233           }
19234     
19235           this.tokens.push({
19236             type: 'list_end'
19237           });
19238     
19239           continue;
19240         }
19241     
19242         // html
19243         if (cap = this.rules.html.exec(src)) {
19244           src = src.substring(cap[0].length);
19245           this.tokens.push({
19246             type: this.options.sanitize
19247               ? 'paragraph'
19248               : 'html',
19249             pre: !this.options.sanitizer
19250               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19251             text: cap[0]
19252           });
19253           continue;
19254         }
19255     
19256         // def
19257         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19258           src = src.substring(cap[0].length);
19259           this.tokens.links[cap[1].toLowerCase()] = {
19260             href: cap[2],
19261             title: cap[3]
19262           };
19263           continue;
19264         }
19265     
19266         // table (gfm)
19267         if (top && (cap = this.rules.table.exec(src))) {
19268           src = src.substring(cap[0].length);
19269     
19270           item = {
19271             type: 'table',
19272             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19273             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19274             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19275           };
19276     
19277           for (i = 0; i < item.align.length; i++) {
19278             if (/^ *-+: *$/.test(item.align[i])) {
19279               item.align[i] = 'right';
19280             } else if (/^ *:-+: *$/.test(item.align[i])) {
19281               item.align[i] = 'center';
19282             } else if (/^ *:-+ *$/.test(item.align[i])) {
19283               item.align[i] = 'left';
19284             } else {
19285               item.align[i] = null;
19286             }
19287           }
19288     
19289           for (i = 0; i < item.cells.length; i++) {
19290             item.cells[i] = item.cells[i]
19291               .replace(/^ *\| *| *\| *$/g, '')
19292               .split(/ *\| */);
19293           }
19294     
19295           this.tokens.push(item);
19296     
19297           continue;
19298         }
19299     
19300         // top-level paragraph
19301         if (top && (cap = this.rules.paragraph.exec(src))) {
19302           src = src.substring(cap[0].length);
19303           this.tokens.push({
19304             type: 'paragraph',
19305             text: cap[1].charAt(cap[1].length - 1) === '\n'
19306               ? cap[1].slice(0, -1)
19307               : cap[1]
19308           });
19309           continue;
19310         }
19311     
19312         // text
19313         if (cap = this.rules.text.exec(src)) {
19314           // Top-level should never reach here.
19315           src = src.substring(cap[0].length);
19316           this.tokens.push({
19317             type: 'text',
19318             text: cap[0]
19319           });
19320           continue;
19321         }
19322     
19323         if (src) {
19324           throw new
19325             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19326         }
19327       }
19328     
19329       return this.tokens;
19330     };
19331     
19332     /**
19333      * Inline-Level Grammar
19334      */
19335     
19336     var inline = {
19337       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19338       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19339       url: noop,
19340       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19341       link: /^!?\[(inside)\]\(href\)/,
19342       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19343       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19344       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19345       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19346       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19347       br: /^ {2,}\n(?!\s*$)/,
19348       del: noop,
19349       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19350     };
19351     
19352     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19353     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19354     
19355     inline.link = replace(inline.link)
19356       ('inside', inline._inside)
19357       ('href', inline._href)
19358       ();
19359     
19360     inline.reflink = replace(inline.reflink)
19361       ('inside', inline._inside)
19362       ();
19363     
19364     /**
19365      * Normal Inline Grammar
19366      */
19367     
19368     inline.normal = merge({}, inline);
19369     
19370     /**
19371      * Pedantic Inline Grammar
19372      */
19373     
19374     inline.pedantic = merge({}, inline.normal, {
19375       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19376       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19377     });
19378     
19379     /**
19380      * GFM Inline Grammar
19381      */
19382     
19383     inline.gfm = merge({}, inline.normal, {
19384       escape: replace(inline.escape)('])', '~|])')(),
19385       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19386       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19387       text: replace(inline.text)
19388         (']|', '~]|')
19389         ('|', '|https?://|')
19390         ()
19391     });
19392     
19393     /**
19394      * GFM + Line Breaks Inline Grammar
19395      */
19396     
19397     inline.breaks = merge({}, inline.gfm, {
19398       br: replace(inline.br)('{2,}', '*')(),
19399       text: replace(inline.gfm.text)('{2,}', '*')()
19400     });
19401     
19402     /**
19403      * Inline Lexer & Compiler
19404      */
19405     
19406     var InlineLexer  = function (links, options) {
19407       this.options = options || marked.defaults;
19408       this.links = links;
19409       this.rules = inline.normal;
19410       this.renderer = this.options.renderer || new Renderer;
19411       this.renderer.options = this.options;
19412     
19413       if (!this.links) {
19414         throw new
19415           Error('Tokens array requires a `links` property.');
19416       }
19417     
19418       if (this.options.gfm) {
19419         if (this.options.breaks) {
19420           this.rules = inline.breaks;
19421         } else {
19422           this.rules = inline.gfm;
19423         }
19424       } else if (this.options.pedantic) {
19425         this.rules = inline.pedantic;
19426       }
19427     }
19428     
19429     /**
19430      * Expose Inline Rules
19431      */
19432     
19433     InlineLexer.rules = inline;
19434     
19435     /**
19436      * Static Lexing/Compiling Method
19437      */
19438     
19439     InlineLexer.output = function(src, links, options) {
19440       var inline = new InlineLexer(links, options);
19441       return inline.output(src);
19442     };
19443     
19444     /**
19445      * Lexing/Compiling
19446      */
19447     
19448     InlineLexer.prototype.output = function(src) {
19449       var out = ''
19450         , link
19451         , text
19452         , href
19453         , cap;
19454     
19455       while (src) {
19456         // escape
19457         if (cap = this.rules.escape.exec(src)) {
19458           src = src.substring(cap[0].length);
19459           out += cap[1];
19460           continue;
19461         }
19462     
19463         // autolink
19464         if (cap = this.rules.autolink.exec(src)) {
19465           src = src.substring(cap[0].length);
19466           if (cap[2] === '@') {
19467             text = cap[1].charAt(6) === ':'
19468               ? this.mangle(cap[1].substring(7))
19469               : this.mangle(cap[1]);
19470             href = this.mangle('mailto:') + text;
19471           } else {
19472             text = escape(cap[1]);
19473             href = text;
19474           }
19475           out += this.renderer.link(href, null, text);
19476           continue;
19477         }
19478     
19479         // url (gfm)
19480         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19481           src = src.substring(cap[0].length);
19482           text = escape(cap[1]);
19483           href = text;
19484           out += this.renderer.link(href, null, text);
19485           continue;
19486         }
19487     
19488         // tag
19489         if (cap = this.rules.tag.exec(src)) {
19490           if (!this.inLink && /^<a /i.test(cap[0])) {
19491             this.inLink = true;
19492           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19493             this.inLink = false;
19494           }
19495           src = src.substring(cap[0].length);
19496           out += this.options.sanitize
19497             ? this.options.sanitizer
19498               ? this.options.sanitizer(cap[0])
19499               : escape(cap[0])
19500             : cap[0];
19501           continue;
19502         }
19503     
19504         // link
19505         if (cap = this.rules.link.exec(src)) {
19506           src = src.substring(cap[0].length);
19507           this.inLink = true;
19508           out += this.outputLink(cap, {
19509             href: cap[2],
19510             title: cap[3]
19511           });
19512           this.inLink = false;
19513           continue;
19514         }
19515     
19516         // reflink, nolink
19517         if ((cap = this.rules.reflink.exec(src))
19518             || (cap = this.rules.nolink.exec(src))) {
19519           src = src.substring(cap[0].length);
19520           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19521           link = this.links[link.toLowerCase()];
19522           if (!link || !link.href) {
19523             out += cap[0].charAt(0);
19524             src = cap[0].substring(1) + src;
19525             continue;
19526           }
19527           this.inLink = true;
19528           out += this.outputLink(cap, link);
19529           this.inLink = false;
19530           continue;
19531         }
19532     
19533         // strong
19534         if (cap = this.rules.strong.exec(src)) {
19535           src = src.substring(cap[0].length);
19536           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19537           continue;
19538         }
19539     
19540         // em
19541         if (cap = this.rules.em.exec(src)) {
19542           src = src.substring(cap[0].length);
19543           out += this.renderer.em(this.output(cap[2] || cap[1]));
19544           continue;
19545         }
19546     
19547         // code
19548         if (cap = this.rules.code.exec(src)) {
19549           src = src.substring(cap[0].length);
19550           out += this.renderer.codespan(escape(cap[2], true));
19551           continue;
19552         }
19553     
19554         // br
19555         if (cap = this.rules.br.exec(src)) {
19556           src = src.substring(cap[0].length);
19557           out += this.renderer.br();
19558           continue;
19559         }
19560     
19561         // del (gfm)
19562         if (cap = this.rules.del.exec(src)) {
19563           src = src.substring(cap[0].length);
19564           out += this.renderer.del(this.output(cap[1]));
19565           continue;
19566         }
19567     
19568         // text
19569         if (cap = this.rules.text.exec(src)) {
19570           src = src.substring(cap[0].length);
19571           out += this.renderer.text(escape(this.smartypants(cap[0])));
19572           continue;
19573         }
19574     
19575         if (src) {
19576           throw new
19577             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19578         }
19579       }
19580     
19581       return out;
19582     };
19583     
19584     /**
19585      * Compile Link
19586      */
19587     
19588     InlineLexer.prototype.outputLink = function(cap, link) {
19589       var href = escape(link.href)
19590         , title = link.title ? escape(link.title) : null;
19591     
19592       return cap[0].charAt(0) !== '!'
19593         ? this.renderer.link(href, title, this.output(cap[1]))
19594         : this.renderer.image(href, title, escape(cap[1]));
19595     };
19596     
19597     /**
19598      * Smartypants Transformations
19599      */
19600     
19601     InlineLexer.prototype.smartypants = function(text) {
19602       if (!this.options.smartypants)  { return text; }
19603       return text
19604         // em-dashes
19605         .replace(/---/g, '\u2014')
19606         // en-dashes
19607         .replace(/--/g, '\u2013')
19608         // opening singles
19609         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19610         // closing singles & apostrophes
19611         .replace(/'/g, '\u2019')
19612         // opening doubles
19613         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19614         // closing doubles
19615         .replace(/"/g, '\u201d')
19616         // ellipses
19617         .replace(/\.{3}/g, '\u2026');
19618     };
19619     
19620     /**
19621      * Mangle Links
19622      */
19623     
19624     InlineLexer.prototype.mangle = function(text) {
19625       if (!this.options.mangle) { return text; }
19626       var out = ''
19627         , l = text.length
19628         , i = 0
19629         , ch;
19630     
19631       for (; i < l; i++) {
19632         ch = text.charCodeAt(i);
19633         if (Math.random() > 0.5) {
19634           ch = 'x' + ch.toString(16);
19635         }
19636         out += '&#' + ch + ';';
19637       }
19638     
19639       return out;
19640     };
19641     
19642     /**
19643      * Renderer
19644      */
19645     
19646      /**
19647          * eval:var:Renderer
19648     */
19649     
19650     var Renderer   = function (options) {
19651       this.options = options || {};
19652     }
19653     
19654     Renderer.prototype.code = function(code, lang, escaped) {
19655       if (this.options.highlight) {
19656         var out = this.options.highlight(code, lang);
19657         if (out != null && out !== code) {
19658           escaped = true;
19659           code = out;
19660         }
19661       } else {
19662             // hack!!! - it's already escapeD?
19663             escaped = true;
19664       }
19665     
19666       if (!lang) {
19667         return '<pre><code>'
19668           + (escaped ? code : escape(code, true))
19669           + '\n</code></pre>';
19670       }
19671     
19672       return '<pre><code class="'
19673         + this.options.langPrefix
19674         + escape(lang, true)
19675         + '">'
19676         + (escaped ? code : escape(code, true))
19677         + '\n</code></pre>\n';
19678     };
19679     
19680     Renderer.prototype.blockquote = function(quote) {
19681       return '<blockquote>\n' + quote + '</blockquote>\n';
19682     };
19683     
19684     Renderer.prototype.html = function(html) {
19685       return html;
19686     };
19687     
19688     Renderer.prototype.heading = function(text, level, raw) {
19689       return '<h'
19690         + level
19691         + ' id="'
19692         + this.options.headerPrefix
19693         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19694         + '">'
19695         + text
19696         + '</h'
19697         + level
19698         + '>\n';
19699     };
19700     
19701     Renderer.prototype.hr = function() {
19702       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19703     };
19704     
19705     Renderer.prototype.list = function(body, ordered) {
19706       var type = ordered ? 'ol' : 'ul';
19707       return '<' + type + '>\n' + body + '</' + type + '>\n';
19708     };
19709     
19710     Renderer.prototype.listitem = function(text) {
19711       return '<li>' + text + '</li>\n';
19712     };
19713     
19714     Renderer.prototype.paragraph = function(text) {
19715       return '<p>' + text + '</p>\n';
19716     };
19717     
19718     Renderer.prototype.table = function(header, body) {
19719       return '<table class="table table-striped">\n'
19720         + '<thead>\n'
19721         + header
19722         + '</thead>\n'
19723         + '<tbody>\n'
19724         + body
19725         + '</tbody>\n'
19726         + '</table>\n';
19727     };
19728     
19729     Renderer.prototype.tablerow = function(content) {
19730       return '<tr>\n' + content + '</tr>\n';
19731     };
19732     
19733     Renderer.prototype.tablecell = function(content, flags) {
19734       var type = flags.header ? 'th' : 'td';
19735       var tag = flags.align
19736         ? '<' + type + ' style="text-align:' + flags.align + '">'
19737         : '<' + type + '>';
19738       return tag + content + '</' + type + '>\n';
19739     };
19740     
19741     // span level renderer
19742     Renderer.prototype.strong = function(text) {
19743       return '<strong>' + text + '</strong>';
19744     };
19745     
19746     Renderer.prototype.em = function(text) {
19747       return '<em>' + text + '</em>';
19748     };
19749     
19750     Renderer.prototype.codespan = function(text) {
19751       return '<code>' + text + '</code>';
19752     };
19753     
19754     Renderer.prototype.br = function() {
19755       return this.options.xhtml ? '<br/>' : '<br>';
19756     };
19757     
19758     Renderer.prototype.del = function(text) {
19759       return '<del>' + text + '</del>';
19760     };
19761     
19762     Renderer.prototype.link = function(href, title, text) {
19763       if (this.options.sanitize) {
19764         try {
19765           var prot = decodeURIComponent(unescape(href))
19766             .replace(/[^\w:]/g, '')
19767             .toLowerCase();
19768         } catch (e) {
19769           return '';
19770         }
19771         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19772           return '';
19773         }
19774       }
19775       var out = '<a href="' + href + '"';
19776       if (title) {
19777         out += ' title="' + title + '"';
19778       }
19779       out += '>' + text + '</a>';
19780       return out;
19781     };
19782     
19783     Renderer.prototype.image = function(href, title, text) {
19784       var out = '<img src="' + href + '" alt="' + text + '"';
19785       if (title) {
19786         out += ' title="' + title + '"';
19787       }
19788       out += this.options.xhtml ? '/>' : '>';
19789       return out;
19790     };
19791     
19792     Renderer.prototype.text = function(text) {
19793       return text;
19794     };
19795     
19796     /**
19797      * Parsing & Compiling
19798      */
19799          /**
19800          * eval:var:Parser
19801     */
19802     
19803     var Parser= function (options) {
19804       this.tokens = [];
19805       this.token = null;
19806       this.options = options || marked.defaults;
19807       this.options.renderer = this.options.renderer || new Renderer;
19808       this.renderer = this.options.renderer;
19809       this.renderer.options = this.options;
19810     }
19811     
19812     /**
19813      * Static Parse Method
19814      */
19815     
19816     Parser.parse = function(src, options, renderer) {
19817       var parser = new Parser(options, renderer);
19818       return parser.parse(src);
19819     };
19820     
19821     /**
19822      * Parse Loop
19823      */
19824     
19825     Parser.prototype.parse = function(src) {
19826       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19827       this.tokens = src.reverse();
19828     
19829       var out = '';
19830       while (this.next()) {
19831         out += this.tok();
19832       }
19833     
19834       return out;
19835     };
19836     
19837     /**
19838      * Next Token
19839      */
19840     
19841     Parser.prototype.next = function() {
19842       return this.token = this.tokens.pop();
19843     };
19844     
19845     /**
19846      * Preview Next Token
19847      */
19848     
19849     Parser.prototype.peek = function() {
19850       return this.tokens[this.tokens.length - 1] || 0;
19851     };
19852     
19853     /**
19854      * Parse Text Tokens
19855      */
19856     
19857     Parser.prototype.parseText = function() {
19858       var body = this.token.text;
19859     
19860       while (this.peek().type === 'text') {
19861         body += '\n' + this.next().text;
19862       }
19863     
19864       return this.inline.output(body);
19865     };
19866     
19867     /**
19868      * Parse Current Token
19869      */
19870     
19871     Parser.prototype.tok = function() {
19872       switch (this.token.type) {
19873         case 'space': {
19874           return '';
19875         }
19876         case 'hr': {
19877           return this.renderer.hr();
19878         }
19879         case 'heading': {
19880           return this.renderer.heading(
19881             this.inline.output(this.token.text),
19882             this.token.depth,
19883             this.token.text);
19884         }
19885         case 'code': {
19886           return this.renderer.code(this.token.text,
19887             this.token.lang,
19888             this.token.escaped);
19889         }
19890         case 'table': {
19891           var header = ''
19892             , body = ''
19893             , i
19894             , row
19895             , cell
19896             , flags
19897             , j;
19898     
19899           // header
19900           cell = '';
19901           for (i = 0; i < this.token.header.length; i++) {
19902             flags = { header: true, align: this.token.align[i] };
19903             cell += this.renderer.tablecell(
19904               this.inline.output(this.token.header[i]),
19905               { header: true, align: this.token.align[i] }
19906             );
19907           }
19908           header += this.renderer.tablerow(cell);
19909     
19910           for (i = 0; i < this.token.cells.length; i++) {
19911             row = this.token.cells[i];
19912     
19913             cell = '';
19914             for (j = 0; j < row.length; j++) {
19915               cell += this.renderer.tablecell(
19916                 this.inline.output(row[j]),
19917                 { header: false, align: this.token.align[j] }
19918               );
19919             }
19920     
19921             body += this.renderer.tablerow(cell);
19922           }
19923           return this.renderer.table(header, body);
19924         }
19925         case 'blockquote_start': {
19926           var body = '';
19927     
19928           while (this.next().type !== 'blockquote_end') {
19929             body += this.tok();
19930           }
19931     
19932           return this.renderer.blockquote(body);
19933         }
19934         case 'list_start': {
19935           var body = ''
19936             , ordered = this.token.ordered;
19937     
19938           while (this.next().type !== 'list_end') {
19939             body += this.tok();
19940           }
19941     
19942           return this.renderer.list(body, ordered);
19943         }
19944         case 'list_item_start': {
19945           var body = '';
19946     
19947           while (this.next().type !== 'list_item_end') {
19948             body += this.token.type === 'text'
19949               ? this.parseText()
19950               : this.tok();
19951           }
19952     
19953           return this.renderer.listitem(body);
19954         }
19955         case 'loose_item_start': {
19956           var body = '';
19957     
19958           while (this.next().type !== 'list_item_end') {
19959             body += this.tok();
19960           }
19961     
19962           return this.renderer.listitem(body);
19963         }
19964         case 'html': {
19965           var html = !this.token.pre && !this.options.pedantic
19966             ? this.inline.output(this.token.text)
19967             : this.token.text;
19968           return this.renderer.html(html);
19969         }
19970         case 'paragraph': {
19971           return this.renderer.paragraph(this.inline.output(this.token.text));
19972         }
19973         case 'text': {
19974           return this.renderer.paragraph(this.parseText());
19975         }
19976       }
19977     };
19978   
19979     
19980     /**
19981      * Marked
19982      */
19983          /**
19984          * eval:var:marked
19985     */
19986     var marked = function (src, opt, callback) {
19987       if (callback || typeof opt === 'function') {
19988         if (!callback) {
19989           callback = opt;
19990           opt = null;
19991         }
19992     
19993         opt = merge({}, marked.defaults, opt || {});
19994     
19995         var highlight = opt.highlight
19996           , tokens
19997           , pending
19998           , i = 0;
19999     
20000         try {
20001           tokens = Lexer.lex(src, opt)
20002         } catch (e) {
20003           return callback(e);
20004         }
20005     
20006         pending = tokens.length;
20007          /**
20008          * eval:var:done
20009     */
20010         var done = function(err) {
20011           if (err) {
20012             opt.highlight = highlight;
20013             return callback(err);
20014           }
20015     
20016           var out;
20017     
20018           try {
20019             out = Parser.parse(tokens, opt);
20020           } catch (e) {
20021             err = e;
20022           }
20023     
20024           opt.highlight = highlight;
20025     
20026           return err
20027             ? callback(err)
20028             : callback(null, out);
20029         };
20030     
20031         if (!highlight || highlight.length < 3) {
20032           return done();
20033         }
20034     
20035         delete opt.highlight;
20036     
20037         if (!pending) { return done(); }
20038     
20039         for (; i < tokens.length; i++) {
20040           (function(token) {
20041             if (token.type !== 'code') {
20042               return --pending || done();
20043             }
20044             return highlight(token.text, token.lang, function(err, code) {
20045               if (err) { return done(err); }
20046               if (code == null || code === token.text) {
20047                 return --pending || done();
20048               }
20049               token.text = code;
20050               token.escaped = true;
20051               --pending || done();
20052             });
20053           })(tokens[i]);
20054         }
20055     
20056         return;
20057       }
20058       try {
20059         if (opt) { opt = merge({}, marked.defaults, opt); }
20060         return Parser.parse(Lexer.lex(src, opt), opt);
20061       } catch (e) {
20062         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20063         if ((opt || marked.defaults).silent) {
20064           return '<p>An error occured:</p><pre>'
20065             + escape(e.message + '', true)
20066             + '</pre>';
20067         }
20068         throw e;
20069       }
20070     }
20071     
20072     /**
20073      * Options
20074      */
20075     
20076     marked.options =
20077     marked.setOptions = function(opt) {
20078       merge(marked.defaults, opt);
20079       return marked;
20080     };
20081     
20082     marked.defaults = {
20083       gfm: true,
20084       tables: true,
20085       breaks: false,
20086       pedantic: false,
20087       sanitize: false,
20088       sanitizer: null,
20089       mangle: true,
20090       smartLists: false,
20091       silent: false,
20092       highlight: null,
20093       langPrefix: 'lang-',
20094       smartypants: false,
20095       headerPrefix: '',
20096       renderer: new Renderer,
20097       xhtml: false
20098     };
20099     
20100     /**
20101      * Expose
20102      */
20103     
20104     marked.Parser = Parser;
20105     marked.parser = Parser.parse;
20106     
20107     marked.Renderer = Renderer;
20108     
20109     marked.Lexer = Lexer;
20110     marked.lexer = Lexer.lex;
20111     
20112     marked.InlineLexer = InlineLexer;
20113     marked.inlineLexer = InlineLexer.output;
20114     
20115     marked.parse = marked;
20116     
20117     Roo.Markdown.marked = marked;
20118
20119 })();/*
20120  * Based on:
20121  * Ext JS Library 1.1.1
20122  * Copyright(c) 2006-2007, Ext JS, LLC.
20123  *
20124  * Originally Released Under LGPL - original licence link has changed is not relivant.
20125  *
20126  * Fork - LGPL
20127  * <script type="text/javascript">
20128  */
20129
20130
20131
20132 /*
20133  * These classes are derivatives of the similarly named classes in the YUI Library.
20134  * The original license:
20135  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20136  * Code licensed under the BSD License:
20137  * http://developer.yahoo.net/yui/license.txt
20138  */
20139
20140 (function() {
20141
20142 var Event=Roo.EventManager;
20143 var Dom=Roo.lib.Dom;
20144
20145 /**
20146  * @class Roo.dd.DragDrop
20147  * @extends Roo.util.Observable
20148  * Defines the interface and base operation of items that that can be
20149  * dragged or can be drop targets.  It was designed to be extended, overriding
20150  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20151  * Up to three html elements can be associated with a DragDrop instance:
20152  * <ul>
20153  * <li>linked element: the element that is passed into the constructor.
20154  * This is the element which defines the boundaries for interaction with
20155  * other DragDrop objects.</li>
20156  * <li>handle element(s): The drag operation only occurs if the element that
20157  * was clicked matches a handle element.  By default this is the linked
20158  * element, but there are times that you will want only a portion of the
20159  * linked element to initiate the drag operation, and the setHandleElId()
20160  * method provides a way to define this.</li>
20161  * <li>drag element: this represents the element that would be moved along
20162  * with the cursor during a drag operation.  By default, this is the linked
20163  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20164  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20165  * </li>
20166  * </ul>
20167  * This class should not be instantiated until the onload event to ensure that
20168  * the associated elements are available.
20169  * The following would define a DragDrop obj that would interact with any
20170  * other DragDrop obj in the "group1" group:
20171  * <pre>
20172  *  dd = new Roo.dd.DragDrop("div1", "group1");
20173  * </pre>
20174  * Since none of the event handlers have been implemented, nothing would
20175  * actually happen if you were to run the code above.  Normally you would
20176  * override this class or one of the default implementations, but you can
20177  * also override the methods you want on an instance of the class...
20178  * <pre>
20179  *  dd.onDragDrop = function(e, id) {
20180  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20181  *  }
20182  * </pre>
20183  * @constructor
20184  * @param {String} id of the element that is linked to this instance
20185  * @param {String} sGroup the group of related DragDrop objects
20186  * @param {object} config an object containing configurable attributes
20187  *                Valid properties for DragDrop:
20188  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20189  */
20190 Roo.dd.DragDrop = function(id, sGroup, config) {
20191     if (id) {
20192         this.init(id, sGroup, config);
20193     }
20194     
20195 };
20196
20197 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20198
20199     /**
20200      * The id of the element associated with this object.  This is what we
20201      * refer to as the "linked element" because the size and position of
20202      * this element is used to determine when the drag and drop objects have
20203      * interacted.
20204      * @property id
20205      * @type String
20206      */
20207     id: null,
20208
20209     /**
20210      * Configuration attributes passed into the constructor
20211      * @property config
20212      * @type object
20213      */
20214     config: null,
20215
20216     /**
20217      * The id of the element that will be dragged.  By default this is same
20218      * as the linked element , but could be changed to another element. Ex:
20219      * Roo.dd.DDProxy
20220      * @property dragElId
20221      * @type String
20222      * @private
20223      */
20224     dragElId: null,
20225
20226     /**
20227      * the id of the element that initiates the drag operation.  By default
20228      * this is the linked element, but could be changed to be a child of this
20229      * element.  This lets us do things like only starting the drag when the
20230      * header element within the linked html element is clicked.
20231      * @property handleElId
20232      * @type String
20233      * @private
20234      */
20235     handleElId: null,
20236
20237     /**
20238      * An associative array of HTML tags that will be ignored if clicked.
20239      * @property invalidHandleTypes
20240      * @type {string: string}
20241      */
20242     invalidHandleTypes: null,
20243
20244     /**
20245      * An associative array of ids for elements that will be ignored if clicked
20246      * @property invalidHandleIds
20247      * @type {string: string}
20248      */
20249     invalidHandleIds: null,
20250
20251     /**
20252      * An indexted array of css class names for elements that will be ignored
20253      * if clicked.
20254      * @property invalidHandleClasses
20255      * @type string[]
20256      */
20257     invalidHandleClasses: null,
20258
20259     /**
20260      * The linked element's absolute X position at the time the drag was
20261      * started
20262      * @property startPageX
20263      * @type int
20264      * @private
20265      */
20266     startPageX: 0,
20267
20268     /**
20269      * The linked element's absolute X position at the time the drag was
20270      * started
20271      * @property startPageY
20272      * @type int
20273      * @private
20274      */
20275     startPageY: 0,
20276
20277     /**
20278      * The group defines a logical collection of DragDrop objects that are
20279      * related.  Instances only get events when interacting with other
20280      * DragDrop object in the same group.  This lets us define multiple
20281      * groups using a single DragDrop subclass if we want.
20282      * @property groups
20283      * @type {string: string}
20284      */
20285     groups: null,
20286
20287     /**
20288      * Individual drag/drop instances can be locked.  This will prevent
20289      * onmousedown start drag.
20290      * @property locked
20291      * @type boolean
20292      * @private
20293      */
20294     locked: false,
20295
20296     /**
20297      * Lock this instance
20298      * @method lock
20299      */
20300     lock: function() { this.locked = true; },
20301
20302     /**
20303      * Unlock this instace
20304      * @method unlock
20305      */
20306     unlock: function() { this.locked = false; },
20307
20308     /**
20309      * By default, all insances can be a drop target.  This can be disabled by
20310      * setting isTarget to false.
20311      * @method isTarget
20312      * @type boolean
20313      */
20314     isTarget: true,
20315
20316     /**
20317      * The padding configured for this drag and drop object for calculating
20318      * the drop zone intersection with this object.
20319      * @method padding
20320      * @type int[]
20321      */
20322     padding: null,
20323
20324     /**
20325      * Cached reference to the linked element
20326      * @property _domRef
20327      * @private
20328      */
20329     _domRef: null,
20330
20331     /**
20332      * Internal typeof flag
20333      * @property __ygDragDrop
20334      * @private
20335      */
20336     __ygDragDrop: true,
20337
20338     /**
20339      * Set to true when horizontal contraints are applied
20340      * @property constrainX
20341      * @type boolean
20342      * @private
20343      */
20344     constrainX: false,
20345
20346     /**
20347      * Set to true when vertical contraints are applied
20348      * @property constrainY
20349      * @type boolean
20350      * @private
20351      */
20352     constrainY: false,
20353
20354     /**
20355      * The left constraint
20356      * @property minX
20357      * @type int
20358      * @private
20359      */
20360     minX: 0,
20361
20362     /**
20363      * The right constraint
20364      * @property maxX
20365      * @type int
20366      * @private
20367      */
20368     maxX: 0,
20369
20370     /**
20371      * The up constraint
20372      * @property minY
20373      * @type int
20374      * @type int
20375      * @private
20376      */
20377     minY: 0,
20378
20379     /**
20380      * The down constraint
20381      * @property maxY
20382      * @type int
20383      * @private
20384      */
20385     maxY: 0,
20386
20387     /**
20388      * Maintain offsets when we resetconstraints.  Set to true when you want
20389      * the position of the element relative to its parent to stay the same
20390      * when the page changes
20391      *
20392      * @property maintainOffset
20393      * @type boolean
20394      */
20395     maintainOffset: false,
20396
20397     /**
20398      * Array of pixel locations the element will snap to if we specified a
20399      * horizontal graduation/interval.  This array is generated automatically
20400      * when you define a tick interval.
20401      * @property xTicks
20402      * @type int[]
20403      */
20404     xTicks: null,
20405
20406     /**
20407      * Array of pixel locations the element will snap to if we specified a
20408      * vertical graduation/interval.  This array is generated automatically
20409      * when you define a tick interval.
20410      * @property yTicks
20411      * @type int[]
20412      */
20413     yTicks: null,
20414
20415     /**
20416      * By default the drag and drop instance will only respond to the primary
20417      * button click (left button for a right-handed mouse).  Set to true to
20418      * allow drag and drop to start with any mouse click that is propogated
20419      * by the browser
20420      * @property primaryButtonOnly
20421      * @type boolean
20422      */
20423     primaryButtonOnly: true,
20424
20425     /**
20426      * The availabe property is false until the linked dom element is accessible.
20427      * @property available
20428      * @type boolean
20429      */
20430     available: false,
20431
20432     /**
20433      * By default, drags can only be initiated if the mousedown occurs in the
20434      * region the linked element is.  This is done in part to work around a
20435      * bug in some browsers that mis-report the mousedown if the previous
20436      * mouseup happened outside of the window.  This property is set to true
20437      * if outer handles are defined.
20438      *
20439      * @property hasOuterHandles
20440      * @type boolean
20441      * @default false
20442      */
20443     hasOuterHandles: false,
20444
20445     /**
20446      * Code that executes immediately before the startDrag event
20447      * @method b4StartDrag
20448      * @private
20449      */
20450     b4StartDrag: function(x, y) { },
20451
20452     /**
20453      * Abstract method called after a drag/drop object is clicked
20454      * and the drag or mousedown time thresholds have beeen met.
20455      * @method startDrag
20456      * @param {int} X click location
20457      * @param {int} Y click location
20458      */
20459     startDrag: function(x, y) { /* override this */ },
20460
20461     /**
20462      * Code that executes immediately before the onDrag event
20463      * @method b4Drag
20464      * @private
20465      */
20466     b4Drag: function(e) { },
20467
20468     /**
20469      * Abstract method called during the onMouseMove event while dragging an
20470      * object.
20471      * @method onDrag
20472      * @param {Event} e the mousemove event
20473      */
20474     onDrag: function(e) { /* override this */ },
20475
20476     /**
20477      * Abstract method called when this element fist begins hovering over
20478      * another DragDrop obj
20479      * @method onDragEnter
20480      * @param {Event} e the mousemove event
20481      * @param {String|DragDrop[]} id In POINT mode, the element
20482      * id this is hovering over.  In INTERSECT mode, an array of one or more
20483      * dragdrop items being hovered over.
20484      */
20485     onDragEnter: function(e, id) { /* override this */ },
20486
20487     /**
20488      * Code that executes immediately before the onDragOver event
20489      * @method b4DragOver
20490      * @private
20491      */
20492     b4DragOver: function(e) { },
20493
20494     /**
20495      * Abstract method called when this element is hovering over another
20496      * DragDrop obj
20497      * @method onDragOver
20498      * @param {Event} e the mousemove event
20499      * @param {String|DragDrop[]} id In POINT mode, the element
20500      * id this is hovering over.  In INTERSECT mode, an array of dd items
20501      * being hovered over.
20502      */
20503     onDragOver: function(e, id) { /* override this */ },
20504
20505     /**
20506      * Code that executes immediately before the onDragOut event
20507      * @method b4DragOut
20508      * @private
20509      */
20510     b4DragOut: function(e) { },
20511
20512     /**
20513      * Abstract method called when we are no longer hovering over an element
20514      * @method onDragOut
20515      * @param {Event} e the mousemove event
20516      * @param {String|DragDrop[]} id In POINT mode, the element
20517      * id this was hovering over.  In INTERSECT mode, an array of dd items
20518      * that the mouse is no longer over.
20519      */
20520     onDragOut: function(e, id) { /* override this */ },
20521
20522     /**
20523      * Code that executes immediately before the onDragDrop event
20524      * @method b4DragDrop
20525      * @private
20526      */
20527     b4DragDrop: function(e) { },
20528
20529     /**
20530      * Abstract method called when this item is dropped on another DragDrop
20531      * obj
20532      * @method onDragDrop
20533      * @param {Event} e the mouseup event
20534      * @param {String|DragDrop[]} id In POINT mode, the element
20535      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20536      * was dropped on.
20537      */
20538     onDragDrop: function(e, id) { /* override this */ },
20539
20540     /**
20541      * Abstract method called when this item is dropped on an area with no
20542      * drop target
20543      * @method onInvalidDrop
20544      * @param {Event} e the mouseup event
20545      */
20546     onInvalidDrop: function(e) { /* override this */ },
20547
20548     /**
20549      * Code that executes immediately before the endDrag event
20550      * @method b4EndDrag
20551      * @private
20552      */
20553     b4EndDrag: function(e) { },
20554
20555     /**
20556      * Fired when we are done dragging the object
20557      * @method endDrag
20558      * @param {Event} e the mouseup event
20559      */
20560     endDrag: function(e) { /* override this */ },
20561
20562     /**
20563      * Code executed immediately before the onMouseDown event
20564      * @method b4MouseDown
20565      * @param {Event} e the mousedown event
20566      * @private
20567      */
20568     b4MouseDown: function(e) {  },
20569
20570     /**
20571      * Event handler that fires when a drag/drop obj gets a mousedown
20572      * @method onMouseDown
20573      * @param {Event} e the mousedown event
20574      */
20575     onMouseDown: function(e) { /* override this */ },
20576
20577     /**
20578      * Event handler that fires when a drag/drop obj gets a mouseup
20579      * @method onMouseUp
20580      * @param {Event} e the mouseup event
20581      */
20582     onMouseUp: function(e) { /* override this */ },
20583
20584     /**
20585      * Override the onAvailable method to do what is needed after the initial
20586      * position was determined.
20587      * @method onAvailable
20588      */
20589     onAvailable: function () {
20590     },
20591
20592     /*
20593      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20594      * @type Object
20595      */
20596     defaultPadding : {left:0, right:0, top:0, bottom:0},
20597
20598     /*
20599      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20600  *
20601  * Usage:
20602  <pre><code>
20603  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20604                 { dragElId: "existingProxyDiv" });
20605  dd.startDrag = function(){
20606      this.constrainTo("parent-id");
20607  };
20608  </code></pre>
20609  * Or you can initalize it using the {@link Roo.Element} object:
20610  <pre><code>
20611  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20612      startDrag : function(){
20613          this.constrainTo("parent-id");
20614      }
20615  });
20616  </code></pre>
20617      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20618      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20619      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20620      * an object containing the sides to pad. For example: {right:10, bottom:10}
20621      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20622      */
20623     constrainTo : function(constrainTo, pad, inContent){
20624         if(typeof pad == "number"){
20625             pad = {left: pad, right:pad, top:pad, bottom:pad};
20626         }
20627         pad = pad || this.defaultPadding;
20628         var b = Roo.get(this.getEl()).getBox();
20629         var ce = Roo.get(constrainTo);
20630         var s = ce.getScroll();
20631         var c, cd = ce.dom;
20632         if(cd == document.body){
20633             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20634         }else{
20635             xy = ce.getXY();
20636             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20637         }
20638
20639
20640         var topSpace = b.y - c.y;
20641         var leftSpace = b.x - c.x;
20642
20643         this.resetConstraints();
20644         this.setXConstraint(leftSpace - (pad.left||0), // left
20645                 c.width - leftSpace - b.width - (pad.right||0) //right
20646         );
20647         this.setYConstraint(topSpace - (pad.top||0), //top
20648                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20649         );
20650     },
20651
20652     /**
20653      * Returns a reference to the linked element
20654      * @method getEl
20655      * @return {HTMLElement} the html element
20656      */
20657     getEl: function() {
20658         if (!this._domRef) {
20659             this._domRef = Roo.getDom(this.id);
20660         }
20661
20662         return this._domRef;
20663     },
20664
20665     /**
20666      * Returns a reference to the actual element to drag.  By default this is
20667      * the same as the html element, but it can be assigned to another
20668      * element. An example of this can be found in Roo.dd.DDProxy
20669      * @method getDragEl
20670      * @return {HTMLElement} the html element
20671      */
20672     getDragEl: function() {
20673         return Roo.getDom(this.dragElId);
20674     },
20675
20676     /**
20677      * Sets up the DragDrop object.  Must be called in the constructor of any
20678      * Roo.dd.DragDrop subclass
20679      * @method init
20680      * @param id the id of the linked element
20681      * @param {String} sGroup the group of related items
20682      * @param {object} config configuration attributes
20683      */
20684     init: function(id, sGroup, config) {
20685         this.initTarget(id, sGroup, config);
20686         if (!Roo.isTouch) {
20687             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20688         }
20689         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20690         // Event.on(this.id, "selectstart", Event.preventDefault);
20691     },
20692
20693     /**
20694      * Initializes Targeting functionality only... the object does not
20695      * get a mousedown handler.
20696      * @method initTarget
20697      * @param id the id of the linked element
20698      * @param {String} sGroup the group of related items
20699      * @param {object} config configuration attributes
20700      */
20701     initTarget: function(id, sGroup, config) {
20702
20703         // configuration attributes
20704         this.config = config || {};
20705
20706         // create a local reference to the drag and drop manager
20707         this.DDM = Roo.dd.DDM;
20708         // initialize the groups array
20709         this.groups = {};
20710
20711         // assume that we have an element reference instead of an id if the
20712         // parameter is not a string
20713         if (typeof id !== "string") {
20714             id = Roo.id(id);
20715         }
20716
20717         // set the id
20718         this.id = id;
20719
20720         // add to an interaction group
20721         this.addToGroup((sGroup) ? sGroup : "default");
20722
20723         // We don't want to register this as the handle with the manager
20724         // so we just set the id rather than calling the setter.
20725         this.handleElId = id;
20726
20727         // the linked element is the element that gets dragged by default
20728         this.setDragElId(id);
20729
20730         // by default, clicked anchors will not start drag operations.
20731         this.invalidHandleTypes = { A: "A" };
20732         this.invalidHandleIds = {};
20733         this.invalidHandleClasses = [];
20734
20735         this.applyConfig();
20736
20737         this.handleOnAvailable();
20738     },
20739
20740     /**
20741      * Applies the configuration parameters that were passed into the constructor.
20742      * This is supposed to happen at each level through the inheritance chain.  So
20743      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20744      * DragDrop in order to get all of the parameters that are available in
20745      * each object.
20746      * @method applyConfig
20747      */
20748     applyConfig: function() {
20749
20750         // configurable properties:
20751         //    padding, isTarget, maintainOffset, primaryButtonOnly
20752         this.padding           = this.config.padding || [0, 0, 0, 0];
20753         this.isTarget          = (this.config.isTarget !== false);
20754         this.maintainOffset    = (this.config.maintainOffset);
20755         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20756
20757     },
20758
20759     /**
20760      * Executed when the linked element is available
20761      * @method handleOnAvailable
20762      * @private
20763      */
20764     handleOnAvailable: function() {
20765         this.available = true;
20766         this.resetConstraints();
20767         this.onAvailable();
20768     },
20769
20770      /**
20771      * Configures the padding for the target zone in px.  Effectively expands
20772      * (or reduces) the virtual object size for targeting calculations.
20773      * Supports css-style shorthand; if only one parameter is passed, all sides
20774      * will have that padding, and if only two are passed, the top and bottom
20775      * will have the first param, the left and right the second.
20776      * @method setPadding
20777      * @param {int} iTop    Top pad
20778      * @param {int} iRight  Right pad
20779      * @param {int} iBot    Bot pad
20780      * @param {int} iLeft   Left pad
20781      */
20782     setPadding: function(iTop, iRight, iBot, iLeft) {
20783         // this.padding = [iLeft, iRight, iTop, iBot];
20784         if (!iRight && 0 !== iRight) {
20785             this.padding = [iTop, iTop, iTop, iTop];
20786         } else if (!iBot && 0 !== iBot) {
20787             this.padding = [iTop, iRight, iTop, iRight];
20788         } else {
20789             this.padding = [iTop, iRight, iBot, iLeft];
20790         }
20791     },
20792
20793     /**
20794      * Stores the initial placement of the linked element.
20795      * @method setInitialPosition
20796      * @param {int} diffX   the X offset, default 0
20797      * @param {int} diffY   the Y offset, default 0
20798      */
20799     setInitPosition: function(diffX, diffY) {
20800         var el = this.getEl();
20801
20802         if (!this.DDM.verifyEl(el)) {
20803             return;
20804         }
20805
20806         var dx = diffX || 0;
20807         var dy = diffY || 0;
20808
20809         var p = Dom.getXY( el );
20810
20811         this.initPageX = p[0] - dx;
20812         this.initPageY = p[1] - dy;
20813
20814         this.lastPageX = p[0];
20815         this.lastPageY = p[1];
20816
20817
20818         this.setStartPosition(p);
20819     },
20820
20821     /**
20822      * Sets the start position of the element.  This is set when the obj
20823      * is initialized, the reset when a drag is started.
20824      * @method setStartPosition
20825      * @param pos current position (from previous lookup)
20826      * @private
20827      */
20828     setStartPosition: function(pos) {
20829         var p = pos || Dom.getXY( this.getEl() );
20830         this.deltaSetXY = null;
20831
20832         this.startPageX = p[0];
20833         this.startPageY = p[1];
20834     },
20835
20836     /**
20837      * Add this instance to a group of related drag/drop objects.  All
20838      * instances belong to at least one group, and can belong to as many
20839      * groups as needed.
20840      * @method addToGroup
20841      * @param sGroup {string} the name of the group
20842      */
20843     addToGroup: function(sGroup) {
20844         this.groups[sGroup] = true;
20845         this.DDM.regDragDrop(this, sGroup);
20846     },
20847
20848     /**
20849      * Remove's this instance from the supplied interaction group
20850      * @method removeFromGroup
20851      * @param {string}  sGroup  The group to drop
20852      */
20853     removeFromGroup: function(sGroup) {
20854         if (this.groups[sGroup]) {
20855             delete this.groups[sGroup];
20856         }
20857
20858         this.DDM.removeDDFromGroup(this, sGroup);
20859     },
20860
20861     /**
20862      * Allows you to specify that an element other than the linked element
20863      * will be moved with the cursor during a drag
20864      * @method setDragElId
20865      * @param id {string} the id of the element that will be used to initiate the drag
20866      */
20867     setDragElId: function(id) {
20868         this.dragElId = id;
20869     },
20870
20871     /**
20872      * Allows you to specify a child of the linked element that should be
20873      * used to initiate the drag operation.  An example of this would be if
20874      * you have a content div with text and links.  Clicking anywhere in the
20875      * content area would normally start the drag operation.  Use this method
20876      * to specify that an element inside of the content div is the element
20877      * that starts the drag operation.
20878      * @method setHandleElId
20879      * @param id {string} the id of the element that will be used to
20880      * initiate the drag.
20881      */
20882     setHandleElId: function(id) {
20883         if (typeof id !== "string") {
20884             id = Roo.id(id);
20885         }
20886         this.handleElId = id;
20887         this.DDM.regHandle(this.id, id);
20888     },
20889
20890     /**
20891      * Allows you to set an element outside of the linked element as a drag
20892      * handle
20893      * @method setOuterHandleElId
20894      * @param id the id of the element that will be used to initiate the drag
20895      */
20896     setOuterHandleElId: function(id) {
20897         if (typeof id !== "string") {
20898             id = Roo.id(id);
20899         }
20900         Event.on(id, "mousedown",
20901                 this.handleMouseDown, this);
20902         this.setHandleElId(id);
20903
20904         this.hasOuterHandles = true;
20905     },
20906
20907     /**
20908      * Remove all drag and drop hooks for this element
20909      * @method unreg
20910      */
20911     unreg: function() {
20912         Event.un(this.id, "mousedown",
20913                 this.handleMouseDown);
20914         Event.un(this.id, "touchstart",
20915                 this.handleMouseDown);
20916         this._domRef = null;
20917         this.DDM._remove(this);
20918     },
20919
20920     destroy : function(){
20921         this.unreg();
20922     },
20923
20924     /**
20925      * Returns true if this instance is locked, or the drag drop mgr is locked
20926      * (meaning that all drag/drop is disabled on the page.)
20927      * @method isLocked
20928      * @return {boolean} true if this obj or all drag/drop is locked, else
20929      * false
20930      */
20931     isLocked: function() {
20932         return (this.DDM.isLocked() || this.locked);
20933     },
20934
20935     /**
20936      * Fired when this object is clicked
20937      * @method handleMouseDown
20938      * @param {Event} e
20939      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20940      * @private
20941      */
20942     handleMouseDown: function(e, oDD){
20943      
20944         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20945             //Roo.log('not touch/ button !=0');
20946             return;
20947         }
20948         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20949             return; // double touch..
20950         }
20951         
20952
20953         if (this.isLocked()) {
20954             //Roo.log('locked');
20955             return;
20956         }
20957
20958         this.DDM.refreshCache(this.groups);
20959 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20960         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20961         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20962             //Roo.log('no outer handes or not over target');
20963                 // do nothing.
20964         } else {
20965 //            Roo.log('check validator');
20966             if (this.clickValidator(e)) {
20967 //                Roo.log('validate success');
20968                 // set the initial element position
20969                 this.setStartPosition();
20970
20971
20972                 this.b4MouseDown(e);
20973                 this.onMouseDown(e);
20974
20975                 this.DDM.handleMouseDown(e, this);
20976
20977                 this.DDM.stopEvent(e);
20978             } else {
20979
20980
20981             }
20982         }
20983     },
20984
20985     clickValidator: function(e) {
20986         var target = e.getTarget();
20987         return ( this.isValidHandleChild(target) &&
20988                     (this.id == this.handleElId ||
20989                         this.DDM.handleWasClicked(target, this.id)) );
20990     },
20991
20992     /**
20993      * Allows you to specify a tag name that should not start a drag operation
20994      * when clicked.  This is designed to facilitate embedding links within a
20995      * drag handle that do something other than start the drag.
20996      * @method addInvalidHandleType
20997      * @param {string} tagName the type of element to exclude
20998      */
20999     addInvalidHandleType: function(tagName) {
21000         var type = tagName.toUpperCase();
21001         this.invalidHandleTypes[type] = type;
21002     },
21003
21004     /**
21005      * Lets you to specify an element id for a child of a drag handle
21006      * that should not initiate a drag
21007      * @method addInvalidHandleId
21008      * @param {string} id the element id of the element you wish to ignore
21009      */
21010     addInvalidHandleId: function(id) {
21011         if (typeof id !== "string") {
21012             id = Roo.id(id);
21013         }
21014         this.invalidHandleIds[id] = id;
21015     },
21016
21017     /**
21018      * Lets you specify a css class of elements that will not initiate a drag
21019      * @method addInvalidHandleClass
21020      * @param {string} cssClass the class of the elements you wish to ignore
21021      */
21022     addInvalidHandleClass: function(cssClass) {
21023         this.invalidHandleClasses.push(cssClass);
21024     },
21025
21026     /**
21027      * Unsets an excluded tag name set by addInvalidHandleType
21028      * @method removeInvalidHandleType
21029      * @param {string} tagName the type of element to unexclude
21030      */
21031     removeInvalidHandleType: function(tagName) {
21032         var type = tagName.toUpperCase();
21033         // this.invalidHandleTypes[type] = null;
21034         delete this.invalidHandleTypes[type];
21035     },
21036
21037     /**
21038      * Unsets an invalid handle id
21039      * @method removeInvalidHandleId
21040      * @param {string} id the id of the element to re-enable
21041      */
21042     removeInvalidHandleId: function(id) {
21043         if (typeof id !== "string") {
21044             id = Roo.id(id);
21045         }
21046         delete this.invalidHandleIds[id];
21047     },
21048
21049     /**
21050      * Unsets an invalid css class
21051      * @method removeInvalidHandleClass
21052      * @param {string} cssClass the class of the element(s) you wish to
21053      * re-enable
21054      */
21055     removeInvalidHandleClass: function(cssClass) {
21056         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21057             if (this.invalidHandleClasses[i] == cssClass) {
21058                 delete this.invalidHandleClasses[i];
21059             }
21060         }
21061     },
21062
21063     /**
21064      * Checks the tag exclusion list to see if this click should be ignored
21065      * @method isValidHandleChild
21066      * @param {HTMLElement} node the HTMLElement to evaluate
21067      * @return {boolean} true if this is a valid tag type, false if not
21068      */
21069     isValidHandleChild: function(node) {
21070
21071         var valid = true;
21072         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21073         var nodeName;
21074         try {
21075             nodeName = node.nodeName.toUpperCase();
21076         } catch(e) {
21077             nodeName = node.nodeName;
21078         }
21079         valid = valid && !this.invalidHandleTypes[nodeName];
21080         valid = valid && !this.invalidHandleIds[node.id];
21081
21082         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21083             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21084         }
21085
21086
21087         return valid;
21088
21089     },
21090
21091     /**
21092      * Create the array of horizontal tick marks if an interval was specified
21093      * in setXConstraint().
21094      * @method setXTicks
21095      * @private
21096      */
21097     setXTicks: function(iStartX, iTickSize) {
21098         this.xTicks = [];
21099         this.xTickSize = iTickSize;
21100
21101         var tickMap = {};
21102
21103         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21104             if (!tickMap[i]) {
21105                 this.xTicks[this.xTicks.length] = i;
21106                 tickMap[i] = true;
21107             }
21108         }
21109
21110         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21111             if (!tickMap[i]) {
21112                 this.xTicks[this.xTicks.length] = i;
21113                 tickMap[i] = true;
21114             }
21115         }
21116
21117         this.xTicks.sort(this.DDM.numericSort) ;
21118     },
21119
21120     /**
21121      * Create the array of vertical tick marks if an interval was specified in
21122      * setYConstraint().
21123      * @method setYTicks
21124      * @private
21125      */
21126     setYTicks: function(iStartY, iTickSize) {
21127         this.yTicks = [];
21128         this.yTickSize = iTickSize;
21129
21130         var tickMap = {};
21131
21132         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21133             if (!tickMap[i]) {
21134                 this.yTicks[this.yTicks.length] = i;
21135                 tickMap[i] = true;
21136             }
21137         }
21138
21139         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21140             if (!tickMap[i]) {
21141                 this.yTicks[this.yTicks.length] = i;
21142                 tickMap[i] = true;
21143             }
21144         }
21145
21146         this.yTicks.sort(this.DDM.numericSort) ;
21147     },
21148
21149     /**
21150      * By default, the element can be dragged any place on the screen.  Use
21151      * this method to limit the horizontal travel of the element.  Pass in
21152      * 0,0 for the parameters if you want to lock the drag to the y axis.
21153      * @method setXConstraint
21154      * @param {int} iLeft the number of pixels the element can move to the left
21155      * @param {int} iRight the number of pixels the element can move to the
21156      * right
21157      * @param {int} iTickSize optional parameter for specifying that the
21158      * element
21159      * should move iTickSize pixels at a time.
21160      */
21161     setXConstraint: function(iLeft, iRight, iTickSize) {
21162         this.leftConstraint = iLeft;
21163         this.rightConstraint = iRight;
21164
21165         this.minX = this.initPageX - iLeft;
21166         this.maxX = this.initPageX + iRight;
21167         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21168
21169         this.constrainX = true;
21170     },
21171
21172     /**
21173      * Clears any constraints applied to this instance.  Also clears ticks
21174      * since they can't exist independent of a constraint at this time.
21175      * @method clearConstraints
21176      */
21177     clearConstraints: function() {
21178         this.constrainX = false;
21179         this.constrainY = false;
21180         this.clearTicks();
21181     },
21182
21183     /**
21184      * Clears any tick interval defined for this instance
21185      * @method clearTicks
21186      */
21187     clearTicks: function() {
21188         this.xTicks = null;
21189         this.yTicks = null;
21190         this.xTickSize = 0;
21191         this.yTickSize = 0;
21192     },
21193
21194     /**
21195      * By default, the element can be dragged any place on the screen.  Set
21196      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21197      * parameters if you want to lock the drag to the x axis.
21198      * @method setYConstraint
21199      * @param {int} iUp the number of pixels the element can move up
21200      * @param {int} iDown the number of pixels the element can move down
21201      * @param {int} iTickSize optional parameter for specifying that the
21202      * element should move iTickSize pixels at a time.
21203      */
21204     setYConstraint: function(iUp, iDown, iTickSize) {
21205         this.topConstraint = iUp;
21206         this.bottomConstraint = iDown;
21207
21208         this.minY = this.initPageY - iUp;
21209         this.maxY = this.initPageY + iDown;
21210         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21211
21212         this.constrainY = true;
21213
21214     },
21215
21216     /**
21217      * resetConstraints must be called if you manually reposition a dd element.
21218      * @method resetConstraints
21219      * @param {boolean} maintainOffset
21220      */
21221     resetConstraints: function() {
21222
21223
21224         // Maintain offsets if necessary
21225         if (this.initPageX || this.initPageX === 0) {
21226             // figure out how much this thing has moved
21227             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21228             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21229
21230             this.setInitPosition(dx, dy);
21231
21232         // This is the first time we have detected the element's position
21233         } else {
21234             this.setInitPosition();
21235         }
21236
21237         if (this.constrainX) {
21238             this.setXConstraint( this.leftConstraint,
21239                                  this.rightConstraint,
21240                                  this.xTickSize        );
21241         }
21242
21243         if (this.constrainY) {
21244             this.setYConstraint( this.topConstraint,
21245                                  this.bottomConstraint,
21246                                  this.yTickSize         );
21247         }
21248     },
21249
21250     /**
21251      * Normally the drag element is moved pixel by pixel, but we can specify
21252      * that it move a number of pixels at a time.  This method resolves the
21253      * location when we have it set up like this.
21254      * @method getTick
21255      * @param {int} val where we want to place the object
21256      * @param {int[]} tickArray sorted array of valid points
21257      * @return {int} the closest tick
21258      * @private
21259      */
21260     getTick: function(val, tickArray) {
21261
21262         if (!tickArray) {
21263             // If tick interval is not defined, it is effectively 1 pixel,
21264             // so we return the value passed to us.
21265             return val;
21266         } else if (tickArray[0] >= val) {
21267             // The value is lower than the first tick, so we return the first
21268             // tick.
21269             return tickArray[0];
21270         } else {
21271             for (var i=0, len=tickArray.length; i<len; ++i) {
21272                 var next = i + 1;
21273                 if (tickArray[next] && tickArray[next] >= val) {
21274                     var diff1 = val - tickArray[i];
21275                     var diff2 = tickArray[next] - val;
21276                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21277                 }
21278             }
21279
21280             // The value is larger than the last tick, so we return the last
21281             // tick.
21282             return tickArray[tickArray.length - 1];
21283         }
21284     },
21285
21286     /**
21287      * toString method
21288      * @method toString
21289      * @return {string} string representation of the dd obj
21290      */
21291     toString: function() {
21292         return ("DragDrop " + this.id);
21293     }
21294
21295 });
21296
21297 })();
21298 /*
21299  * Based on:
21300  * Ext JS Library 1.1.1
21301  * Copyright(c) 2006-2007, Ext JS, LLC.
21302  *
21303  * Originally Released Under LGPL - original licence link has changed is not relivant.
21304  *
21305  * Fork - LGPL
21306  * <script type="text/javascript">
21307  */
21308
21309
21310 /**
21311  * The drag and drop utility provides a framework for building drag and drop
21312  * applications.  In addition to enabling drag and drop for specific elements,
21313  * the drag and drop elements are tracked by the manager class, and the
21314  * interactions between the various elements are tracked during the drag and
21315  * the implementing code is notified about these important moments.
21316  */
21317
21318 // Only load the library once.  Rewriting the manager class would orphan
21319 // existing drag and drop instances.
21320 if (!Roo.dd.DragDropMgr) {
21321
21322 /**
21323  * @class Roo.dd.DragDropMgr
21324  * DragDropMgr is a singleton that tracks the element interaction for
21325  * all DragDrop items in the window.  Generally, you will not call
21326  * this class directly, but it does have helper methods that could
21327  * be useful in your DragDrop implementations.
21328  * @static
21329  */
21330 Roo.dd.DragDropMgr = function() {
21331
21332     var Event = Roo.EventManager;
21333
21334     return {
21335
21336         /**
21337          * Two dimensional Array of registered DragDrop objects.  The first
21338          * dimension is the DragDrop item group, the second the DragDrop
21339          * object.
21340          * @property ids
21341          * @type {string: string}
21342          * @private
21343          * @static
21344          */
21345         ids: {},
21346
21347         /**
21348          * Array of element ids defined as drag handles.  Used to determine
21349          * if the element that generated the mousedown event is actually the
21350          * handle and not the html element itself.
21351          * @property handleIds
21352          * @type {string: string}
21353          * @private
21354          * @static
21355          */
21356         handleIds: {},
21357
21358         /**
21359          * the DragDrop object that is currently being dragged
21360          * @property dragCurrent
21361          * @type DragDrop
21362          * @private
21363          * @static
21364          **/
21365         dragCurrent: null,
21366
21367         /**
21368          * the DragDrop object(s) that are being hovered over
21369          * @property dragOvers
21370          * @type Array
21371          * @private
21372          * @static
21373          */
21374         dragOvers: {},
21375
21376         /**
21377          * the X distance between the cursor and the object being dragged
21378          * @property deltaX
21379          * @type int
21380          * @private
21381          * @static
21382          */
21383         deltaX: 0,
21384
21385         /**
21386          * the Y distance between the cursor and the object being dragged
21387          * @property deltaY
21388          * @type int
21389          * @private
21390          * @static
21391          */
21392         deltaY: 0,
21393
21394         /**
21395          * Flag to determine if we should prevent the default behavior of the
21396          * events we define. By default this is true, but this can be set to
21397          * false if you need the default behavior (not recommended)
21398          * @property preventDefault
21399          * @type boolean
21400          * @static
21401          */
21402         preventDefault: true,
21403
21404         /**
21405          * Flag to determine if we should stop the propagation of the events
21406          * we generate. This is true by default but you may want to set it to
21407          * false if the html element contains other features that require the
21408          * mouse click.
21409          * @property stopPropagation
21410          * @type boolean
21411          * @static
21412          */
21413         stopPropagation: true,
21414
21415         /**
21416          * Internal flag that is set to true when drag and drop has been
21417          * intialized
21418          * @property initialized
21419          * @private
21420          * @static
21421          */
21422         initalized: false,
21423
21424         /**
21425          * All drag and drop can be disabled.
21426          * @property locked
21427          * @private
21428          * @static
21429          */
21430         locked: false,
21431
21432         /**
21433          * Called the first time an element is registered.
21434          * @method init
21435          * @private
21436          * @static
21437          */
21438         init: function() {
21439             this.initialized = true;
21440         },
21441
21442         /**
21443          * In point mode, drag and drop interaction is defined by the
21444          * location of the cursor during the drag/drop
21445          * @property POINT
21446          * @type int
21447          * @static
21448          */
21449         POINT: 0,
21450
21451         /**
21452          * In intersect mode, drag and drop interactio nis defined by the
21453          * overlap of two or more drag and drop objects.
21454          * @property INTERSECT
21455          * @type int
21456          * @static
21457          */
21458         INTERSECT: 1,
21459
21460         /**
21461          * The current drag and drop mode.  Default: POINT
21462          * @property mode
21463          * @type int
21464          * @static
21465          */
21466         mode: 0,
21467
21468         /**
21469          * Runs method on all drag and drop objects
21470          * @method _execOnAll
21471          * @private
21472          * @static
21473          */
21474         _execOnAll: function(sMethod, args) {
21475             for (var i in this.ids) {
21476                 for (var j in this.ids[i]) {
21477                     var oDD = this.ids[i][j];
21478                     if (! this.isTypeOfDD(oDD)) {
21479                         continue;
21480                     }
21481                     oDD[sMethod].apply(oDD, args);
21482                 }
21483             }
21484         },
21485
21486         /**
21487          * Drag and drop initialization.  Sets up the global event handlers
21488          * @method _onLoad
21489          * @private
21490          * @static
21491          */
21492         _onLoad: function() {
21493
21494             this.init();
21495
21496             if (!Roo.isTouch) {
21497                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21498                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21499             }
21500             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21501             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21502             
21503             Event.on(window,   "unload",    this._onUnload, this, true);
21504             Event.on(window,   "resize",    this._onResize, this, true);
21505             // Event.on(window,   "mouseout",    this._test);
21506
21507         },
21508
21509         /**
21510          * Reset constraints on all drag and drop objs
21511          * @method _onResize
21512          * @private
21513          * @static
21514          */
21515         _onResize: function(e) {
21516             this._execOnAll("resetConstraints", []);
21517         },
21518
21519         /**
21520          * Lock all drag and drop functionality
21521          * @method lock
21522          * @static
21523          */
21524         lock: function() { this.locked = true; },
21525
21526         /**
21527          * Unlock all drag and drop functionality
21528          * @method unlock
21529          * @static
21530          */
21531         unlock: function() { this.locked = false; },
21532
21533         /**
21534          * Is drag and drop locked?
21535          * @method isLocked
21536          * @return {boolean} True if drag and drop is locked, false otherwise.
21537          * @static
21538          */
21539         isLocked: function() { return this.locked; },
21540
21541         /**
21542          * Location cache that is set for all drag drop objects when a drag is
21543          * initiated, cleared when the drag is finished.
21544          * @property locationCache
21545          * @private
21546          * @static
21547          */
21548         locationCache: {},
21549
21550         /**
21551          * Set useCache to false if you want to force object the lookup of each
21552          * drag and drop linked element constantly during a drag.
21553          * @property useCache
21554          * @type boolean
21555          * @static
21556          */
21557         useCache: true,
21558
21559         /**
21560          * The number of pixels that the mouse needs to move after the
21561          * mousedown before the drag is initiated.  Default=3;
21562          * @property clickPixelThresh
21563          * @type int
21564          * @static
21565          */
21566         clickPixelThresh: 3,
21567
21568         /**
21569          * The number of milliseconds after the mousedown event to initiate the
21570          * drag if we don't get a mouseup event. Default=1000
21571          * @property clickTimeThresh
21572          * @type int
21573          * @static
21574          */
21575         clickTimeThresh: 350,
21576
21577         /**
21578          * Flag that indicates that either the drag pixel threshold or the
21579          * mousdown time threshold has been met
21580          * @property dragThreshMet
21581          * @type boolean
21582          * @private
21583          * @static
21584          */
21585         dragThreshMet: false,
21586
21587         /**
21588          * Timeout used for the click time threshold
21589          * @property clickTimeout
21590          * @type Object
21591          * @private
21592          * @static
21593          */
21594         clickTimeout: null,
21595
21596         /**
21597          * The X position of the mousedown event stored for later use when a
21598          * drag threshold is met.
21599          * @property startX
21600          * @type int
21601          * @private
21602          * @static
21603          */
21604         startX: 0,
21605
21606         /**
21607          * The Y position of the mousedown event stored for later use when a
21608          * drag threshold is met.
21609          * @property startY
21610          * @type int
21611          * @private
21612          * @static
21613          */
21614         startY: 0,
21615
21616         /**
21617          * Each DragDrop instance must be registered with the DragDropMgr.
21618          * This is executed in DragDrop.init()
21619          * @method regDragDrop
21620          * @param {DragDrop} oDD the DragDrop object to register
21621          * @param {String} sGroup the name of the group this element belongs to
21622          * @static
21623          */
21624         regDragDrop: function(oDD, sGroup) {
21625             if (!this.initialized) { this.init(); }
21626
21627             if (!this.ids[sGroup]) {
21628                 this.ids[sGroup] = {};
21629             }
21630             this.ids[sGroup][oDD.id] = oDD;
21631         },
21632
21633         /**
21634          * Removes the supplied dd instance from the supplied group. Executed
21635          * by DragDrop.removeFromGroup, so don't call this function directly.
21636          * @method removeDDFromGroup
21637          * @private
21638          * @static
21639          */
21640         removeDDFromGroup: function(oDD, sGroup) {
21641             if (!this.ids[sGroup]) {
21642                 this.ids[sGroup] = {};
21643             }
21644
21645             var obj = this.ids[sGroup];
21646             if (obj && obj[oDD.id]) {
21647                 delete obj[oDD.id];
21648             }
21649         },
21650
21651         /**
21652          * Unregisters a drag and drop item.  This is executed in
21653          * DragDrop.unreg, use that method instead of calling this directly.
21654          * @method _remove
21655          * @private
21656          * @static
21657          */
21658         _remove: function(oDD) {
21659             for (var g in oDD.groups) {
21660                 if (g && this.ids[g][oDD.id]) {
21661                     delete this.ids[g][oDD.id];
21662                 }
21663             }
21664             delete this.handleIds[oDD.id];
21665         },
21666
21667         /**
21668          * Each DragDrop handle element must be registered.  This is done
21669          * automatically when executing DragDrop.setHandleElId()
21670          * @method regHandle
21671          * @param {String} sDDId the DragDrop id this element is a handle for
21672          * @param {String} sHandleId the id of the element that is the drag
21673          * handle
21674          * @static
21675          */
21676         regHandle: function(sDDId, sHandleId) {
21677             if (!this.handleIds[sDDId]) {
21678                 this.handleIds[sDDId] = {};
21679             }
21680             this.handleIds[sDDId][sHandleId] = sHandleId;
21681         },
21682
21683         /**
21684          * Utility function to determine if a given element has been
21685          * registered as a drag drop item.
21686          * @method isDragDrop
21687          * @param {String} id the element id to check
21688          * @return {boolean} true if this element is a DragDrop item,
21689          * false otherwise
21690          * @static
21691          */
21692         isDragDrop: function(id) {
21693             return ( this.getDDById(id) ) ? true : false;
21694         },
21695
21696         /**
21697          * Returns the drag and drop instances that are in all groups the
21698          * passed in instance belongs to.
21699          * @method getRelated
21700          * @param {DragDrop} p_oDD the obj to get related data for
21701          * @param {boolean} bTargetsOnly if true, only return targetable objs
21702          * @return {DragDrop[]} the related instances
21703          * @static
21704          */
21705         getRelated: function(p_oDD, bTargetsOnly) {
21706             var oDDs = [];
21707             for (var i in p_oDD.groups) {
21708                 for (j in this.ids[i]) {
21709                     var dd = this.ids[i][j];
21710                     if (! this.isTypeOfDD(dd)) {
21711                         continue;
21712                     }
21713                     if (!bTargetsOnly || dd.isTarget) {
21714                         oDDs[oDDs.length] = dd;
21715                     }
21716                 }
21717             }
21718
21719             return oDDs;
21720         },
21721
21722         /**
21723          * Returns true if the specified dd target is a legal target for
21724          * the specifice drag obj
21725          * @method isLegalTarget
21726          * @param {DragDrop} the drag obj
21727          * @param {DragDrop} the target
21728          * @return {boolean} true if the target is a legal target for the
21729          * dd obj
21730          * @static
21731          */
21732         isLegalTarget: function (oDD, oTargetDD) {
21733             var targets = this.getRelated(oDD, true);
21734             for (var i=0, len=targets.length;i<len;++i) {
21735                 if (targets[i].id == oTargetDD.id) {
21736                     return true;
21737                 }
21738             }
21739
21740             return false;
21741         },
21742
21743         /**
21744          * My goal is to be able to transparently determine if an object is
21745          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21746          * returns "object", oDD.constructor.toString() always returns
21747          * "DragDrop" and not the name of the subclass.  So for now it just
21748          * evaluates a well-known variable in DragDrop.
21749          * @method isTypeOfDD
21750          * @param {Object} the object to evaluate
21751          * @return {boolean} true if typeof oDD = DragDrop
21752          * @static
21753          */
21754         isTypeOfDD: function (oDD) {
21755             return (oDD && oDD.__ygDragDrop);
21756         },
21757
21758         /**
21759          * Utility function to determine if a given element has been
21760          * registered as a drag drop handle for the given Drag Drop object.
21761          * @method isHandle
21762          * @param {String} id the element id to check
21763          * @return {boolean} true if this element is a DragDrop handle, false
21764          * otherwise
21765          * @static
21766          */
21767         isHandle: function(sDDId, sHandleId) {
21768             return ( this.handleIds[sDDId] &&
21769                             this.handleIds[sDDId][sHandleId] );
21770         },
21771
21772         /**
21773          * Returns the DragDrop instance for a given id
21774          * @method getDDById
21775          * @param {String} id the id of the DragDrop object
21776          * @return {DragDrop} the drag drop object, null if it is not found
21777          * @static
21778          */
21779         getDDById: function(id) {
21780             for (var i in this.ids) {
21781                 if (this.ids[i][id]) {
21782                     return this.ids[i][id];
21783                 }
21784             }
21785             return null;
21786         },
21787
21788         /**
21789          * Fired after a registered DragDrop object gets the mousedown event.
21790          * Sets up the events required to track the object being dragged
21791          * @method handleMouseDown
21792          * @param {Event} e the event
21793          * @param oDD the DragDrop object being dragged
21794          * @private
21795          * @static
21796          */
21797         handleMouseDown: function(e, oDD) {
21798             if(Roo.QuickTips){
21799                 Roo.QuickTips.disable();
21800             }
21801             this.currentTarget = e.getTarget();
21802
21803             this.dragCurrent = oDD;
21804
21805             var el = oDD.getEl();
21806
21807             // track start position
21808             this.startX = e.getPageX();
21809             this.startY = e.getPageY();
21810
21811             this.deltaX = this.startX - el.offsetLeft;
21812             this.deltaY = this.startY - el.offsetTop;
21813
21814             this.dragThreshMet = false;
21815
21816             this.clickTimeout = setTimeout(
21817                     function() {
21818                         var DDM = Roo.dd.DDM;
21819                         DDM.startDrag(DDM.startX, DDM.startY);
21820                     },
21821                     this.clickTimeThresh );
21822         },
21823
21824         /**
21825          * Fired when either the drag pixel threshol or the mousedown hold
21826          * time threshold has been met.
21827          * @method startDrag
21828          * @param x {int} the X position of the original mousedown
21829          * @param y {int} the Y position of the original mousedown
21830          * @static
21831          */
21832         startDrag: function(x, y) {
21833             clearTimeout(this.clickTimeout);
21834             if (this.dragCurrent) {
21835                 this.dragCurrent.b4StartDrag(x, y);
21836                 this.dragCurrent.startDrag(x, y);
21837             }
21838             this.dragThreshMet = true;
21839         },
21840
21841         /**
21842          * Internal function to handle the mouseup event.  Will be invoked
21843          * from the context of the document.
21844          * @method handleMouseUp
21845          * @param {Event} e the event
21846          * @private
21847          * @static
21848          */
21849         handleMouseUp: function(e) {
21850
21851             if(Roo.QuickTips){
21852                 Roo.QuickTips.enable();
21853             }
21854             if (! this.dragCurrent) {
21855                 return;
21856             }
21857
21858             clearTimeout(this.clickTimeout);
21859
21860             if (this.dragThreshMet) {
21861                 this.fireEvents(e, true);
21862             } else {
21863             }
21864
21865             this.stopDrag(e);
21866
21867             this.stopEvent(e);
21868         },
21869
21870         /**
21871          * Utility to stop event propagation and event default, if these
21872          * features are turned on.
21873          * @method stopEvent
21874          * @param {Event} e the event as returned by this.getEvent()
21875          * @static
21876          */
21877         stopEvent: function(e){
21878             if(this.stopPropagation) {
21879                 e.stopPropagation();
21880             }
21881
21882             if (this.preventDefault) {
21883                 e.preventDefault();
21884             }
21885         },
21886
21887         /**
21888          * Internal function to clean up event handlers after the drag
21889          * operation is complete
21890          * @method stopDrag
21891          * @param {Event} e the event
21892          * @private
21893          * @static
21894          */
21895         stopDrag: function(e) {
21896             // Fire the drag end event for the item that was dragged
21897             if (this.dragCurrent) {
21898                 if (this.dragThreshMet) {
21899                     this.dragCurrent.b4EndDrag(e);
21900                     this.dragCurrent.endDrag(e);
21901                 }
21902
21903                 this.dragCurrent.onMouseUp(e);
21904             }
21905
21906             this.dragCurrent = null;
21907             this.dragOvers = {};
21908         },
21909
21910         /**
21911          * Internal function to handle the mousemove event.  Will be invoked
21912          * from the context of the html element.
21913          *
21914          * @TODO figure out what we can do about mouse events lost when the
21915          * user drags objects beyond the window boundary.  Currently we can
21916          * detect this in internet explorer by verifying that the mouse is
21917          * down during the mousemove event.  Firefox doesn't give us the
21918          * button state on the mousemove event.
21919          * @method handleMouseMove
21920          * @param {Event} e the event
21921          * @private
21922          * @static
21923          */
21924         handleMouseMove: function(e) {
21925             if (! this.dragCurrent) {
21926                 return true;
21927             }
21928
21929             // var button = e.which || e.button;
21930
21931             // check for IE mouseup outside of page boundary
21932             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21933                 this.stopEvent(e);
21934                 return this.handleMouseUp(e);
21935             }
21936
21937             if (!this.dragThreshMet) {
21938                 var diffX = Math.abs(this.startX - e.getPageX());
21939                 var diffY = Math.abs(this.startY - e.getPageY());
21940                 if (diffX > this.clickPixelThresh ||
21941                             diffY > this.clickPixelThresh) {
21942                     this.startDrag(this.startX, this.startY);
21943                 }
21944             }
21945
21946             if (this.dragThreshMet) {
21947                 this.dragCurrent.b4Drag(e);
21948                 this.dragCurrent.onDrag(e);
21949                 if(!this.dragCurrent.moveOnly){
21950                     this.fireEvents(e, false);
21951                 }
21952             }
21953
21954             this.stopEvent(e);
21955
21956             return true;
21957         },
21958
21959         /**
21960          * Iterates over all of the DragDrop elements to find ones we are
21961          * hovering over or dropping on
21962          * @method fireEvents
21963          * @param {Event} e the event
21964          * @param {boolean} isDrop is this a drop op or a mouseover op?
21965          * @private
21966          * @static
21967          */
21968         fireEvents: function(e, isDrop) {
21969             var dc = this.dragCurrent;
21970
21971             // If the user did the mouse up outside of the window, we could
21972             // get here even though we have ended the drag.
21973             if (!dc || dc.isLocked()) {
21974                 return;
21975             }
21976
21977             var pt = e.getPoint();
21978
21979             // cache the previous dragOver array
21980             var oldOvers = [];
21981
21982             var outEvts   = [];
21983             var overEvts  = [];
21984             var dropEvts  = [];
21985             var enterEvts = [];
21986
21987             // Check to see if the object(s) we were hovering over is no longer
21988             // being hovered over so we can fire the onDragOut event
21989             for (var i in this.dragOvers) {
21990
21991                 var ddo = this.dragOvers[i];
21992
21993                 if (! this.isTypeOfDD(ddo)) {
21994                     continue;
21995                 }
21996
21997                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21998                     outEvts.push( ddo );
21999                 }
22000
22001                 oldOvers[i] = true;
22002                 delete this.dragOvers[i];
22003             }
22004
22005             for (var sGroup in dc.groups) {
22006
22007                 if ("string" != typeof sGroup) {
22008                     continue;
22009                 }
22010
22011                 for (i in this.ids[sGroup]) {
22012                     var oDD = this.ids[sGroup][i];
22013                     if (! this.isTypeOfDD(oDD)) {
22014                         continue;
22015                     }
22016
22017                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22018                         if (this.isOverTarget(pt, oDD, this.mode)) {
22019                             // look for drop interactions
22020                             if (isDrop) {
22021                                 dropEvts.push( oDD );
22022                             // look for drag enter and drag over interactions
22023                             } else {
22024
22025                                 // initial drag over: dragEnter fires
22026                                 if (!oldOvers[oDD.id]) {
22027                                     enterEvts.push( oDD );
22028                                 // subsequent drag overs: dragOver fires
22029                                 } else {
22030                                     overEvts.push( oDD );
22031                                 }
22032
22033                                 this.dragOvers[oDD.id] = oDD;
22034                             }
22035                         }
22036                     }
22037                 }
22038             }
22039
22040             if (this.mode) {
22041                 if (outEvts.length) {
22042                     dc.b4DragOut(e, outEvts);
22043                     dc.onDragOut(e, outEvts);
22044                 }
22045
22046                 if (enterEvts.length) {
22047                     dc.onDragEnter(e, enterEvts);
22048                 }
22049
22050                 if (overEvts.length) {
22051                     dc.b4DragOver(e, overEvts);
22052                     dc.onDragOver(e, overEvts);
22053                 }
22054
22055                 if (dropEvts.length) {
22056                     dc.b4DragDrop(e, dropEvts);
22057                     dc.onDragDrop(e, dropEvts);
22058                 }
22059
22060             } else {
22061                 // fire dragout events
22062                 var len = 0;
22063                 for (i=0, len=outEvts.length; i<len; ++i) {
22064                     dc.b4DragOut(e, outEvts[i].id);
22065                     dc.onDragOut(e, outEvts[i].id);
22066                 }
22067
22068                 // fire enter events
22069                 for (i=0,len=enterEvts.length; i<len; ++i) {
22070                     // dc.b4DragEnter(e, oDD.id);
22071                     dc.onDragEnter(e, enterEvts[i].id);
22072                 }
22073
22074                 // fire over events
22075                 for (i=0,len=overEvts.length; i<len; ++i) {
22076                     dc.b4DragOver(e, overEvts[i].id);
22077                     dc.onDragOver(e, overEvts[i].id);
22078                 }
22079
22080                 // fire drop events
22081                 for (i=0, len=dropEvts.length; i<len; ++i) {
22082                     dc.b4DragDrop(e, dropEvts[i].id);
22083                     dc.onDragDrop(e, dropEvts[i].id);
22084                 }
22085
22086             }
22087
22088             // notify about a drop that did not find a target
22089             if (isDrop && !dropEvts.length) {
22090                 dc.onInvalidDrop(e);
22091             }
22092
22093         },
22094
22095         /**
22096          * Helper function for getting the best match from the list of drag
22097          * and drop objects returned by the drag and drop events when we are
22098          * in INTERSECT mode.  It returns either the first object that the
22099          * cursor is over, or the object that has the greatest overlap with
22100          * the dragged element.
22101          * @method getBestMatch
22102          * @param  {DragDrop[]} dds The array of drag and drop objects
22103          * targeted
22104          * @return {DragDrop}       The best single match
22105          * @static
22106          */
22107         getBestMatch: function(dds) {
22108             var winner = null;
22109             // Return null if the input is not what we expect
22110             //if (!dds || !dds.length || dds.length == 0) {
22111                // winner = null;
22112             // If there is only one item, it wins
22113             //} else if (dds.length == 1) {
22114
22115             var len = dds.length;
22116
22117             if (len == 1) {
22118                 winner = dds[0];
22119             } else {
22120                 // Loop through the targeted items
22121                 for (var i=0; i<len; ++i) {
22122                     var dd = dds[i];
22123                     // If the cursor is over the object, it wins.  If the
22124                     // cursor is over multiple matches, the first one we come
22125                     // to wins.
22126                     if (dd.cursorIsOver) {
22127                         winner = dd;
22128                         break;
22129                     // Otherwise the object with the most overlap wins
22130                     } else {
22131                         if (!winner ||
22132                             winner.overlap.getArea() < dd.overlap.getArea()) {
22133                             winner = dd;
22134                         }
22135                     }
22136                 }
22137             }
22138
22139             return winner;
22140         },
22141
22142         /**
22143          * Refreshes the cache of the top-left and bottom-right points of the
22144          * drag and drop objects in the specified group(s).  This is in the
22145          * format that is stored in the drag and drop instance, so typical
22146          * usage is:
22147          * <code>
22148          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22149          * </code>
22150          * Alternatively:
22151          * <code>
22152          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22153          * </code>
22154          * @TODO this really should be an indexed array.  Alternatively this
22155          * method could accept both.
22156          * @method refreshCache
22157          * @param {Object} groups an associative array of groups to refresh
22158          * @static
22159          */
22160         refreshCache: function(groups) {
22161             for (var sGroup in groups) {
22162                 if ("string" != typeof sGroup) {
22163                     continue;
22164                 }
22165                 for (var i in this.ids[sGroup]) {
22166                     var oDD = this.ids[sGroup][i];
22167
22168                     if (this.isTypeOfDD(oDD)) {
22169                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22170                         var loc = this.getLocation(oDD);
22171                         if (loc) {
22172                             this.locationCache[oDD.id] = loc;
22173                         } else {
22174                             delete this.locationCache[oDD.id];
22175                             // this will unregister the drag and drop object if
22176                             // the element is not in a usable state
22177                             // oDD.unreg();
22178                         }
22179                     }
22180                 }
22181             }
22182         },
22183
22184         /**
22185          * This checks to make sure an element exists and is in the DOM.  The
22186          * main purpose is to handle cases where innerHTML is used to remove
22187          * drag and drop objects from the DOM.  IE provides an 'unspecified
22188          * error' when trying to access the offsetParent of such an element
22189          * @method verifyEl
22190          * @param {HTMLElement} el the element to check
22191          * @return {boolean} true if the element looks usable
22192          * @static
22193          */
22194         verifyEl: function(el) {
22195             if (el) {
22196                 var parent;
22197                 if(Roo.isIE){
22198                     try{
22199                         parent = el.offsetParent;
22200                     }catch(e){}
22201                 }else{
22202                     parent = el.offsetParent;
22203                 }
22204                 if (parent) {
22205                     return true;
22206                 }
22207             }
22208
22209             return false;
22210         },
22211
22212         /**
22213          * Returns a Region object containing the drag and drop element's position
22214          * and size, including the padding configured for it
22215          * @method getLocation
22216          * @param {DragDrop} oDD the drag and drop object to get the
22217          *                       location for
22218          * @return {Roo.lib.Region} a Region object representing the total area
22219          *                             the element occupies, including any padding
22220          *                             the instance is configured for.
22221          * @static
22222          */
22223         getLocation: function(oDD) {
22224             if (! this.isTypeOfDD(oDD)) {
22225                 return null;
22226             }
22227
22228             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22229
22230             try {
22231                 pos= Roo.lib.Dom.getXY(el);
22232             } catch (e) { }
22233
22234             if (!pos) {
22235                 return null;
22236             }
22237
22238             x1 = pos[0];
22239             x2 = x1 + el.offsetWidth;
22240             y1 = pos[1];
22241             y2 = y1 + el.offsetHeight;
22242
22243             t = y1 - oDD.padding[0];
22244             r = x2 + oDD.padding[1];
22245             b = y2 + oDD.padding[2];
22246             l = x1 - oDD.padding[3];
22247
22248             return new Roo.lib.Region( t, r, b, l );
22249         },
22250
22251         /**
22252          * Checks the cursor location to see if it over the target
22253          * @method isOverTarget
22254          * @param {Roo.lib.Point} pt The point to evaluate
22255          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22256          * @return {boolean} true if the mouse is over the target
22257          * @private
22258          * @static
22259          */
22260         isOverTarget: function(pt, oTarget, intersect) {
22261             // use cache if available
22262             var loc = this.locationCache[oTarget.id];
22263             if (!loc || !this.useCache) {
22264                 loc = this.getLocation(oTarget);
22265                 this.locationCache[oTarget.id] = loc;
22266
22267             }
22268
22269             if (!loc) {
22270                 return false;
22271             }
22272
22273             oTarget.cursorIsOver = loc.contains( pt );
22274
22275             // DragDrop is using this as a sanity check for the initial mousedown
22276             // in this case we are done.  In POINT mode, if the drag obj has no
22277             // contraints, we are also done. Otherwise we need to evaluate the
22278             // location of the target as related to the actual location of the
22279             // dragged element.
22280             var dc = this.dragCurrent;
22281             if (!dc || !dc.getTargetCoord ||
22282                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22283                 return oTarget.cursorIsOver;
22284             }
22285
22286             oTarget.overlap = null;
22287
22288             // Get the current location of the drag element, this is the
22289             // location of the mouse event less the delta that represents
22290             // where the original mousedown happened on the element.  We
22291             // need to consider constraints and ticks as well.
22292             var pos = dc.getTargetCoord(pt.x, pt.y);
22293
22294             var el = dc.getDragEl();
22295             var curRegion = new Roo.lib.Region( pos.y,
22296                                                    pos.x + el.offsetWidth,
22297                                                    pos.y + el.offsetHeight,
22298                                                    pos.x );
22299
22300             var overlap = curRegion.intersect(loc);
22301
22302             if (overlap) {
22303                 oTarget.overlap = overlap;
22304                 return (intersect) ? true : oTarget.cursorIsOver;
22305             } else {
22306                 return false;
22307             }
22308         },
22309
22310         /**
22311          * unload event handler
22312          * @method _onUnload
22313          * @private
22314          * @static
22315          */
22316         _onUnload: function(e, me) {
22317             Roo.dd.DragDropMgr.unregAll();
22318         },
22319
22320         /**
22321          * Cleans up the drag and drop events and objects.
22322          * @method unregAll
22323          * @private
22324          * @static
22325          */
22326         unregAll: function() {
22327
22328             if (this.dragCurrent) {
22329                 this.stopDrag();
22330                 this.dragCurrent = null;
22331             }
22332
22333             this._execOnAll("unreg", []);
22334
22335             for (i in this.elementCache) {
22336                 delete this.elementCache[i];
22337             }
22338
22339             this.elementCache = {};
22340             this.ids = {};
22341         },
22342
22343         /**
22344          * A cache of DOM elements
22345          * @property elementCache
22346          * @private
22347          * @static
22348          */
22349         elementCache: {},
22350
22351         /**
22352          * Get the wrapper for the DOM element specified
22353          * @method getElWrapper
22354          * @param {String} id the id of the element to get
22355          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22356          * @private
22357          * @deprecated This wrapper isn't that useful
22358          * @static
22359          */
22360         getElWrapper: function(id) {
22361             var oWrapper = this.elementCache[id];
22362             if (!oWrapper || !oWrapper.el) {
22363                 oWrapper = this.elementCache[id] =
22364                     new this.ElementWrapper(Roo.getDom(id));
22365             }
22366             return oWrapper;
22367         },
22368
22369         /**
22370          * Returns the actual DOM element
22371          * @method getElement
22372          * @param {String} id the id of the elment to get
22373          * @return {Object} The element
22374          * @deprecated use Roo.getDom instead
22375          * @static
22376          */
22377         getElement: function(id) {
22378             return Roo.getDom(id);
22379         },
22380
22381         /**
22382          * Returns the style property for the DOM element (i.e.,
22383          * document.getElById(id).style)
22384          * @method getCss
22385          * @param {String} id the id of the elment to get
22386          * @return {Object} The style property of the element
22387          * @deprecated use Roo.getDom instead
22388          * @static
22389          */
22390         getCss: function(id) {
22391             var el = Roo.getDom(id);
22392             return (el) ? el.style : null;
22393         },
22394
22395         /**
22396          * Inner class for cached elements
22397          * @class DragDropMgr.ElementWrapper
22398          * @for DragDropMgr
22399          * @private
22400          * @deprecated
22401          */
22402         ElementWrapper: function(el) {
22403                 /**
22404                  * The element
22405                  * @property el
22406                  */
22407                 this.el = el || null;
22408                 /**
22409                  * The element id
22410                  * @property id
22411                  */
22412                 this.id = this.el && el.id;
22413                 /**
22414                  * A reference to the style property
22415                  * @property css
22416                  */
22417                 this.css = this.el && el.style;
22418             },
22419
22420         /**
22421          * Returns the X position of an html element
22422          * @method getPosX
22423          * @param el the element for which to get the position
22424          * @return {int} the X coordinate
22425          * @for DragDropMgr
22426          * @deprecated use Roo.lib.Dom.getX instead
22427          * @static
22428          */
22429         getPosX: function(el) {
22430             return Roo.lib.Dom.getX(el);
22431         },
22432
22433         /**
22434          * Returns the Y position of an html element
22435          * @method getPosY
22436          * @param el the element for which to get the position
22437          * @return {int} the Y coordinate
22438          * @deprecated use Roo.lib.Dom.getY instead
22439          * @static
22440          */
22441         getPosY: function(el) {
22442             return Roo.lib.Dom.getY(el);
22443         },
22444
22445         /**
22446          * Swap two nodes.  In IE, we use the native method, for others we
22447          * emulate the IE behavior
22448          * @method swapNode
22449          * @param n1 the first node to swap
22450          * @param n2 the other node to swap
22451          * @static
22452          */
22453         swapNode: function(n1, n2) {
22454             if (n1.swapNode) {
22455                 n1.swapNode(n2);
22456             } else {
22457                 var p = n2.parentNode;
22458                 var s = n2.nextSibling;
22459
22460                 if (s == n1) {
22461                     p.insertBefore(n1, n2);
22462                 } else if (n2 == n1.nextSibling) {
22463                     p.insertBefore(n2, n1);
22464                 } else {
22465                     n1.parentNode.replaceChild(n2, n1);
22466                     p.insertBefore(n1, s);
22467                 }
22468             }
22469         },
22470
22471         /**
22472          * Returns the current scroll position
22473          * @method getScroll
22474          * @private
22475          * @static
22476          */
22477         getScroll: function () {
22478             var t, l, dde=document.documentElement, db=document.body;
22479             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22480                 t = dde.scrollTop;
22481                 l = dde.scrollLeft;
22482             } else if (db) {
22483                 t = db.scrollTop;
22484                 l = db.scrollLeft;
22485             } else {
22486
22487             }
22488             return { top: t, left: l };
22489         },
22490
22491         /**
22492          * Returns the specified element style property
22493          * @method getStyle
22494          * @param {HTMLElement} el          the element
22495          * @param {string}      styleProp   the style property
22496          * @return {string} The value of the style property
22497          * @deprecated use Roo.lib.Dom.getStyle
22498          * @static
22499          */
22500         getStyle: function(el, styleProp) {
22501             return Roo.fly(el).getStyle(styleProp);
22502         },
22503
22504         /**
22505          * Gets the scrollTop
22506          * @method getScrollTop
22507          * @return {int} the document's scrollTop
22508          * @static
22509          */
22510         getScrollTop: function () { return this.getScroll().top; },
22511
22512         /**
22513          * Gets the scrollLeft
22514          * @method getScrollLeft
22515          * @return {int} the document's scrollTop
22516          * @static
22517          */
22518         getScrollLeft: function () { return this.getScroll().left; },
22519
22520         /**
22521          * Sets the x/y position of an element to the location of the
22522          * target element.
22523          * @method moveToEl
22524          * @param {HTMLElement} moveEl      The element to move
22525          * @param {HTMLElement} targetEl    The position reference element
22526          * @static
22527          */
22528         moveToEl: function (moveEl, targetEl) {
22529             var aCoord = Roo.lib.Dom.getXY(targetEl);
22530             Roo.lib.Dom.setXY(moveEl, aCoord);
22531         },
22532
22533         /**
22534          * Numeric array sort function
22535          * @method numericSort
22536          * @static
22537          */
22538         numericSort: function(a, b) { return (a - b); },
22539
22540         /**
22541          * Internal counter
22542          * @property _timeoutCount
22543          * @private
22544          * @static
22545          */
22546         _timeoutCount: 0,
22547
22548         /**
22549          * Trying to make the load order less important.  Without this we get
22550          * an error if this file is loaded before the Event Utility.
22551          * @method _addListeners
22552          * @private
22553          * @static
22554          */
22555         _addListeners: function() {
22556             var DDM = Roo.dd.DDM;
22557             if ( Roo.lib.Event && document ) {
22558                 DDM._onLoad();
22559             } else {
22560                 if (DDM._timeoutCount > 2000) {
22561                 } else {
22562                     setTimeout(DDM._addListeners, 10);
22563                     if (document && document.body) {
22564                         DDM._timeoutCount += 1;
22565                     }
22566                 }
22567             }
22568         },
22569
22570         /**
22571          * Recursively searches the immediate parent and all child nodes for
22572          * the handle element in order to determine wheter or not it was
22573          * clicked.
22574          * @method handleWasClicked
22575          * @param node the html element to inspect
22576          * @static
22577          */
22578         handleWasClicked: function(node, id) {
22579             if (this.isHandle(id, node.id)) {
22580                 return true;
22581             } else {
22582                 // check to see if this is a text node child of the one we want
22583                 var p = node.parentNode;
22584
22585                 while (p) {
22586                     if (this.isHandle(id, p.id)) {
22587                         return true;
22588                     } else {
22589                         p = p.parentNode;
22590                     }
22591                 }
22592             }
22593
22594             return false;
22595         }
22596
22597     };
22598
22599 }();
22600
22601 // shorter alias, save a few bytes
22602 Roo.dd.DDM = Roo.dd.DragDropMgr;
22603 Roo.dd.DDM._addListeners();
22604
22605 }/*
22606  * Based on:
22607  * Ext JS Library 1.1.1
22608  * Copyright(c) 2006-2007, Ext JS, LLC.
22609  *
22610  * Originally Released Under LGPL - original licence link has changed is not relivant.
22611  *
22612  * Fork - LGPL
22613  * <script type="text/javascript">
22614  */
22615
22616 /**
22617  * @class Roo.dd.DD
22618  * A DragDrop implementation where the linked element follows the
22619  * mouse cursor during a drag.
22620  * @extends Roo.dd.DragDrop
22621  * @constructor
22622  * @param {String} id the id of the linked element
22623  * @param {String} sGroup the group of related DragDrop items
22624  * @param {object} config an object containing configurable attributes
22625  *                Valid properties for DD:
22626  *                    scroll
22627  */
22628 Roo.dd.DD = function(id, sGroup, config) {
22629     if (id) {
22630         this.init(id, sGroup, config);
22631     }
22632 };
22633
22634 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22635
22636     /**
22637      * When set to true, the utility automatically tries to scroll the browser
22638      * window wehn a drag and drop element is dragged near the viewport boundary.
22639      * Defaults to true.
22640      * @property scroll
22641      * @type boolean
22642      */
22643     scroll: true,
22644
22645     /**
22646      * Sets the pointer offset to the distance between the linked element's top
22647      * left corner and the location the element was clicked
22648      * @method autoOffset
22649      * @param {int} iPageX the X coordinate of the click
22650      * @param {int} iPageY the Y coordinate of the click
22651      */
22652     autoOffset: function(iPageX, iPageY) {
22653         var x = iPageX - this.startPageX;
22654         var y = iPageY - this.startPageY;
22655         this.setDelta(x, y);
22656     },
22657
22658     /**
22659      * Sets the pointer offset.  You can call this directly to force the
22660      * offset to be in a particular location (e.g., pass in 0,0 to set it
22661      * to the center of the object)
22662      * @method setDelta
22663      * @param {int} iDeltaX the distance from the left
22664      * @param {int} iDeltaY the distance from the top
22665      */
22666     setDelta: function(iDeltaX, iDeltaY) {
22667         this.deltaX = iDeltaX;
22668         this.deltaY = iDeltaY;
22669     },
22670
22671     /**
22672      * Sets the drag element to the location of the mousedown or click event,
22673      * maintaining the cursor location relative to the location on the element
22674      * that was clicked.  Override this if you want to place the element in a
22675      * location other than where the cursor is.
22676      * @method setDragElPos
22677      * @param {int} iPageX the X coordinate of the mousedown or drag event
22678      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22679      */
22680     setDragElPos: function(iPageX, iPageY) {
22681         // the first time we do this, we are going to check to make sure
22682         // the element has css positioning
22683
22684         var el = this.getDragEl();
22685         this.alignElWithMouse(el, iPageX, iPageY);
22686     },
22687
22688     /**
22689      * Sets the element to the location of the mousedown or click event,
22690      * maintaining the cursor location relative to the location on the element
22691      * that was clicked.  Override this if you want to place the element in a
22692      * location other than where the cursor is.
22693      * @method alignElWithMouse
22694      * @param {HTMLElement} el the element to move
22695      * @param {int} iPageX the X coordinate of the mousedown or drag event
22696      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22697      */
22698     alignElWithMouse: function(el, iPageX, iPageY) {
22699         var oCoord = this.getTargetCoord(iPageX, iPageY);
22700         var fly = el.dom ? el : Roo.fly(el);
22701         if (!this.deltaSetXY) {
22702             var aCoord = [oCoord.x, oCoord.y];
22703             fly.setXY(aCoord);
22704             var newLeft = fly.getLeft(true);
22705             var newTop  = fly.getTop(true);
22706             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22707         } else {
22708             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22709         }
22710
22711         this.cachePosition(oCoord.x, oCoord.y);
22712         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22713         return oCoord;
22714     },
22715
22716     /**
22717      * Saves the most recent position so that we can reset the constraints and
22718      * tick marks on-demand.  We need to know this so that we can calculate the
22719      * number of pixels the element is offset from its original position.
22720      * @method cachePosition
22721      * @param iPageX the current x position (optional, this just makes it so we
22722      * don't have to look it up again)
22723      * @param iPageY the current y position (optional, this just makes it so we
22724      * don't have to look it up again)
22725      */
22726     cachePosition: function(iPageX, iPageY) {
22727         if (iPageX) {
22728             this.lastPageX = iPageX;
22729             this.lastPageY = iPageY;
22730         } else {
22731             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22732             this.lastPageX = aCoord[0];
22733             this.lastPageY = aCoord[1];
22734         }
22735     },
22736
22737     /**
22738      * Auto-scroll the window if the dragged object has been moved beyond the
22739      * visible window boundary.
22740      * @method autoScroll
22741      * @param {int} x the drag element's x position
22742      * @param {int} y the drag element's y position
22743      * @param {int} h the height of the drag element
22744      * @param {int} w the width of the drag element
22745      * @private
22746      */
22747     autoScroll: function(x, y, h, w) {
22748
22749         if (this.scroll) {
22750             // The client height
22751             var clientH = Roo.lib.Dom.getViewWidth();
22752
22753             // The client width
22754             var clientW = Roo.lib.Dom.getViewHeight();
22755
22756             // The amt scrolled down
22757             var st = this.DDM.getScrollTop();
22758
22759             // The amt scrolled right
22760             var sl = this.DDM.getScrollLeft();
22761
22762             // Location of the bottom of the element
22763             var bot = h + y;
22764
22765             // Location of the right of the element
22766             var right = w + x;
22767
22768             // The distance from the cursor to the bottom of the visible area,
22769             // adjusted so that we don't scroll if the cursor is beyond the
22770             // element drag constraints
22771             var toBot = (clientH + st - y - this.deltaY);
22772
22773             // The distance from the cursor to the right of the visible area
22774             var toRight = (clientW + sl - x - this.deltaX);
22775
22776
22777             // How close to the edge the cursor must be before we scroll
22778             // var thresh = (document.all) ? 100 : 40;
22779             var thresh = 40;
22780
22781             // How many pixels to scroll per autoscroll op.  This helps to reduce
22782             // clunky scrolling. IE is more sensitive about this ... it needs this
22783             // value to be higher.
22784             var scrAmt = (document.all) ? 80 : 30;
22785
22786             // Scroll down if we are near the bottom of the visible page and the
22787             // obj extends below the crease
22788             if ( bot > clientH && toBot < thresh ) {
22789                 window.scrollTo(sl, st + scrAmt);
22790             }
22791
22792             // Scroll up if the window is scrolled down and the top of the object
22793             // goes above the top border
22794             if ( y < st && st > 0 && y - st < thresh ) {
22795                 window.scrollTo(sl, st - scrAmt);
22796             }
22797
22798             // Scroll right if the obj is beyond the right border and the cursor is
22799             // near the border.
22800             if ( right > clientW && toRight < thresh ) {
22801                 window.scrollTo(sl + scrAmt, st);
22802             }
22803
22804             // Scroll left if the window has been scrolled to the right and the obj
22805             // extends past the left border
22806             if ( x < sl && sl > 0 && x - sl < thresh ) {
22807                 window.scrollTo(sl - scrAmt, st);
22808             }
22809         }
22810     },
22811
22812     /**
22813      * Finds the location the element should be placed if we want to move
22814      * it to where the mouse location less the click offset would place us.
22815      * @method getTargetCoord
22816      * @param {int} iPageX the X coordinate of the click
22817      * @param {int} iPageY the Y coordinate of the click
22818      * @return an object that contains the coordinates (Object.x and Object.y)
22819      * @private
22820      */
22821     getTargetCoord: function(iPageX, iPageY) {
22822
22823
22824         var x = iPageX - this.deltaX;
22825         var y = iPageY - this.deltaY;
22826
22827         if (this.constrainX) {
22828             if (x < this.minX) { x = this.minX; }
22829             if (x > this.maxX) { x = this.maxX; }
22830         }
22831
22832         if (this.constrainY) {
22833             if (y < this.minY) { y = this.minY; }
22834             if (y > this.maxY) { y = this.maxY; }
22835         }
22836
22837         x = this.getTick(x, this.xTicks);
22838         y = this.getTick(y, this.yTicks);
22839
22840
22841         return {x:x, y:y};
22842     },
22843
22844     /*
22845      * Sets up config options specific to this class. Overrides
22846      * Roo.dd.DragDrop, but all versions of this method through the
22847      * inheritance chain are called
22848      */
22849     applyConfig: function() {
22850         Roo.dd.DD.superclass.applyConfig.call(this);
22851         this.scroll = (this.config.scroll !== false);
22852     },
22853
22854     /*
22855      * Event that fires prior to the onMouseDown event.  Overrides
22856      * Roo.dd.DragDrop.
22857      */
22858     b4MouseDown: function(e) {
22859         // this.resetConstraints();
22860         this.autoOffset(e.getPageX(),
22861                             e.getPageY());
22862     },
22863
22864     /*
22865      * Event that fires prior to the onDrag event.  Overrides
22866      * Roo.dd.DragDrop.
22867      */
22868     b4Drag: function(e) {
22869         this.setDragElPos(e.getPageX(),
22870                             e.getPageY());
22871     },
22872
22873     toString: function() {
22874         return ("DD " + this.id);
22875     }
22876
22877     //////////////////////////////////////////////////////////////////////////
22878     // Debugging ygDragDrop events that can be overridden
22879     //////////////////////////////////////////////////////////////////////////
22880     /*
22881     startDrag: function(x, y) {
22882     },
22883
22884     onDrag: function(e) {
22885     },
22886
22887     onDragEnter: function(e, id) {
22888     },
22889
22890     onDragOver: function(e, id) {
22891     },
22892
22893     onDragOut: function(e, id) {
22894     },
22895
22896     onDragDrop: function(e, id) {
22897     },
22898
22899     endDrag: function(e) {
22900     }
22901
22902     */
22903
22904 });/*
22905  * Based on:
22906  * Ext JS Library 1.1.1
22907  * Copyright(c) 2006-2007, Ext JS, LLC.
22908  *
22909  * Originally Released Under LGPL - original licence link has changed is not relivant.
22910  *
22911  * Fork - LGPL
22912  * <script type="text/javascript">
22913  */
22914
22915 /**
22916  * @class Roo.dd.DDProxy
22917  * A DragDrop implementation that inserts an empty, bordered div into
22918  * the document that follows the cursor during drag operations.  At the time of
22919  * the click, the frame div is resized to the dimensions of the linked html
22920  * element, and moved to the exact location of the linked element.
22921  *
22922  * References to the "frame" element refer to the single proxy element that
22923  * was created to be dragged in place of all DDProxy elements on the
22924  * page.
22925  *
22926  * @extends Roo.dd.DD
22927  * @constructor
22928  * @param {String} id the id of the linked html element
22929  * @param {String} sGroup the group of related DragDrop objects
22930  * @param {object} config an object containing configurable attributes
22931  *                Valid properties for DDProxy in addition to those in DragDrop:
22932  *                   resizeFrame, centerFrame, dragElId
22933  */
22934 Roo.dd.DDProxy = function(id, sGroup, config) {
22935     if (id) {
22936         this.init(id, sGroup, config);
22937         this.initFrame();
22938     }
22939 };
22940
22941 /**
22942  * The default drag frame div id
22943  * @property Roo.dd.DDProxy.dragElId
22944  * @type String
22945  * @static
22946  */
22947 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22948
22949 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22950
22951     /**
22952      * By default we resize the drag frame to be the same size as the element
22953      * we want to drag (this is to get the frame effect).  We can turn it off
22954      * if we want a different behavior.
22955      * @property resizeFrame
22956      * @type boolean
22957      */
22958     resizeFrame: true,
22959
22960     /**
22961      * By default the frame is positioned exactly where the drag element is, so
22962      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22963      * you do not have constraints on the obj is to have the drag frame centered
22964      * around the cursor.  Set centerFrame to true for this effect.
22965      * @property centerFrame
22966      * @type boolean
22967      */
22968     centerFrame: false,
22969
22970     /**
22971      * Creates the proxy element if it does not yet exist
22972      * @method createFrame
22973      */
22974     createFrame: function() {
22975         var self = this;
22976         var body = document.body;
22977
22978         if (!body || !body.firstChild) {
22979             setTimeout( function() { self.createFrame(); }, 50 );
22980             return;
22981         }
22982
22983         var div = this.getDragEl();
22984
22985         if (!div) {
22986             div    = document.createElement("div");
22987             div.id = this.dragElId;
22988             var s  = div.style;
22989
22990             s.position   = "absolute";
22991             s.visibility = "hidden";
22992             s.cursor     = "move";
22993             s.border     = "2px solid #aaa";
22994             s.zIndex     = 999;
22995
22996             // appendChild can blow up IE if invoked prior to the window load event
22997             // while rendering a table.  It is possible there are other scenarios
22998             // that would cause this to happen as well.
22999             body.insertBefore(div, body.firstChild);
23000         }
23001     },
23002
23003     /**
23004      * Initialization for the drag frame element.  Must be called in the
23005      * constructor of all subclasses
23006      * @method initFrame
23007      */
23008     initFrame: function() {
23009         this.createFrame();
23010     },
23011
23012     applyConfig: function() {
23013         Roo.dd.DDProxy.superclass.applyConfig.call(this);
23014
23015         this.resizeFrame = (this.config.resizeFrame !== false);
23016         this.centerFrame = (this.config.centerFrame);
23017         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23018     },
23019
23020     /**
23021      * Resizes the drag frame to the dimensions of the clicked object, positions
23022      * it over the object, and finally displays it
23023      * @method showFrame
23024      * @param {int} iPageX X click position
23025      * @param {int} iPageY Y click position
23026      * @private
23027      */
23028     showFrame: function(iPageX, iPageY) {
23029         var el = this.getEl();
23030         var dragEl = this.getDragEl();
23031         var s = dragEl.style;
23032
23033         this._resizeProxy();
23034
23035         if (this.centerFrame) {
23036             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23037                            Math.round(parseInt(s.height, 10)/2) );
23038         }
23039
23040         this.setDragElPos(iPageX, iPageY);
23041
23042         Roo.fly(dragEl).show();
23043     },
23044
23045     /**
23046      * The proxy is automatically resized to the dimensions of the linked
23047      * element when a drag is initiated, unless resizeFrame is set to false
23048      * @method _resizeProxy
23049      * @private
23050      */
23051     _resizeProxy: function() {
23052         if (this.resizeFrame) {
23053             var el = this.getEl();
23054             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23055         }
23056     },
23057
23058     // overrides Roo.dd.DragDrop
23059     b4MouseDown: function(e) {
23060         var x = e.getPageX();
23061         var y = e.getPageY();
23062         this.autoOffset(x, y);
23063         this.setDragElPos(x, y);
23064     },
23065
23066     // overrides Roo.dd.DragDrop
23067     b4StartDrag: function(x, y) {
23068         // show the drag frame
23069         this.showFrame(x, y);
23070     },
23071
23072     // overrides Roo.dd.DragDrop
23073     b4EndDrag: function(e) {
23074         Roo.fly(this.getDragEl()).hide();
23075     },
23076
23077     // overrides Roo.dd.DragDrop
23078     // By default we try to move the element to the last location of the frame.
23079     // This is so that the default behavior mirrors that of Roo.dd.DD.
23080     endDrag: function(e) {
23081
23082         var lel = this.getEl();
23083         var del = this.getDragEl();
23084
23085         // Show the drag frame briefly so we can get its position
23086         del.style.visibility = "";
23087
23088         this.beforeMove();
23089         // Hide the linked element before the move to get around a Safari
23090         // rendering bug.
23091         lel.style.visibility = "hidden";
23092         Roo.dd.DDM.moveToEl(lel, del);
23093         del.style.visibility = "hidden";
23094         lel.style.visibility = "";
23095
23096         this.afterDrag();
23097     },
23098
23099     beforeMove : function(){
23100
23101     },
23102
23103     afterDrag : function(){
23104
23105     },
23106
23107     toString: function() {
23108         return ("DDProxy " + this.id);
23109     }
23110
23111 });
23112 /*
23113  * Based on:
23114  * Ext JS Library 1.1.1
23115  * Copyright(c) 2006-2007, Ext JS, LLC.
23116  *
23117  * Originally Released Under LGPL - original licence link has changed is not relivant.
23118  *
23119  * Fork - LGPL
23120  * <script type="text/javascript">
23121  */
23122
23123  /**
23124  * @class Roo.dd.DDTarget
23125  * A DragDrop implementation that does not move, but can be a drop
23126  * target.  You would get the same result by simply omitting implementation
23127  * for the event callbacks, but this way we reduce the processing cost of the
23128  * event listener and the callbacks.
23129  * @extends Roo.dd.DragDrop
23130  * @constructor
23131  * @param {String} id the id of the element that is a drop target
23132  * @param {String} sGroup the group of related DragDrop objects
23133  * @param {object} config an object containing configurable attributes
23134  *                 Valid properties for DDTarget in addition to those in
23135  *                 DragDrop:
23136  *                    none
23137  */
23138 Roo.dd.DDTarget = function(id, sGroup, config) {
23139     if (id) {
23140         this.initTarget(id, sGroup, config);
23141     }
23142     if (config && (config.listeners || config.events)) { 
23143         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23144             listeners : config.listeners || {}, 
23145             events : config.events || {} 
23146         });    
23147     }
23148 };
23149
23150 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23151 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23152     toString: function() {
23153         return ("DDTarget " + this.id);
23154     }
23155 });
23156 /*
23157  * Based on:
23158  * Ext JS Library 1.1.1
23159  * Copyright(c) 2006-2007, Ext JS, LLC.
23160  *
23161  * Originally Released Under LGPL - original licence link has changed is not relivant.
23162  *
23163  * Fork - LGPL
23164  * <script type="text/javascript">
23165  */
23166  
23167
23168 /**
23169  * @class Roo.dd.ScrollManager
23170  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23171  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23172  * @static
23173  */
23174 Roo.dd.ScrollManager = function(){
23175     var ddm = Roo.dd.DragDropMgr;
23176     var els = {};
23177     var dragEl = null;
23178     var proc = {};
23179     
23180     
23181     
23182     var onStop = function(e){
23183         dragEl = null;
23184         clearProc();
23185     };
23186     
23187     var triggerRefresh = function(){
23188         if(ddm.dragCurrent){
23189              ddm.refreshCache(ddm.dragCurrent.groups);
23190         }
23191     };
23192     
23193     var doScroll = function(){
23194         if(ddm.dragCurrent){
23195             var dds = Roo.dd.ScrollManager;
23196             if(!dds.animate){
23197                 if(proc.el.scroll(proc.dir, dds.increment)){
23198                     triggerRefresh();
23199                 }
23200             }else{
23201                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23202             }
23203         }
23204     };
23205     
23206     var clearProc = function(){
23207         if(proc.id){
23208             clearInterval(proc.id);
23209         }
23210         proc.id = 0;
23211         proc.el = null;
23212         proc.dir = "";
23213     };
23214     
23215     var startProc = function(el, dir){
23216          Roo.log('scroll startproc');
23217         clearProc();
23218         proc.el = el;
23219         proc.dir = dir;
23220         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23221     };
23222     
23223     var onFire = function(e, isDrop){
23224        
23225         if(isDrop || !ddm.dragCurrent){ return; }
23226         var dds = Roo.dd.ScrollManager;
23227         if(!dragEl || dragEl != ddm.dragCurrent){
23228             dragEl = ddm.dragCurrent;
23229             // refresh regions on drag start
23230             dds.refreshCache();
23231         }
23232         
23233         var xy = Roo.lib.Event.getXY(e);
23234         var pt = new Roo.lib.Point(xy[0], xy[1]);
23235         for(var id in els){
23236             var el = els[id], r = el._region;
23237             if(r && r.contains(pt) && el.isScrollable()){
23238                 if(r.bottom - pt.y <= dds.thresh){
23239                     if(proc.el != el){
23240                         startProc(el, "down");
23241                     }
23242                     return;
23243                 }else if(r.right - pt.x <= dds.thresh){
23244                     if(proc.el != el){
23245                         startProc(el, "left");
23246                     }
23247                     return;
23248                 }else if(pt.y - r.top <= dds.thresh){
23249                     if(proc.el != el){
23250                         startProc(el, "up");
23251                     }
23252                     return;
23253                 }else if(pt.x - r.left <= dds.thresh){
23254                     if(proc.el != el){
23255                         startProc(el, "right");
23256                     }
23257                     return;
23258                 }
23259             }
23260         }
23261         clearProc();
23262     };
23263     
23264     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23265     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23266     
23267     return {
23268         /**
23269          * Registers new overflow element(s) to auto scroll
23270          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23271          */
23272         register : function(el){
23273             if(el instanceof Array){
23274                 for(var i = 0, len = el.length; i < len; i++) {
23275                         this.register(el[i]);
23276                 }
23277             }else{
23278                 el = Roo.get(el);
23279                 els[el.id] = el;
23280             }
23281             Roo.dd.ScrollManager.els = els;
23282         },
23283         
23284         /**
23285          * Unregisters overflow element(s) so they are no longer scrolled
23286          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23287          */
23288         unregister : function(el){
23289             if(el instanceof Array){
23290                 for(var i = 0, len = el.length; i < len; i++) {
23291                         this.unregister(el[i]);
23292                 }
23293             }else{
23294                 el = Roo.get(el);
23295                 delete els[el.id];
23296             }
23297         },
23298         
23299         /**
23300          * The number of pixels from the edge of a container the pointer needs to be to 
23301          * trigger scrolling (defaults to 25)
23302          * @type Number
23303          */
23304         thresh : 25,
23305         
23306         /**
23307          * The number of pixels to scroll in each scroll increment (defaults to 50)
23308          * @type Number
23309          */
23310         increment : 100,
23311         
23312         /**
23313          * The frequency of scrolls in milliseconds (defaults to 500)
23314          * @type Number
23315          */
23316         frequency : 500,
23317         
23318         /**
23319          * True to animate the scroll (defaults to true)
23320          * @type Boolean
23321          */
23322         animate: true,
23323         
23324         /**
23325          * The animation duration in seconds - 
23326          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23327          * @type Number
23328          */
23329         animDuration: .4,
23330         
23331         /**
23332          * Manually trigger a cache refresh.
23333          */
23334         refreshCache : function(){
23335             for(var id in els){
23336                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23337                     els[id]._region = els[id].getRegion();
23338                 }
23339             }
23340         }
23341     };
23342 }();/*
23343  * Based on:
23344  * Ext JS Library 1.1.1
23345  * Copyright(c) 2006-2007, Ext JS, LLC.
23346  *
23347  * Originally Released Under LGPL - original licence link has changed is not relivant.
23348  *
23349  * Fork - LGPL
23350  * <script type="text/javascript">
23351  */
23352  
23353
23354 /**
23355  * @class Roo.dd.Registry
23356  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23357  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23358  * @static
23359  */
23360 Roo.dd.Registry = function(){
23361     var elements = {}; 
23362     var handles = {}; 
23363     var autoIdSeed = 0;
23364
23365     var getId = function(el, autogen){
23366         if(typeof el == "string"){
23367             return el;
23368         }
23369         var id = el.id;
23370         if(!id && autogen !== false){
23371             id = "roodd-" + (++autoIdSeed);
23372             el.id = id;
23373         }
23374         return id;
23375     };
23376     
23377     return {
23378     /**
23379      * Register a drag drop element
23380      * @param {String|HTMLElement} element The id or DOM node to register
23381      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23382      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23383      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23384      * populated in the data object (if applicable):
23385      * <pre>
23386 Value      Description<br />
23387 ---------  ------------------------------------------<br />
23388 handles    Array of DOM nodes that trigger dragging<br />
23389            for the element being registered<br />
23390 isHandle   True if the element passed in triggers<br />
23391            dragging itself, else false
23392 </pre>
23393      */
23394         register : function(el, data){
23395             data = data || {};
23396             if(typeof el == "string"){
23397                 el = document.getElementById(el);
23398             }
23399             data.ddel = el;
23400             elements[getId(el)] = data;
23401             if(data.isHandle !== false){
23402                 handles[data.ddel.id] = data;
23403             }
23404             if(data.handles){
23405                 var hs = data.handles;
23406                 for(var i = 0, len = hs.length; i < len; i++){
23407                         handles[getId(hs[i])] = data;
23408                 }
23409             }
23410         },
23411
23412     /**
23413      * Unregister a drag drop element
23414      * @param {String|HTMLElement}  element The id or DOM node to unregister
23415      */
23416         unregister : function(el){
23417             var id = getId(el, false);
23418             var data = elements[id];
23419             if(data){
23420                 delete elements[id];
23421                 if(data.handles){
23422                     var hs = data.handles;
23423                     for(var i = 0, len = hs.length; i < len; i++){
23424                         delete handles[getId(hs[i], false)];
23425                     }
23426                 }
23427             }
23428         },
23429
23430     /**
23431      * Returns the handle registered for a DOM Node by id
23432      * @param {String|HTMLElement} id The DOM node or id to look up
23433      * @return {Object} handle The custom handle data
23434      */
23435         getHandle : function(id){
23436             if(typeof id != "string"){ // must be element?
23437                 id = id.id;
23438             }
23439             return handles[id];
23440         },
23441
23442     /**
23443      * Returns the handle that is registered for the DOM node that is the target of the event
23444      * @param {Event} e The event
23445      * @return {Object} handle The custom handle data
23446      */
23447         getHandleFromEvent : function(e){
23448             var t = Roo.lib.Event.getTarget(e);
23449             return t ? handles[t.id] : null;
23450         },
23451
23452     /**
23453      * Returns a custom data object that is registered for a DOM node by id
23454      * @param {String|HTMLElement} id The DOM node or id to look up
23455      * @return {Object} data The custom data
23456      */
23457         getTarget : function(id){
23458             if(typeof id != "string"){ // must be element?
23459                 id = id.id;
23460             }
23461             return elements[id];
23462         },
23463
23464     /**
23465      * Returns a custom data object that is registered for the DOM node that is the target of the event
23466      * @param {Event} e The event
23467      * @return {Object} data The custom data
23468      */
23469         getTargetFromEvent : function(e){
23470             var t = Roo.lib.Event.getTarget(e);
23471             return t ? elements[t.id] || handles[t.id] : null;
23472         }
23473     };
23474 }();/*
23475  * Based on:
23476  * Ext JS Library 1.1.1
23477  * Copyright(c) 2006-2007, Ext JS, LLC.
23478  *
23479  * Originally Released Under LGPL - original licence link has changed is not relivant.
23480  *
23481  * Fork - LGPL
23482  * <script type="text/javascript">
23483  */
23484  
23485
23486 /**
23487  * @class Roo.dd.StatusProxy
23488  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23489  * default drag proxy used by all Roo.dd components.
23490  * @constructor
23491  * @param {Object} config
23492  */
23493 Roo.dd.StatusProxy = function(config){
23494     Roo.apply(this, config);
23495     this.id = this.id || Roo.id();
23496     this.el = new Roo.Layer({
23497         dh: {
23498             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23499                 {tag: "div", cls: "x-dd-drop-icon"},
23500                 {tag: "div", cls: "x-dd-drag-ghost"}
23501             ]
23502         }, 
23503         shadow: !config || config.shadow !== false
23504     });
23505     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23506     this.dropStatus = this.dropNotAllowed;
23507 };
23508
23509 Roo.dd.StatusProxy.prototype = {
23510     /**
23511      * @cfg {String} dropAllowed
23512      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23513      */
23514     dropAllowed : "x-dd-drop-ok",
23515     /**
23516      * @cfg {String} dropNotAllowed
23517      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23518      */
23519     dropNotAllowed : "x-dd-drop-nodrop",
23520
23521     /**
23522      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23523      * over the current target element.
23524      * @param {String} cssClass The css class for the new drop status indicator image
23525      */
23526     setStatus : function(cssClass){
23527         cssClass = cssClass || this.dropNotAllowed;
23528         if(this.dropStatus != cssClass){
23529             this.el.replaceClass(this.dropStatus, cssClass);
23530             this.dropStatus = cssClass;
23531         }
23532     },
23533
23534     /**
23535      * Resets the status indicator to the default dropNotAllowed value
23536      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23537      */
23538     reset : function(clearGhost){
23539         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23540         this.dropStatus = this.dropNotAllowed;
23541         if(clearGhost){
23542             this.ghost.update("");
23543         }
23544     },
23545
23546     /**
23547      * Updates the contents of the ghost element
23548      * @param {String} html The html that will replace the current innerHTML of the ghost element
23549      */
23550     update : function(html){
23551         if(typeof html == "string"){
23552             this.ghost.update(html);
23553         }else{
23554             this.ghost.update("");
23555             html.style.margin = "0";
23556             this.ghost.dom.appendChild(html);
23557         }
23558         // ensure float = none set?? cant remember why though.
23559         var el = this.ghost.dom.firstChild;
23560                 if(el){
23561                         Roo.fly(el).setStyle('float', 'none');
23562                 }
23563     },
23564     
23565     /**
23566      * Returns the underlying proxy {@link Roo.Layer}
23567      * @return {Roo.Layer} el
23568     */
23569     getEl : function(){
23570         return this.el;
23571     },
23572
23573     /**
23574      * Returns the ghost element
23575      * @return {Roo.Element} el
23576      */
23577     getGhost : function(){
23578         return this.ghost;
23579     },
23580
23581     /**
23582      * Hides the proxy
23583      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23584      */
23585     hide : function(clear){
23586         this.el.hide();
23587         if(clear){
23588             this.reset(true);
23589         }
23590     },
23591
23592     /**
23593      * Stops the repair animation if it's currently running
23594      */
23595     stop : function(){
23596         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23597             this.anim.stop();
23598         }
23599     },
23600
23601     /**
23602      * Displays this proxy
23603      */
23604     show : function(){
23605         this.el.show();
23606     },
23607
23608     /**
23609      * Force the Layer to sync its shadow and shim positions to the element
23610      */
23611     sync : function(){
23612         this.el.sync();
23613     },
23614
23615     /**
23616      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23617      * invalid drop operation by the item being dragged.
23618      * @param {Array} xy The XY position of the element ([x, y])
23619      * @param {Function} callback The function to call after the repair is complete
23620      * @param {Object} scope The scope in which to execute the callback
23621      */
23622     repair : function(xy, callback, scope){
23623         this.callback = callback;
23624         this.scope = scope;
23625         if(xy && this.animRepair !== false){
23626             this.el.addClass("x-dd-drag-repair");
23627             this.el.hideUnders(true);
23628             this.anim = this.el.shift({
23629                 duration: this.repairDuration || .5,
23630                 easing: 'easeOut',
23631                 xy: xy,
23632                 stopFx: true,
23633                 callback: this.afterRepair,
23634                 scope: this
23635             });
23636         }else{
23637             this.afterRepair();
23638         }
23639     },
23640
23641     // private
23642     afterRepair : function(){
23643         this.hide(true);
23644         if(typeof this.callback == "function"){
23645             this.callback.call(this.scope || this);
23646         }
23647         this.callback = null;
23648         this.scope = null;
23649     }
23650 };/*
23651  * Based on:
23652  * Ext JS Library 1.1.1
23653  * Copyright(c) 2006-2007, Ext JS, LLC.
23654  *
23655  * Originally Released Under LGPL - original licence link has changed is not relivant.
23656  *
23657  * Fork - LGPL
23658  * <script type="text/javascript">
23659  */
23660
23661 /**
23662  * @class Roo.dd.DragSource
23663  * @extends Roo.dd.DDProxy
23664  * A simple class that provides the basic implementation needed to make any element draggable.
23665  * @constructor
23666  * @param {String/HTMLElement/Element} el The container element
23667  * @param {Object} config
23668  */
23669 Roo.dd.DragSource = function(el, config){
23670     this.el = Roo.get(el);
23671     this.dragData = {};
23672     
23673     Roo.apply(this, config);
23674     
23675     if(!this.proxy){
23676         this.proxy = new Roo.dd.StatusProxy();
23677     }
23678
23679     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23680           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23681     
23682     this.dragging = false;
23683 };
23684
23685 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23686     /**
23687      * @cfg {String} dropAllowed
23688      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23689      */
23690     dropAllowed : "x-dd-drop-ok",
23691     /**
23692      * @cfg {String} dropNotAllowed
23693      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23694      */
23695     dropNotAllowed : "x-dd-drop-nodrop",
23696
23697     /**
23698      * Returns the data object associated with this drag source
23699      * @return {Object} data An object containing arbitrary data
23700      */
23701     getDragData : function(e){
23702         return this.dragData;
23703     },
23704
23705     // private
23706     onDragEnter : function(e, id){
23707         var target = Roo.dd.DragDropMgr.getDDById(id);
23708         this.cachedTarget = target;
23709         if(this.beforeDragEnter(target, e, id) !== false){
23710             if(target.isNotifyTarget){
23711                 var status = target.notifyEnter(this, e, this.dragData);
23712                 this.proxy.setStatus(status);
23713             }else{
23714                 this.proxy.setStatus(this.dropAllowed);
23715             }
23716             
23717             if(this.afterDragEnter){
23718                 /**
23719                  * An empty function by default, but provided so that you can perform a custom action
23720                  * when the dragged item enters the drop target by providing an implementation.
23721                  * @param {Roo.dd.DragDrop} target The drop target
23722                  * @param {Event} e The event object
23723                  * @param {String} id The id of the dragged element
23724                  * @method afterDragEnter
23725                  */
23726                 this.afterDragEnter(target, e, id);
23727             }
23728         }
23729     },
23730
23731     /**
23732      * An empty function by default, but provided so that you can perform a custom action
23733      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23734      * @param {Roo.dd.DragDrop} target The drop target
23735      * @param {Event} e The event object
23736      * @param {String} id The id of the dragged element
23737      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23738      */
23739     beforeDragEnter : function(target, e, id){
23740         return true;
23741     },
23742
23743     // private
23744     alignElWithMouse: function() {
23745         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23746         this.proxy.sync();
23747     },
23748
23749     // private
23750     onDragOver : function(e, id){
23751         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23752         if(this.beforeDragOver(target, e, id) !== false){
23753             if(target.isNotifyTarget){
23754                 var status = target.notifyOver(this, e, this.dragData);
23755                 this.proxy.setStatus(status);
23756             }
23757
23758             if(this.afterDragOver){
23759                 /**
23760                  * An empty function by default, but provided so that you can perform a custom action
23761                  * while the dragged item is over the drop target by providing an implementation.
23762                  * @param {Roo.dd.DragDrop} target The drop target
23763                  * @param {Event} e The event object
23764                  * @param {String} id The id of the dragged element
23765                  * @method afterDragOver
23766                  */
23767                 this.afterDragOver(target, e, id);
23768             }
23769         }
23770     },
23771
23772     /**
23773      * An empty function by default, but provided so that you can perform a custom action
23774      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23775      * @param {Roo.dd.DragDrop} target The drop target
23776      * @param {Event} e The event object
23777      * @param {String} id The id of the dragged element
23778      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23779      */
23780     beforeDragOver : function(target, e, id){
23781         return true;
23782     },
23783
23784     // private
23785     onDragOut : function(e, id){
23786         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23787         if(this.beforeDragOut(target, e, id) !== false){
23788             if(target.isNotifyTarget){
23789                 target.notifyOut(this, e, this.dragData);
23790             }
23791             this.proxy.reset();
23792             if(this.afterDragOut){
23793                 /**
23794                  * An empty function by default, but provided so that you can perform a custom action
23795                  * after the dragged item is dragged out of the target without dropping.
23796                  * @param {Roo.dd.DragDrop} target The drop target
23797                  * @param {Event} e The event object
23798                  * @param {String} id The id of the dragged element
23799                  * @method afterDragOut
23800                  */
23801                 this.afterDragOut(target, e, id);
23802             }
23803         }
23804         this.cachedTarget = null;
23805     },
23806
23807     /**
23808      * An empty function by default, but provided so that you can perform a custom action before the dragged
23809      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23810      * @param {Roo.dd.DragDrop} target The drop target
23811      * @param {Event} e The event object
23812      * @param {String} id The id of the dragged element
23813      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23814      */
23815     beforeDragOut : function(target, e, id){
23816         return true;
23817     },
23818     
23819     // private
23820     onDragDrop : function(e, id){
23821         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23822         if(this.beforeDragDrop(target, e, id) !== false){
23823             if(target.isNotifyTarget){
23824                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23825                     this.onValidDrop(target, e, id);
23826                 }else{
23827                     this.onInvalidDrop(target, e, id);
23828                 }
23829             }else{
23830                 this.onValidDrop(target, e, id);
23831             }
23832             
23833             if(this.afterDragDrop){
23834                 /**
23835                  * An empty function by default, but provided so that you can perform a custom action
23836                  * after a valid drag drop has occurred by providing an implementation.
23837                  * @param {Roo.dd.DragDrop} target The drop target
23838                  * @param {Event} e The event object
23839                  * @param {String} id The id of the dropped element
23840                  * @method afterDragDrop
23841                  */
23842                 this.afterDragDrop(target, e, id);
23843             }
23844         }
23845         delete this.cachedTarget;
23846     },
23847
23848     /**
23849      * An empty function by default, but provided so that you can perform a custom action before the dragged
23850      * item is dropped onto the target and optionally cancel the onDragDrop.
23851      * @param {Roo.dd.DragDrop} target The drop target
23852      * @param {Event} e The event object
23853      * @param {String} id The id of the dragged element
23854      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23855      */
23856     beforeDragDrop : function(target, e, id){
23857         return true;
23858     },
23859
23860     // private
23861     onValidDrop : function(target, e, id){
23862         this.hideProxy();
23863         if(this.afterValidDrop){
23864             /**
23865              * An empty function by default, but provided so that you can perform a custom action
23866              * after a valid drop has occurred by providing an implementation.
23867              * @param {Object} target The target DD 
23868              * @param {Event} e The event object
23869              * @param {String} id The id of the dropped element
23870              * @method afterInvalidDrop
23871              */
23872             this.afterValidDrop(target, e, id);
23873         }
23874     },
23875
23876     // private
23877     getRepairXY : function(e, data){
23878         return this.el.getXY();  
23879     },
23880
23881     // private
23882     onInvalidDrop : function(target, e, id){
23883         this.beforeInvalidDrop(target, e, id);
23884         if(this.cachedTarget){
23885             if(this.cachedTarget.isNotifyTarget){
23886                 this.cachedTarget.notifyOut(this, e, this.dragData);
23887             }
23888             this.cacheTarget = null;
23889         }
23890         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23891
23892         if(this.afterInvalidDrop){
23893             /**
23894              * An empty function by default, but provided so that you can perform a custom action
23895              * after an invalid drop has occurred by providing an implementation.
23896              * @param {Event} e The event object
23897              * @param {String} id The id of the dropped element
23898              * @method afterInvalidDrop
23899              */
23900             this.afterInvalidDrop(e, id);
23901         }
23902     },
23903
23904     // private
23905     afterRepair : function(){
23906         if(Roo.enableFx){
23907             this.el.highlight(this.hlColor || "c3daf9");
23908         }
23909         this.dragging = false;
23910     },
23911
23912     /**
23913      * An empty function by default, but provided so that you can perform a custom action after an invalid
23914      * drop has occurred.
23915      * @param {Roo.dd.DragDrop} target The drop target
23916      * @param {Event} e The event object
23917      * @param {String} id The id of the dragged element
23918      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23919      */
23920     beforeInvalidDrop : function(target, e, id){
23921         return true;
23922     },
23923
23924     // private
23925     handleMouseDown : function(e){
23926         if(this.dragging) {
23927             return;
23928         }
23929         var data = this.getDragData(e);
23930         if(data && this.onBeforeDrag(data, e) !== false){
23931             this.dragData = data;
23932             this.proxy.stop();
23933             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23934         } 
23935     },
23936
23937     /**
23938      * An empty function by default, but provided so that you can perform a custom action before the initial
23939      * drag event begins and optionally cancel it.
23940      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23941      * @param {Event} e The event object
23942      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23943      */
23944     onBeforeDrag : function(data, e){
23945         return true;
23946     },
23947
23948     /**
23949      * An empty function by default, but provided so that you can perform a custom action once the initial
23950      * drag event has begun.  The drag cannot be canceled from this function.
23951      * @param {Number} x The x position of the click on the dragged object
23952      * @param {Number} y The y position of the click on the dragged object
23953      */
23954     onStartDrag : Roo.emptyFn,
23955
23956     // private - YUI override
23957     startDrag : function(x, y){
23958         this.proxy.reset();
23959         this.dragging = true;
23960         this.proxy.update("");
23961         this.onInitDrag(x, y);
23962         this.proxy.show();
23963     },
23964
23965     // private
23966     onInitDrag : function(x, y){
23967         var clone = this.el.dom.cloneNode(true);
23968         clone.id = Roo.id(); // prevent duplicate ids
23969         this.proxy.update(clone);
23970         this.onStartDrag(x, y);
23971         return true;
23972     },
23973
23974     /**
23975      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23976      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23977      */
23978     getProxy : function(){
23979         return this.proxy;  
23980     },
23981
23982     /**
23983      * Hides the drag source's {@link Roo.dd.StatusProxy}
23984      */
23985     hideProxy : function(){
23986         this.proxy.hide();  
23987         this.proxy.reset(true);
23988         this.dragging = false;
23989     },
23990
23991     // private
23992     triggerCacheRefresh : function(){
23993         Roo.dd.DDM.refreshCache(this.groups);
23994     },
23995
23996     // private - override to prevent hiding
23997     b4EndDrag: function(e) {
23998     },
23999
24000     // private - override to prevent moving
24001     endDrag : function(e){
24002         this.onEndDrag(this.dragData, e);
24003     },
24004
24005     // private
24006     onEndDrag : function(data, e){
24007     },
24008     
24009     // private - pin to cursor
24010     autoOffset : function(x, y) {
24011         this.setDelta(-12, -20);
24012     }    
24013 });/*
24014  * Based on:
24015  * Ext JS Library 1.1.1
24016  * Copyright(c) 2006-2007, Ext JS, LLC.
24017  *
24018  * Originally Released Under LGPL - original licence link has changed is not relivant.
24019  *
24020  * Fork - LGPL
24021  * <script type="text/javascript">
24022  */
24023
24024
24025 /**
24026  * @class Roo.dd.DropTarget
24027  * @extends Roo.dd.DDTarget
24028  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24029  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24030  * @constructor
24031  * @param {String/HTMLElement/Element} el The container element
24032  * @param {Object} config
24033  */
24034 Roo.dd.DropTarget = function(el, config){
24035     this.el = Roo.get(el);
24036     
24037     var listeners = false; ;
24038     if (config && config.listeners) {
24039         listeners= config.listeners;
24040         delete config.listeners;
24041     }
24042     Roo.apply(this, config);
24043     
24044     if(this.containerScroll){
24045         Roo.dd.ScrollManager.register(this.el);
24046     }
24047     this.addEvents( {
24048          /**
24049          * @scope Roo.dd.DropTarget
24050          */
24051          
24052          /**
24053          * @event enter
24054          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24055          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24056          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24057          * 
24058          * IMPORTANT : it should set  this.valid to true|false
24059          * 
24060          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24061          * @param {Event} e The event
24062          * @param {Object} data An object containing arbitrary data supplied by the drag source
24063          */
24064         "enter" : true,
24065         
24066          /**
24067          * @event over
24068          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24069          * This method will be called on every mouse movement while the drag source is over the drop target.
24070          * This default implementation simply returns the dropAllowed config value.
24071          * 
24072          * IMPORTANT : it should set  this.valid to true|false
24073          * 
24074          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24075          * @param {Event} e The event
24076          * @param {Object} data An object containing arbitrary data supplied by the drag source
24077          
24078          */
24079         "over" : true,
24080         /**
24081          * @event out
24082          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24083          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24084          * overClass (if any) from the drop element.
24085          * 
24086          * 
24087          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24088          * @param {Event} e The event
24089          * @param {Object} data An object containing arbitrary data supplied by the drag source
24090          */
24091          "out" : true,
24092          
24093         /**
24094          * @event drop
24095          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24096          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24097          * implementation that does something to process the drop event and returns true so that the drag source's
24098          * repair action does not run.
24099          * 
24100          * IMPORTANT : it should set this.success
24101          * 
24102          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24103          * @param {Event} e The event
24104          * @param {Object} data An object containing arbitrary data supplied by the drag source
24105         */
24106          "drop" : true
24107     });
24108             
24109      
24110     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24111         this.el.dom, 
24112         this.ddGroup || this.group,
24113         {
24114             isTarget: true,
24115             listeners : listeners || {} 
24116            
24117         
24118         }
24119     );
24120
24121 };
24122
24123 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24124     /**
24125      * @cfg {String} overClass
24126      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24127      */
24128      /**
24129      * @cfg {String} ddGroup
24130      * The drag drop group to handle drop events for
24131      */
24132      
24133     /**
24134      * @cfg {String} dropAllowed
24135      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24136      */
24137     dropAllowed : "x-dd-drop-ok",
24138     /**
24139      * @cfg {String} dropNotAllowed
24140      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24141      */
24142     dropNotAllowed : "x-dd-drop-nodrop",
24143     /**
24144      * @cfg {boolean} success
24145      * set this after drop listener.. 
24146      */
24147     success : false,
24148     /**
24149      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24150      * if the drop point is valid for over/enter..
24151      */
24152     valid : false,
24153     // private
24154     isTarget : true,
24155
24156     // private
24157     isNotifyTarget : true,
24158     
24159     /**
24160      * @hide
24161      */
24162     notifyEnter : function(dd, e, data)
24163     {
24164         this.valid = true;
24165         this.fireEvent('enter', dd, e, data);
24166         if(this.overClass){
24167             this.el.addClass(this.overClass);
24168         }
24169         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24170             this.valid ? this.dropAllowed : this.dropNotAllowed
24171         );
24172     },
24173
24174     /**
24175      * @hide
24176      */
24177     notifyOver : function(dd, e, data)
24178     {
24179         this.valid = true;
24180         this.fireEvent('over', dd, e, data);
24181         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24182             this.valid ? this.dropAllowed : this.dropNotAllowed
24183         );
24184     },
24185
24186     /**
24187      * @hide
24188      */
24189     notifyOut : function(dd, e, data)
24190     {
24191         this.fireEvent('out', dd, e, data);
24192         if(this.overClass){
24193             this.el.removeClass(this.overClass);
24194         }
24195     },
24196
24197     /**
24198      * @hide
24199      */
24200     notifyDrop : function(dd, e, data)
24201     {
24202         this.success = false;
24203         this.fireEvent('drop', dd, e, data);
24204         return this.success;
24205     }
24206 });/*
24207  * Based on:
24208  * Ext JS Library 1.1.1
24209  * Copyright(c) 2006-2007, Ext JS, LLC.
24210  *
24211  * Originally Released Under LGPL - original licence link has changed is not relivant.
24212  *
24213  * Fork - LGPL
24214  * <script type="text/javascript">
24215  */
24216
24217
24218 /**
24219  * @class Roo.dd.DragZone
24220  * @extends Roo.dd.DragSource
24221  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24222  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24223  * @constructor
24224  * @param {String/HTMLElement/Element} el The container element
24225  * @param {Object} config
24226  */
24227 Roo.dd.DragZone = function(el, config){
24228     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24229     if(this.containerScroll){
24230         Roo.dd.ScrollManager.register(this.el);
24231     }
24232 };
24233
24234 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24235     /**
24236      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24237      * for auto scrolling during drag operations.
24238      */
24239     /**
24240      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24241      * method after a failed drop (defaults to "c3daf9" - light blue)
24242      */
24243
24244     /**
24245      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24246      * for a valid target to drag based on the mouse down. Override this method
24247      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24248      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24249      * @param {EventObject} e The mouse down event
24250      * @return {Object} The dragData
24251      */
24252     getDragData : function(e){
24253         return Roo.dd.Registry.getHandleFromEvent(e);
24254     },
24255     
24256     /**
24257      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24258      * this.dragData.ddel
24259      * @param {Number} x The x position of the click on the dragged object
24260      * @param {Number} y The y position of the click on the dragged object
24261      * @return {Boolean} true to continue the drag, false to cancel
24262      */
24263     onInitDrag : function(x, y){
24264         this.proxy.update(this.dragData.ddel.cloneNode(true));
24265         this.onStartDrag(x, y);
24266         return true;
24267     },
24268     
24269     /**
24270      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24271      */
24272     afterRepair : function(){
24273         if(Roo.enableFx){
24274             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24275         }
24276         this.dragging = false;
24277     },
24278
24279     /**
24280      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24281      * the XY of this.dragData.ddel
24282      * @param {EventObject} e The mouse up event
24283      * @return {Array} The xy location (e.g. [100, 200])
24284      */
24285     getRepairXY : function(e){
24286         return Roo.Element.fly(this.dragData.ddel).getXY();  
24287     }
24288 });/*
24289  * Based on:
24290  * Ext JS Library 1.1.1
24291  * Copyright(c) 2006-2007, Ext JS, LLC.
24292  *
24293  * Originally Released Under LGPL - original licence link has changed is not relivant.
24294  *
24295  * Fork - LGPL
24296  * <script type="text/javascript">
24297  */
24298 /**
24299  * @class Roo.dd.DropZone
24300  * @extends Roo.dd.DropTarget
24301  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24302  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24303  * @constructor
24304  * @param {String/HTMLElement/Element} el The container element
24305  * @param {Object} config
24306  */
24307 Roo.dd.DropZone = function(el, config){
24308     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24309 };
24310
24311 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24312     /**
24313      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24314      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24315      * provide your own custom lookup.
24316      * @param {Event} e The event
24317      * @return {Object} data The custom data
24318      */
24319     getTargetFromEvent : function(e){
24320         return Roo.dd.Registry.getTargetFromEvent(e);
24321     },
24322
24323     /**
24324      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24325      * that it has registered.  This method has no default implementation and should be overridden to provide
24326      * node-specific processing if necessary.
24327      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24328      * {@link #getTargetFromEvent} for this node)
24329      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24330      * @param {Event} e The event
24331      * @param {Object} data An object containing arbitrary data supplied by the drag source
24332      */
24333     onNodeEnter : function(n, dd, e, data){
24334         
24335     },
24336
24337     /**
24338      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24339      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24340      * overridden to provide the proper feedback.
24341      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24342      * {@link #getTargetFromEvent} for this node)
24343      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24344      * @param {Event} e The event
24345      * @param {Object} data An object containing arbitrary data supplied by the drag source
24346      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24347      * underlying {@link Roo.dd.StatusProxy} can be updated
24348      */
24349     onNodeOver : function(n, dd, e, data){
24350         return this.dropAllowed;
24351     },
24352
24353     /**
24354      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24355      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24356      * node-specific processing if necessary.
24357      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24358      * {@link #getTargetFromEvent} for this node)
24359      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24360      * @param {Event} e The event
24361      * @param {Object} data An object containing arbitrary data supplied by the drag source
24362      */
24363     onNodeOut : function(n, dd, e, data){
24364         
24365     },
24366
24367     /**
24368      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24369      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24370      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24371      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24372      * {@link #getTargetFromEvent} for this node)
24373      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24374      * @param {Event} e The event
24375      * @param {Object} data An object containing arbitrary data supplied by the drag source
24376      * @return {Boolean} True if the drop was valid, else false
24377      */
24378     onNodeDrop : function(n, dd, e, data){
24379         return false;
24380     },
24381
24382     /**
24383      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24384      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24385      * it should be overridden to provide the proper feedback if necessary.
24386      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24387      * @param {Event} e The event
24388      * @param {Object} data An object containing arbitrary data supplied by the drag source
24389      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24390      * underlying {@link Roo.dd.StatusProxy} can be updated
24391      */
24392     onContainerOver : function(dd, e, data){
24393         return this.dropNotAllowed;
24394     },
24395
24396     /**
24397      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24398      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24399      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24400      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24401      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24402      * @param {Event} e The event
24403      * @param {Object} data An object containing arbitrary data supplied by the drag source
24404      * @return {Boolean} True if the drop was valid, else false
24405      */
24406     onContainerDrop : function(dd, e, data){
24407         return false;
24408     },
24409
24410     /**
24411      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24412      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24413      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24414      * you should override this method and provide a custom implementation.
24415      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24416      * @param {Event} e The event
24417      * @param {Object} data An object containing arbitrary data supplied by the drag source
24418      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24419      * underlying {@link Roo.dd.StatusProxy} can be updated
24420      */
24421     notifyEnter : function(dd, e, data){
24422         return this.dropNotAllowed;
24423     },
24424
24425     /**
24426      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24427      * This method will be called on every mouse movement while the drag source is over the drop zone.
24428      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24429      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24430      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24431      * registered node, it will call {@link #onContainerOver}.
24432      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24433      * @param {Event} e The event
24434      * @param {Object} data An object containing arbitrary data supplied by the drag source
24435      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24436      * underlying {@link Roo.dd.StatusProxy} can be updated
24437      */
24438     notifyOver : function(dd, e, data){
24439         var n = this.getTargetFromEvent(e);
24440         if(!n){ // not over valid drop target
24441             if(this.lastOverNode){
24442                 this.onNodeOut(this.lastOverNode, dd, e, data);
24443                 this.lastOverNode = null;
24444             }
24445             return this.onContainerOver(dd, e, data);
24446         }
24447         if(this.lastOverNode != n){
24448             if(this.lastOverNode){
24449                 this.onNodeOut(this.lastOverNode, dd, e, data);
24450             }
24451             this.onNodeEnter(n, dd, e, data);
24452             this.lastOverNode = n;
24453         }
24454         return this.onNodeOver(n, dd, e, data);
24455     },
24456
24457     /**
24458      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24459      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24460      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24461      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24462      * @param {Event} e The event
24463      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24464      */
24465     notifyOut : function(dd, e, data){
24466         if(this.lastOverNode){
24467             this.onNodeOut(this.lastOverNode, dd, e, data);
24468             this.lastOverNode = null;
24469         }
24470     },
24471
24472     /**
24473      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24474      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24475      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24476      * otherwise it will call {@link #onContainerDrop}.
24477      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24478      * @param {Event} e The event
24479      * @param {Object} data An object containing arbitrary data supplied by the drag source
24480      * @return {Boolean} True if the drop was valid, else false
24481      */
24482     notifyDrop : function(dd, e, data){
24483         if(this.lastOverNode){
24484             this.onNodeOut(this.lastOverNode, dd, e, data);
24485             this.lastOverNode = null;
24486         }
24487         var n = this.getTargetFromEvent(e);
24488         return n ?
24489             this.onNodeDrop(n, dd, e, data) :
24490             this.onContainerDrop(dd, e, data);
24491     },
24492
24493     // private
24494     triggerCacheRefresh : function(){
24495         Roo.dd.DDM.refreshCache(this.groups);
24496     }  
24497 });