Merge branch 'master' of http://git.roojs.com/roojs1
[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 (non-delayed, will get a return value..)
509         callback : function(cb, scope, args, delay)
510                 {
511             if(typeof cb != "function"){
512                                 return false;
513                         }
514                         if(delay){
515                                 cb.defer(delay, scope, args || []);
516                                 return false
517             }
518                         return cb.apply(scope, args || []);
519
520         },
521
522         /**
523          * Return the dom node for the passed string (id), dom node, or Roo.Element
524          * @param {String/HTMLElement/Roo.Element} el
525          * @return HTMLElement
526          */
527         getDom : function(el){
528             if(!el){
529                 return null;
530             }
531             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532         },
533
534         /**
535         * Shorthand for {@link Roo.ComponentMgr#get}
536         * @param {String} id
537         * @return Roo.Component
538         */
539         getCmp : function(id){
540             return Roo.ComponentMgr.get(id);
541         },
542          
543         num : function(v, defaultValue){
544             if(typeof v != 'number'){
545                 return defaultValue;
546             }
547             return v;
548         },
549
550         destroy : function(){
551             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552                 var as = a[i];
553                 if(as){
554                     if(as.dom){
555                         as.removeAllListeners();
556                         as.remove();
557                         continue;
558                     }
559                     if(typeof as.purgeListeners == 'function'){
560                         as.purgeListeners();
561                     }
562                     if(typeof as.destroy == 'function'){
563                         as.destroy();
564                     }
565                 }
566             }
567         },
568
569         // inpired by a similar function in mootools library
570         /**
571          * Returns the type of object that is passed in. If the object passed in is null or undefined it
572          * return false otherwise it returns one of the following values:<ul>
573          * <li><b>string</b>: If the object passed is a string</li>
574          * <li><b>number</b>: If the object passed is a number</li>
575          * <li><b>boolean</b>: If the object passed is a boolean value</li>
576          * <li><b>function</b>: If the object passed is a function reference</li>
577          * <li><b>object</b>: If the object passed is an object</li>
578          * <li><b>array</b>: If the object passed is an array</li>
579          * <li><b>regexp</b>: If the object passed is a regular expression</li>
580          * <li><b>element</b>: If the object passed is a DOM Element</li>
581          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
582          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
583          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
584          * @param {Mixed} object
585          * @return {String}
586          */
587         type : function(o){
588             if(o === undefined || o === null){
589                 return false;
590             }
591             if(o.htmlElement){
592                 return 'element';
593             }
594             var t = typeof o;
595             if(t == 'object' && o.nodeName) {
596                 switch(o.nodeType) {
597                     case 1: return 'element';
598                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
599                 }
600             }
601             if(t == 'object' || t == 'function') {
602                 switch(o.constructor) {
603                     case Array: return 'array';
604                     case RegExp: return 'regexp';
605                 }
606                 if(typeof o.length == 'number' && typeof o.item == 'function') {
607                     return 'nodelist';
608                 }
609             }
610             return t;
611         },
612
613         /**
614          * Returns true if the passed value is null, undefined or an empty string (optional).
615          * @param {Mixed} value The value to test
616          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
617          * @return {Boolean}
618          */
619         isEmpty : function(v, allowBlank){
620             return v === null || v === undefined || (!allowBlank ? v === '' : false);
621         },
622         
623         /** @type Boolean */
624         isOpera : isOpera,
625         /** @type Boolean */
626         isSafari : isSafari,
627         /** @type Boolean */
628         isFirefox : isFirefox,
629         /** @type Boolean */
630         isIE : isIE,
631         /** @type Boolean */
632         isIE7 : isIE7,
633         /** @type Boolean */
634         isIE11 : isIE11,
635         /** @type Boolean */
636         isEdge : isEdge,
637         /** @type Boolean */
638         isGecko : isGecko,
639         /** @type Boolean */
640         isBorderBox : isBorderBox,
641         /** @type Boolean */
642         isWindows : isWindows,
643         /** @type Boolean */
644         isLinux : isLinux,
645         /** @type Boolean */
646         isMac : isMac,
647         /** @type Boolean */
648         isIOS : isIOS,
649         /** @type Boolean */
650         isAndroid : isAndroid,
651         /** @type Boolean */
652         isTouch : isTouch,
653
654         /**
655          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
656          * you may want to set this to true.
657          * @type Boolean
658          */
659         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
660         
661         
662                 
663         /**
664          * Selects a single element as a Roo Element
665          * This is about as close as you can get to jQuery's $('do crazy stuff')
666          * @param {String} selector The selector/xpath query
667          * @param {Node} root (optional) The start of the query (defaults to document).
668          * @return {Roo.Element}
669          */
670         selectNode : function(selector, root) 
671         {
672             var node = Roo.DomQuery.selectNode(selector,root);
673             return node ? Roo.get(node) : new Roo.Element(false);
674         },
675                 /**
676                  * Find the current bootstrap width Grid size
677                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
678                  * @returns {String} (xs|sm|md|lg|xl)
679                  */
680                 
681                 getGridSize : function()
682                 {
683                         var w = Roo.lib.Dom.getViewWidth();
684                         switch(true) {
685                                 case w > 1200:
686                                         return 'xl';
687                                 case w > 992:
688                                         return 'lg';
689                                 case w > 768:
690                                         return 'md';
691                                 case w > 576:
692                                         return 'sm';
693                                 default:
694                                         return 'xs'
695                         }
696                         
697                 } 
698         
699     });
700
701
702 })();
703
704 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
705                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
706                 "Roo.app", "Roo.ux" 
707                );
708 /*
709  * Based on:
710  * Ext JS Library 1.1.1
711  * Copyright(c) 2006-2007, Ext JS, LLC.
712  *
713  * Originally Released Under LGPL - original licence link has changed is not relivant.
714  *
715  * Fork - LGPL
716  * <script type="text/javascript">
717  */
718
719 (function() {    
720     // wrappedn so fnCleanup is not in global scope...
721     if(Roo.isIE) {
722         function fnCleanUp() {
723             var p = Function.prototype;
724             delete p.createSequence;
725             delete p.defer;
726             delete p.createDelegate;
727             delete p.createCallback;
728             delete p.createInterceptor;
729
730             window.detachEvent("onunload", fnCleanUp);
731         }
732         window.attachEvent("onunload", fnCleanUp);
733     }
734 })();
735
736
737 /**
738  * @class Function
739  * These functions are available on every Function object (any JavaScript function).
740  */
741 Roo.apply(Function.prototype, {
742      /**
743      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
744      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
745      * Will create a function that is bound to those 2 args.
746      * @return {Function} The new function
747     */
748     createCallback : function(/*args...*/){
749         // make args available, in function below
750         var args = arguments;
751         var method = this;
752         return function() {
753             return method.apply(window, args);
754         };
755     },
756
757     /**
758      * Creates a delegate (callback) that sets the scope to obj.
759      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
760      * Will create a function that is automatically scoped to this.
761      * @param {Object} obj (optional) The object for which the scope is set
762      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764      *                                             if a number the args are inserted at the specified position
765      * @return {Function} The new function
766      */
767     createDelegate : function(obj, args, appendArgs){
768         var method = this;
769         return function() {
770             var callArgs = args || arguments;
771             if(appendArgs === true){
772                 callArgs = Array.prototype.slice.call(arguments, 0);
773                 callArgs = callArgs.concat(args);
774             }else if(typeof appendArgs == "number"){
775                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
776                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
777                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
778             }
779             return method.apply(obj || window, callArgs);
780         };
781     },
782
783     /**
784      * Calls this function after the number of millseconds specified.
785      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
786      * @param {Object} obj (optional) The object for which the scope is set
787      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
788      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
789      *                                             if a number the args are inserted at the specified position
790      * @return {Number} The timeout id that can be used with clearTimeout
791      */
792     defer : function(millis, obj, args, appendArgs){
793         var fn = this.createDelegate(obj, args, appendArgs);
794         if(millis){
795             return setTimeout(fn, millis);
796         }
797         fn();
798         return 0;
799     },
800     /**
801      * Create a combined function call sequence of the original function + the passed function.
802      * The resulting function returns the results of the original function.
803      * The passed fcn is called with the parameters of the original function
804      * @param {Function} fcn The function to sequence
805      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
806      * @return {Function} The new function
807      */
808     createSequence : function(fcn, scope){
809         if(typeof fcn != "function"){
810             return this;
811         }
812         var method = this;
813         return function() {
814             var retval = method.apply(this || window, arguments);
815             fcn.apply(scope || this || window, arguments);
816             return retval;
817         };
818     },
819
820     /**
821      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
822      * The resulting function returns the results of the original function.
823      * The passed fcn is called with the parameters of the original function.
824      * @addon
825      * @param {Function} fcn The function to call before the original
826      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
827      * @return {Function} The new function
828      */
829     createInterceptor : function(fcn, scope){
830         if(typeof fcn != "function"){
831             return this;
832         }
833         var method = this;
834         return function() {
835             fcn.target = this;
836             fcn.method = method;
837             if(fcn.apply(scope || this || window, arguments) === false){
838                 return;
839             }
840             return method.apply(this || window, arguments);
841         };
842     }
843 });
844 /*
845  * Based on:
846  * Ext JS Library 1.1.1
847  * Copyright(c) 2006-2007, Ext JS, LLC.
848  *
849  * Originally Released Under LGPL - original licence link has changed is not relivant.
850  *
851  * Fork - LGPL
852  * <script type="text/javascript">
853  */
854
855 Roo.applyIf(String, {
856     
857     /** @scope String */
858     
859     /**
860      * Escapes the passed string for ' and \
861      * @param {String} string The string to escape
862      * @return {String} The escaped string
863      * @static
864      */
865     escape : function(string) {
866         return string.replace(/('|\\)/g, "\\$1");
867     },
868
869     /**
870      * Pads the left side of a string with a specified character.  This is especially useful
871      * for normalizing number and date strings.  Example usage:
872      * <pre><code>
873 var s = String.leftPad('123', 5, '0');
874 // s now contains the string: '00123'
875 </code></pre>
876      * @param {String} string The original string
877      * @param {Number} size The total length of the output string
878      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
879      * @return {String} The padded string
880      * @static
881      */
882     leftPad : function (val, size, ch) {
883         var result = new String(val);
884         if(ch === null || ch === undefined || ch === '') {
885             ch = " ";
886         }
887         while (result.length < size) {
888             result = ch + result;
889         }
890         return result;
891     },
892
893     /**
894      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
895      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
896      * <pre><code>
897 var cls = 'my-class', text = 'Some text';
898 var s = String.format('<div class="{0}">{1}</div>', cls, text);
899 // s now contains the string: '<div class="my-class">Some text</div>'
900 </code></pre>
901      * @param {String} string The tokenized string to be formatted
902      * @param {String} value1 The value to replace token {0}
903      * @param {String} value2 Etc...
904      * @return {String} The formatted string
905      * @static
906      */
907     format : function(format){
908         var args = Array.prototype.slice.call(arguments, 1);
909         return format.replace(/\{(\d+)\}/g, function(m, i){
910             return Roo.util.Format.htmlEncode(args[i]);
911         });
912     }
913   
914     
915 });
916
917 /**
918  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
919  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
920  * they are already different, the first value passed in is returned.  Note that this method returns the new value
921  * but does not change the current string.
922  * <pre><code>
923 // alternate sort directions
924 sort = sort.toggle('ASC', 'DESC');
925
926 // instead of conditional logic:
927 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
928 </code></pre>
929  * @param {String} value The value to compare to the current string
930  * @param {String} other The new value to use if the string already equals the first value passed in
931  * @return {String} The new value
932  */
933  
934 String.prototype.toggle = function(value, other){
935     return this == value ? other : value;
936 };
937
938
939 /**
940   * Remove invalid unicode characters from a string 
941   *
942   * @return {String} The clean string
943   */
944 String.prototype.unicodeClean = function () {
945     return this.replace(/[\s\S]/g,
946         function(character) {
947             if (character.charCodeAt()< 256) {
948               return character;
949            }
950            try {
951                 encodeURIComponent(character);
952            } catch(e) { 
953               return '';
954            }
955            return character;
956         }
957     );
958 };
959   
960
961 /**
962   * Make the first letter of a string uppercase
963   *
964   * @return {String} The new string.
965   */
966 String.prototype.toUpperCaseFirst = function () {
967     return this.charAt(0).toUpperCase() + this.slice(1);
968 };  
969   
970 /*
971  * Based on:
972  * Ext JS Library 1.1.1
973  * Copyright(c) 2006-2007, Ext JS, LLC.
974  *
975  * Originally Released Under LGPL - original licence link has changed is not relivant.
976  *
977  * Fork - LGPL
978  * <script type="text/javascript">
979  */
980
981  /**
982  * @class Number
983  */
984 Roo.applyIf(Number.prototype, {
985     /**
986      * Checks whether or not the current number is within a desired range.  If the number is already within the
987      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
988      * exceeded.  Note that this method returns the constrained value but does not change the current number.
989      * @param {Number} min The minimum number in the range
990      * @param {Number} max The maximum number in the range
991      * @return {Number} The constrained value if outside the range, otherwise the current value
992      */
993     constrain : function(min, max){
994         return Math.min(Math.max(this, min), max);
995     }
996 });/*
997  * Based on:
998  * Ext JS Library 1.1.1
999  * Copyright(c) 2006-2007, Ext JS, LLC.
1000  *
1001  * Originally Released Under LGPL - original licence link has changed is not relivant.
1002  *
1003  * Fork - LGPL
1004  * <script type="text/javascript">
1005  */
1006  /**
1007  * @class Array
1008  */
1009 Roo.applyIf(Array.prototype, {
1010     /**
1011      * 
1012      * Checks whether or not the specified object exists in the array.
1013      * @param {Object} o The object to check for
1014      * @return {Number} The index of o in the array (or -1 if it is not found)
1015      */
1016     indexOf : function(o){
1017        for (var i = 0, len = this.length; i < len; i++){
1018               if(this[i] == o) { return i; }
1019        }
1020            return -1;
1021     },
1022
1023     /**
1024      * Removes the specified object from the array.  If the object is not found nothing happens.
1025      * @param {Object} o The object to remove
1026      */
1027     remove : function(o){
1028        var index = this.indexOf(o);
1029        if(index != -1){
1030            this.splice(index, 1);
1031        }
1032     },
1033     /**
1034      * Map (JS 1.6 compatibility)
1035      * @param {Function} function  to call
1036      */
1037     map : function(fun )
1038     {
1039         var len = this.length >>> 0;
1040         if (typeof fun != "function") {
1041             throw new TypeError();
1042         }
1043         var res = new Array(len);
1044         var thisp = arguments[1];
1045         for (var i = 0; i < len; i++)
1046         {
1047             if (i in this) {
1048                 res[i] = fun.call(thisp, this[i], i, this);
1049             }
1050         }
1051
1052         return res;
1053     },
1054     /**
1055      * equals
1056      * @param {Array} o The array to compare to
1057      * @returns {Boolean} true if the same
1058      */
1059     equals : function(b)
1060     {
1061             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1062         if (this === b) {
1063             return true;
1064         }
1065         if (b == null) {
1066             return false;
1067         }
1068         if (this.length !== b.length) {
1069             return false;
1070         }
1071           
1072         // sort?? a.sort().equals(b.sort());
1073           
1074         for (var i = 0; i < this.length; ++i) {
1075             if (this[i] !== b[i]) {
1076             return false;
1077             }
1078         }
1079         return true;
1080     } 
1081     
1082     
1083     
1084     
1085 });
1086
1087 Roo.applyIf(Array, {
1088  /**
1089      * from
1090      * @static
1091      * @param {Array} o Or Array like object (eg. nodelist)
1092      * @returns {Array} 
1093      */
1094     from : function(o)
1095     {
1096         var ret= [];
1097     
1098         for (var i =0; i < o.length; i++) { 
1099             ret[i] = o[i];
1100         }
1101         return ret;
1102       
1103     }
1104 });
1105 /*
1106  * Based on:
1107  * Ext JS Library 1.1.1
1108  * Copyright(c) 2006-2007, Ext JS, LLC.
1109  *
1110  * Originally Released Under LGPL - original licence link has changed is not relivant.
1111  *
1112  * Fork - LGPL
1113  * <script type="text/javascript">
1114  */
1115
1116 /**
1117  * @class Date
1118  *
1119  * The date parsing and format syntax is a subset of
1120  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1121  * supported will provide results equivalent to their PHP versions.
1122  *
1123  * Following is the list of all currently supported formats:
1124  *<pre>
1125 Sample date:
1126 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1127
1128 Format  Output      Description
1129 ------  ----------  --------------------------------------------------------------
1130   d      10         Day of the month, 2 digits with leading zeros
1131   D      Wed        A textual representation of a day, three letters
1132   j      10         Day of the month without leading zeros
1133   l      Wednesday  A full textual representation of the day of the week
1134   S      th         English ordinal day of month suffix, 2 chars (use with j)
1135   w      3          Numeric representation of the day of the week
1136   z      9          The julian date, or day of the year (0-365)
1137   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1138   F      January    A full textual representation of the month
1139   m      01         Numeric representation of a month, with leading zeros
1140   M      Jan        Month name abbreviation, three letters
1141   n      1          Numeric representation of a month, without leading zeros
1142   t      31         Number of days in the given month
1143   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1144   Y      2007       A full numeric representation of a year, 4 digits
1145   y      07         A two digit representation of a year
1146   a      pm         Lowercase Ante meridiem and Post meridiem
1147   A      PM         Uppercase Ante meridiem and Post meridiem
1148   g      3          12-hour format of an hour without leading zeros
1149   G      15         24-hour format of an hour without leading zeros
1150   h      03         12-hour format of an hour with leading zeros
1151   H      15         24-hour format of an hour with leading zeros
1152   i      05         Minutes with leading zeros
1153   s      01         Seconds, with leading zeros
1154   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1155   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1156   T      CST        Timezone setting of the machine running the code
1157   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1158 </pre>
1159  *
1160  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1161  * <pre><code>
1162 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1163 document.write(dt.format('Y-m-d'));                         //2007-01-10
1164 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1165 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
1166  </code></pre>
1167  *
1168  * Here are some standard date/time patterns that you might find helpful.  They
1169  * are not part of the source of Date.js, but to use them you can simply copy this
1170  * block of code into any script that is included after Date.js and they will also become
1171  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1172  * <pre><code>
1173 Date.patterns = {
1174     ISO8601Long:"Y-m-d H:i:s",
1175     ISO8601Short:"Y-m-d",
1176     ShortDate: "n/j/Y",
1177     LongDate: "l, F d, Y",
1178     FullDateTime: "l, F d, Y g:i:s A",
1179     MonthDay: "F d",
1180     ShortTime: "g:i A",
1181     LongTime: "g:i:s A",
1182     SortableDateTime: "Y-m-d\\TH:i:s",
1183     UniversalSortableDateTime: "Y-m-d H:i:sO",
1184     YearMonth: "F, Y"
1185 };
1186 </code></pre>
1187  *
1188  * Example usage:
1189  * <pre><code>
1190 var dt = new Date();
1191 document.write(dt.format(Date.patterns.ShortDate));
1192  </code></pre>
1193  */
1194
1195 /*
1196  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1197  * They generate precompiled functions from date formats instead of parsing and
1198  * processing the pattern every time you format a date.  These functions are available
1199  * on every Date object (any javascript function).
1200  *
1201  * The original article and download are here:
1202  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1203  *
1204  */
1205  
1206  
1207  // was in core
1208 /**
1209  Returns the number of milliseconds between this date and date
1210  @param {Date} date (optional) Defaults to now
1211  @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY) 
1212  @return {Number} The diff in milliseconds or units of interval
1213  @member Date getElapsed
1214  */
1215 Date.prototype.getElapsed = function(date, interval)
1216 {
1217     date = date ||  new Date();
1218     var ret = Math.abs(date.getTime()-this.getTime());
1219     switch (interval) {
1220        
1221         case  Date.SECOND:
1222             return Math.floor(ret / (1000));
1223         case  Date.MINUTE:
1224             return Math.floor(ret / (1000*60));
1225         case  Date.HOUR:
1226             return Math.floor(ret / (1000*60*60));
1227         case  Date.DAY:
1228             return Math.floor(ret / (1000*60*60*24));
1229         case  Date.MONTH: // this does not give exact number...??
1230             return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1231         case  Date.YEAR: // this does not give exact number...??
1232             return (date.format("Y") - this.format("Y"));
1233        
1234         case  Date.MILLI:
1235         default:
1236             return ret;
1237     }
1238 };
1239  
1240 // was in date file..
1241
1242
1243 // private
1244 Date.parseFunctions = {count:0};
1245 // private
1246 Date.parseRegexes = [];
1247 // private
1248 Date.formatFunctions = {count:0};
1249
1250 // private
1251 Date.prototype.dateFormat = function(format) {
1252     if (Date.formatFunctions[format] == null) {
1253         Date.createNewFormat(format);
1254     }
1255     var func = Date.formatFunctions[format];
1256     return this[func]();
1257 };
1258
1259
1260 /**
1261  * Formats a date given the supplied format string
1262  * @param {String} format The format string
1263  * @return {String} The formatted date
1264  * @method
1265  */
1266 Date.prototype.format = Date.prototype.dateFormat;
1267
1268 // private
1269 Date.createNewFormat = function(format) {
1270     var funcName = "format" + Date.formatFunctions.count++;
1271     Date.formatFunctions[format] = funcName;
1272     var code = "Date.prototype." + funcName + " = function(){return ";
1273     var special = false;
1274     var ch = '';
1275     for (var i = 0; i < format.length; ++i) {
1276         ch = format.charAt(i);
1277         if (!special && ch == "\\") {
1278             special = true;
1279         }
1280         else if (special) {
1281             special = false;
1282             code += "'" + String.escape(ch) + "' + ";
1283         }
1284         else {
1285             code += Date.getFormatCode(ch);
1286         }
1287     }
1288     /** eval:var:zzzzzzzzzzzzz */
1289     eval(code.substring(0, code.length - 3) + ";}");
1290 };
1291
1292 // private
1293 Date.getFormatCode = function(character) {
1294     switch (character) {
1295     case "d":
1296         return "String.leftPad(this.getDate(), 2, '0') + ";
1297     case "D":
1298         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1299     case "j":
1300         return "this.getDate() + ";
1301     case "l":
1302         return "Date.dayNames[this.getDay()] + ";
1303     case "S":
1304         return "this.getSuffix() + ";
1305     case "w":
1306         return "this.getDay() + ";
1307     case "z":
1308         return "this.getDayOfYear() + ";
1309     case "W":
1310         return "this.getWeekOfYear() + ";
1311     case "F":
1312         return "Date.monthNames[this.getMonth()] + ";
1313     case "m":
1314         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1315     case "M":
1316         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1317     case "n":
1318         return "(this.getMonth() + 1) + ";
1319     case "t":
1320         return "this.getDaysInMonth() + ";
1321     case "L":
1322         return "(this.isLeapYear() ? 1 : 0) + ";
1323     case "Y":
1324         return "this.getFullYear() + ";
1325     case "y":
1326         return "('' + this.getFullYear()).substring(2, 4) + ";
1327     case "a":
1328         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1329     case "A":
1330         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1331     case "g":
1332         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1333     case "G":
1334         return "this.getHours() + ";
1335     case "h":
1336         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1337     case "H":
1338         return "String.leftPad(this.getHours(), 2, '0') + ";
1339     case "i":
1340         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1341     case "s":
1342         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1343     case "O":
1344         return "this.getGMTOffset() + ";
1345     case "P":
1346         return "this.getGMTColonOffset() + ";
1347     case "T":
1348         return "this.getTimezone() + ";
1349     case "Z":
1350         return "(this.getTimezoneOffset() * -60) + ";
1351     default:
1352         return "'" + String.escape(character) + "' + ";
1353     }
1354 };
1355
1356 /**
1357  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1358  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1359  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1360  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1361  * string or the parse operation will fail.
1362  * Example Usage:
1363 <pre><code>
1364 //dt = Fri May 25 2007 (current date)
1365 var dt = new Date();
1366
1367 //dt = Thu May 25 2006 (today's month/day in 2006)
1368 dt = Date.parseDate("2006", "Y");
1369
1370 //dt = Sun Jan 15 2006 (all date parts specified)
1371 dt = Date.parseDate("2006-1-15", "Y-m-d");
1372
1373 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1374 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1375 </code></pre>
1376  * @param {String} input The unparsed date as a string
1377  * @param {String} format The format the date is in
1378  * @return {Date} The parsed date
1379  * @static
1380  */
1381 Date.parseDate = function(input, format) {
1382     if (Date.parseFunctions[format] == null) {
1383         Date.createParser(format);
1384     }
1385     var func = Date.parseFunctions[format];
1386     return Date[func](input);
1387 };
1388 /**
1389  * @private
1390  */
1391
1392 Date.createParser = function(format) {
1393     var funcName = "parse" + Date.parseFunctions.count++;
1394     var regexNum = Date.parseRegexes.length;
1395     var currentGroup = 1;
1396     Date.parseFunctions[format] = funcName;
1397
1398     var code = "Date." + funcName + " = function(input){\n"
1399         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1400         + "var d = new Date();\n"
1401         + "y = d.getFullYear();\n"
1402         + "m = d.getMonth();\n"
1403         + "d = d.getDate();\n"
1404         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1405         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1406         + "if (results && results.length > 0) {";
1407     var regex = "";
1408
1409     var special = false;
1410     var ch = '';
1411     for (var i = 0; i < format.length; ++i) {
1412         ch = format.charAt(i);
1413         if (!special && ch == "\\") {
1414             special = true;
1415         }
1416         else if (special) {
1417             special = false;
1418             regex += String.escape(ch);
1419         }
1420         else {
1421             var obj = Date.formatCodeToRegex(ch, currentGroup);
1422             currentGroup += obj.g;
1423             regex += obj.s;
1424             if (obj.g && obj.c) {
1425                 code += obj.c;
1426             }
1427         }
1428     }
1429
1430     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1431         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1432         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1433         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1434         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1435         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1436         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1437         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1438         + "else if (y >= 0 && m >= 0)\n"
1439         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1440         + "else if (y >= 0)\n"
1441         + "{v = new Date(y); v.setFullYear(y);}\n"
1442         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1443         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1444         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1445         + ";}";
1446
1447     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1448     /** eval:var:zzzzzzzzzzzzz */
1449     eval(code);
1450 };
1451
1452 // private
1453 Date.formatCodeToRegex = function(character, currentGroup) {
1454     switch (character) {
1455     case "D":
1456         return {g:0,
1457         c:null,
1458         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1459     case "j":
1460         return {g:1,
1461             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1462             s:"(\\d{1,2})"}; // day of month without leading zeroes
1463     case "d":
1464         return {g:1,
1465             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1466             s:"(\\d{2})"}; // day of month with leading zeroes
1467     case "l":
1468         return {g:0,
1469             c:null,
1470             s:"(?:" + Date.dayNames.join("|") + ")"};
1471     case "S":
1472         return {g:0,
1473             c:null,
1474             s:"(?:st|nd|rd|th)"};
1475     case "w":
1476         return {g:0,
1477             c:null,
1478             s:"\\d"};
1479     case "z":
1480         return {g:0,
1481             c:null,
1482             s:"(?:\\d{1,3})"};
1483     case "W":
1484         return {g:0,
1485             c:null,
1486             s:"(?:\\d{2})"};
1487     case "F":
1488         return {g:1,
1489             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1490             s:"(" + Date.monthNames.join("|") + ")"};
1491     case "M":
1492         return {g:1,
1493             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1494             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1495     case "n":
1496         return {g:1,
1497             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1498             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1499     case "m":
1500         return {g:1,
1501             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1502             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1503     case "t":
1504         return {g:0,
1505             c:null,
1506             s:"\\d{1,2}"};
1507     case "L":
1508         return {g:0,
1509             c:null,
1510             s:"(?:1|0)"};
1511     case "Y":
1512         return {g:1,
1513             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1514             s:"(\\d{4})"};
1515     case "y":
1516         return {g:1,
1517             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1518                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1519             s:"(\\d{1,2})"};
1520     case "a":
1521         return {g:1,
1522             c:"if (results[" + currentGroup + "] == 'am') {\n"
1523                 + "if (h == 12) { h = 0; }\n"
1524                 + "} else { if (h < 12) { h += 12; }}",
1525             s:"(am|pm)"};
1526     case "A":
1527         return {g:1,
1528             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1529                 + "if (h == 12) { h = 0; }\n"
1530                 + "} else { if (h < 12) { h += 12; }}",
1531             s:"(AM|PM)"};
1532     case "g":
1533     case "G":
1534         return {g:1,
1535             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1536             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1537     case "h":
1538     case "H":
1539         return {g:1,
1540             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1541             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1542     case "i":
1543         return {g:1,
1544             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1545             s:"(\\d{2})"};
1546     case "s":
1547         return {g:1,
1548             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1549             s:"(\\d{2})"};
1550     case "O":
1551         return {g:1,
1552             c:[
1553                 "o = results[", currentGroup, "];\n",
1554                 "var sn = o.substring(0,1);\n", // get + / - sign
1555                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1556                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1557                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1558                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1559             ].join(""),
1560             s:"([+\-]\\d{2,4})"};
1561     
1562     
1563     case "P":
1564         return {g:1,
1565                 c:[
1566                    "o = results[", currentGroup, "];\n",
1567                    "var sn = o.substring(0,1);\n",
1568                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1569                    "var mn = o.substring(4,6) % 60;\n",
1570                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1571                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1572             ].join(""),
1573             s:"([+\-]\\d{4})"};
1574     case "T":
1575         return {g:0,
1576             c:null,
1577             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1578     case "Z":
1579         return {g:1,
1580             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1581                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1582             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1583     default:
1584         return {g:0,
1585             c:null,
1586             s:String.escape(character)};
1587     }
1588 };
1589
1590 /**
1591  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1592  * @return {String} The abbreviated timezone name (e.g. 'CST')
1593  */
1594 Date.prototype.getTimezone = function() {
1595     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1596 };
1597
1598 /**
1599  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1600  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1601  */
1602 Date.prototype.getGMTOffset = function() {
1603     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1604         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1605         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1606 };
1607
1608 /**
1609  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1610  * @return {String} 2-characters representing hours and 2-characters representing minutes
1611  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1612  */
1613 Date.prototype.getGMTColonOffset = function() {
1614         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1615                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1616                 + ":"
1617                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1618 }
1619
1620 /**
1621  * Get the numeric day number of the year, adjusted for leap year.
1622  * @return {Number} 0 through 364 (365 in leap years)
1623  */
1624 Date.prototype.getDayOfYear = function() {
1625     var num = 0;
1626     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1627     for (var i = 0; i < this.getMonth(); ++i) {
1628         num += Date.daysInMonth[i];
1629     }
1630     return num + this.getDate() - 1;
1631 };
1632
1633 /**
1634  * Get the string representation of the numeric week number of the year
1635  * (equivalent to the format specifier 'W').
1636  * @return {String} '00' through '52'
1637  */
1638 Date.prototype.getWeekOfYear = function() {
1639     // Skip to Thursday of this week
1640     var now = this.getDayOfYear() + (4 - this.getDay());
1641     // Find the first Thursday of the year
1642     var jan1 = new Date(this.getFullYear(), 0, 1);
1643     var then = (7 - jan1.getDay() + 4);
1644     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1645 };
1646
1647 /**
1648  * Whether or not the current date is in a leap year.
1649  * @return {Boolean} True if the current date is in a leap year, else false
1650  */
1651 Date.prototype.isLeapYear = function() {
1652     var year = this.getFullYear();
1653     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1654 };
1655
1656 /**
1657  * Get the first day of the current month, adjusted for leap year.  The returned value
1658  * is the numeric day index within the week (0-6) which can be used in conjunction with
1659  * the {@link #monthNames} array to retrieve the textual day name.
1660  * Example:
1661  *<pre><code>
1662 var dt = new Date('1/10/2007');
1663 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1664 </code></pre>
1665  * @return {Number} The day number (0-6)
1666  */
1667 Date.prototype.getFirstDayOfMonth = function() {
1668     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1669     return (day < 0) ? (day + 7) : day;
1670 };
1671
1672 /**
1673  * Get the last day of the current month, adjusted for leap year.  The returned value
1674  * is the numeric day index within the week (0-6) which can be used in conjunction with
1675  * the {@link #monthNames} array to retrieve the textual day name.
1676  * Example:
1677  *<pre><code>
1678 var dt = new Date('1/10/2007');
1679 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1680 </code></pre>
1681  * @return {Number} The day number (0-6)
1682  */
1683 Date.prototype.getLastDayOfMonth = function() {
1684     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1685     return (day < 0) ? (day + 7) : day;
1686 };
1687
1688
1689 /**
1690  * Get the first date of this date's month
1691  * @return {Date}
1692  */
1693 Date.prototype.getFirstDateOfMonth = function() {
1694     return new Date(this.getFullYear(), this.getMonth(), 1);
1695 };
1696
1697 /**
1698  * Get the last date of this date's month
1699  * @return {Date}
1700  */
1701 Date.prototype.getLastDateOfMonth = function() {
1702     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1703 };
1704 /**
1705  * Get the number of days in the current month, adjusted for leap year.
1706  * @return {Number} The number of days in the month
1707  */
1708 Date.prototype.getDaysInMonth = function() {
1709     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1710     return Date.daysInMonth[this.getMonth()];
1711 };
1712
1713 /**
1714  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1715  * @return {String} 'st, 'nd', 'rd' or 'th'
1716  */
1717 Date.prototype.getSuffix = function() {
1718     switch (this.getDate()) {
1719         case 1:
1720         case 21:
1721         case 31:
1722             return "st";
1723         case 2:
1724         case 22:
1725             return "nd";
1726         case 3:
1727         case 23:
1728             return "rd";
1729         default:
1730             return "th";
1731     }
1732 };
1733
1734 // private
1735 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1736
1737 /**
1738  * An array of textual month names.
1739  * Override these values for international dates, for example...
1740  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1741  * @type Array
1742  * @static
1743  */
1744 Date.monthNames =
1745    ["January",
1746     "February",
1747     "March",
1748     "April",
1749     "May",
1750     "June",
1751     "July",
1752     "August",
1753     "September",
1754     "October",
1755     "November",
1756     "December"];
1757
1758 /**
1759  * An array of textual day names.
1760  * Override these values for international dates, for example...
1761  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1762  * @type Array
1763  * @static
1764  */
1765 Date.dayNames =
1766    ["Sunday",
1767     "Monday",
1768     "Tuesday",
1769     "Wednesday",
1770     "Thursday",
1771     "Friday",
1772     "Saturday"];
1773
1774 // private
1775 Date.y2kYear = 50;
1776 // private
1777 Date.monthNumbers = {
1778     Jan:0,
1779     Feb:1,
1780     Mar:2,
1781     Apr:3,
1782     May:4,
1783     Jun:5,
1784     Jul:6,
1785     Aug:7,
1786     Sep:8,
1787     Oct:9,
1788     Nov:10,
1789     Dec:11};
1790
1791 /**
1792  * Creates and returns a new Date instance with the exact same date value as the called instance.
1793  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1794  * variable will also be changed.  When the intention is to create a new variable that will not
1795  * modify the original instance, you should create a clone.
1796  *
1797  * Example of correctly cloning a date:
1798  * <pre><code>
1799 //wrong way:
1800 var orig = new Date('10/1/2006');
1801 var copy = orig;
1802 copy.setDate(5);
1803 document.write(orig);  //returns 'Thu Oct 05 2006'!
1804
1805 //correct way:
1806 var orig = new Date('10/1/2006');
1807 var copy = orig.clone();
1808 copy.setDate(5);
1809 document.write(orig);  //returns 'Thu Oct 01 2006'
1810 </code></pre>
1811  * @return {Date} The new Date instance
1812  */
1813 Date.prototype.clone = function() {
1814         return new Date(this.getTime());
1815 };
1816
1817 /**
1818  * Clears any time information from this date
1819  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1820  @return {Date} this or the clone
1821  */
1822 Date.prototype.clearTime = function(clone){
1823     if(clone){
1824         return this.clone().clearTime();
1825     }
1826     this.setHours(0);
1827     this.setMinutes(0);
1828     this.setSeconds(0);
1829     this.setMilliseconds(0);
1830     return this;
1831 };
1832
1833 // private
1834 // safari setMonth is broken -- check that this is only donw once...
1835 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1836     Date.brokenSetMonth = Date.prototype.setMonth;
1837         Date.prototype.setMonth = function(num){
1838                 if(num <= -1){
1839                         var n = Math.ceil(-num);
1840                         var back_year = Math.ceil(n/12);
1841                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1842                         this.setFullYear(this.getFullYear() - back_year);
1843                         return Date.brokenSetMonth.call(this, month);
1844                 } else {
1845                         return Date.brokenSetMonth.apply(this, arguments);
1846                 }
1847         };
1848 }
1849
1850 /** Date interval constant 
1851 * @static 
1852 * @type String */
1853 Date.MILLI = "ms";
1854 /** Date interval constant 
1855 * @static 
1856 * @type String */
1857 Date.SECOND = "s";
1858 /** Date interval constant 
1859 * @static 
1860 * @type String */
1861 Date.MINUTE = "mi";
1862 /** Date interval constant 
1863 * @static 
1864 * @type String */
1865 Date.HOUR = "h";
1866 /** Date interval constant 
1867 * @static 
1868 * @type String */
1869 Date.DAY = "d";
1870 /** Date interval constant 
1871 * @static 
1872 * @type String */
1873 Date.MONTH = "mo";
1874 /** Date interval constant 
1875 * @static 
1876 * @type String */
1877 Date.YEAR = "y";
1878
1879 /**
1880  * Provides a convenient method of performing basic date arithmetic.  This method
1881  * does not modify the Date instance being called - it creates and returns
1882  * a new Date instance containing the resulting date value.
1883  *
1884  * Examples:
1885  * <pre><code>
1886 //Basic usage:
1887 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1888 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1889
1890 //Negative values will subtract correctly:
1891 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1892 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1893
1894 //You can even chain several calls together in one line!
1895 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1896 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1897  </code></pre>
1898  *
1899  * @param {String} interval   A valid date interval enum value
1900  * @param {Number} value      The amount to add to the current date
1901  * @return {Date} The new Date instance
1902  */
1903 Date.prototype.add = function(interval, value){
1904   var d = this.clone();
1905   if (!interval || value === 0) { return d; }
1906   switch(interval.toLowerCase()){
1907     case Date.MILLI:
1908       d.setMilliseconds(this.getMilliseconds() + value);
1909       break;
1910     case Date.SECOND:
1911       d.setSeconds(this.getSeconds() + value);
1912       break;
1913     case Date.MINUTE:
1914       d.setMinutes(this.getMinutes() + value);
1915       break;
1916     case Date.HOUR:
1917       d.setHours(this.getHours() + value);
1918       break;
1919     case Date.DAY:
1920       d.setDate(this.getDate() + value);
1921       break;
1922     case Date.MONTH:
1923       var day = this.getDate();
1924       if(day > 28){
1925           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1926       }
1927       d.setDate(day);
1928       d.setMonth(this.getMonth() + value);
1929       break;
1930     case Date.YEAR:
1931       d.setFullYear(this.getFullYear() + value);
1932       break;
1933   }
1934   return d;
1935 };
1936 /**
1937  * @class Roo.lib.Dom
1938  * @licence LGPL
1939  * @static
1940  * 
1941  * Dom utils (from YIU afaik)
1942  *
1943  * 
1944  **/
1945 Roo.lib.Dom = {
1946     /**
1947      * Get the view width
1948      * @param {Boolean} full True will get the full document, otherwise it's the view width
1949      * @return {Number} The width
1950      */
1951      
1952     getViewWidth : function(full) {
1953         return full ? this.getDocumentWidth() : this.getViewportWidth();
1954     },
1955     /**
1956      * Get the view height
1957      * @param {Boolean} full True will get the full document, otherwise it's the view height
1958      * @return {Number} The height
1959      */
1960     getViewHeight : function(full) {
1961         return full ? this.getDocumentHeight() : this.getViewportHeight();
1962     },
1963     /**
1964      * Get the Full Document height 
1965      * @return {Number} The height
1966      */
1967     getDocumentHeight: function() {
1968         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1969         return Math.max(scrollHeight, this.getViewportHeight());
1970     },
1971     /**
1972      * Get the Full Document width
1973      * @return {Number} The width
1974      */
1975     getDocumentWidth: function() {
1976         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1977         return Math.max(scrollWidth, this.getViewportWidth());
1978     },
1979     /**
1980      * Get the Window Viewport height
1981      * @return {Number} The height
1982      */
1983     getViewportHeight: function() {
1984         var height = self.innerHeight;
1985         var mode = document.compatMode;
1986
1987         if ((mode || Roo.isIE) && !Roo.isOpera) {
1988             height = (mode == "CSS1Compat") ?
1989                      document.documentElement.clientHeight :
1990                      document.body.clientHeight;
1991         }
1992
1993         return height;
1994     },
1995     /**
1996      * Get the Window Viewport width
1997      * @return {Number} The width
1998      */
1999     getViewportWidth: function() {
2000         var width = self.innerWidth;
2001         var mode = document.compatMode;
2002
2003         if (mode || Roo.isIE) {
2004             width = (mode == "CSS1Compat") ?
2005                     document.documentElement.clientWidth :
2006                     document.body.clientWidth;
2007         }
2008         return width;
2009     },
2010
2011     isAncestor : function(p, c) {
2012         p = Roo.getDom(p);
2013         c = Roo.getDom(c);
2014         if (!p || !c) {
2015             return false;
2016         }
2017
2018         if (p.contains && !Roo.isSafari) {
2019             return p.contains(c);
2020         } else if (p.compareDocumentPosition) {
2021             return !!(p.compareDocumentPosition(c) & 16);
2022         } else {
2023             var parent = c.parentNode;
2024             while (parent) {
2025                 if (parent == p) {
2026                     return true;
2027                 }
2028                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2029                     return false;
2030                 }
2031                 parent = parent.parentNode;
2032             }
2033             return false;
2034         }
2035     },
2036
2037     getRegion : function(el) {
2038         return Roo.lib.Region.getRegion(el);
2039     },
2040
2041     getY : function(el) {
2042         return this.getXY(el)[1];
2043     },
2044
2045     getX : function(el) {
2046         return this.getXY(el)[0];
2047     },
2048
2049     getXY : function(el) {
2050         var p, pe, b, scroll, bd = document.body;
2051         el = Roo.getDom(el);
2052         var fly = Roo.lib.AnimBase.fly;
2053         if (el.getBoundingClientRect) {
2054             b = el.getBoundingClientRect();
2055             scroll = fly(document).getScroll();
2056             return [b.left + scroll.left, b.top + scroll.top];
2057         }
2058         var x = 0, y = 0;
2059
2060         p = el;
2061
2062         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2063
2064         while (p) {
2065
2066             x += p.offsetLeft;
2067             y += p.offsetTop;
2068
2069             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2070                 hasAbsolute = true;
2071             }
2072
2073             if (Roo.isGecko) {
2074                 pe = fly(p);
2075
2076                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2077                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2078
2079
2080                 x += bl;
2081                 y += bt;
2082
2083
2084                 if (p != el && pe.getStyle('overflow') != 'visible') {
2085                     x += bl;
2086                     y += bt;
2087                 }
2088             }
2089             p = p.offsetParent;
2090         }
2091
2092         if (Roo.isSafari && hasAbsolute) {
2093             x -= bd.offsetLeft;
2094             y -= bd.offsetTop;
2095         }
2096
2097         if (Roo.isGecko && !hasAbsolute) {
2098             var dbd = fly(bd);
2099             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2100             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2101         }
2102
2103         p = el.parentNode;
2104         while (p && p != bd) {
2105             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2106                 x -= p.scrollLeft;
2107                 y -= p.scrollTop;
2108             }
2109             p = p.parentNode;
2110         }
2111         return [x, y];
2112     },
2113  
2114   
2115
2116
2117     setXY : function(el, xy) {
2118         el = Roo.fly(el, '_setXY');
2119         el.position();
2120         var pts = el.translatePoints(xy);
2121         if (xy[0] !== false) {
2122             el.dom.style.left = pts.left + "px";
2123         }
2124         if (xy[1] !== false) {
2125             el.dom.style.top = pts.top + "px";
2126         }
2127     },
2128
2129     setX : function(el, x) {
2130         this.setXY(el, [x, false]);
2131     },
2132
2133     setY : function(el, y) {
2134         this.setXY(el, [false, y]);
2135     }
2136 };
2137 /*
2138  * Portions of this file are based on pieces of Yahoo User Interface Library
2139  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2140  * YUI licensed under the BSD License:
2141  * http://developer.yahoo.net/yui/license.txt
2142  * <script type="text/javascript">
2143  *
2144  */
2145
2146 Roo.lib.Event = function() {
2147     var loadComplete = false;
2148     var listeners = [];
2149     var unloadListeners = [];
2150     var retryCount = 0;
2151     var onAvailStack = [];
2152     var counter = 0;
2153     var lastError = null;
2154
2155     return {
2156         POLL_RETRYS: 200,
2157         POLL_INTERVAL: 20,
2158         EL: 0,
2159         TYPE: 1,
2160         FN: 2,
2161         WFN: 3,
2162         OBJ: 3,
2163         ADJ_SCOPE: 4,
2164         _interval: null,
2165
2166         startInterval: function() {
2167             if (!this._interval) {
2168                 var self = this;
2169                 var callback = function() {
2170                     self._tryPreloadAttach();
2171                 };
2172                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2173
2174             }
2175         },
2176
2177         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2178             onAvailStack.push({ id:         p_id,
2179                 fn:         p_fn,
2180                 obj:        p_obj,
2181                 override:   p_override,
2182                 checkReady: false    });
2183
2184             retryCount = this.POLL_RETRYS;
2185             this.startInterval();
2186         },
2187
2188
2189         addListener: function(el, eventName, fn) {
2190             el = Roo.getDom(el);
2191             if (!el || !fn) {
2192                 return false;
2193             }
2194
2195             if ("unload" == eventName) {
2196                 unloadListeners[unloadListeners.length] =
2197                 [el, eventName, fn];
2198                 return true;
2199             }
2200
2201             var wrappedFn = function(e) {
2202                 return fn(Roo.lib.Event.getEvent(e));
2203             };
2204
2205             var li = [el, eventName, fn, wrappedFn];
2206
2207             var index = listeners.length;
2208             listeners[index] = li;
2209
2210             this.doAdd(el, eventName, wrappedFn, false);
2211             return true;
2212
2213         },
2214
2215
2216         removeListener: function(el, eventName, fn) {
2217             var i, len;
2218
2219             el = Roo.getDom(el);
2220
2221             if(!fn) {
2222                 return this.purgeElement(el, false, eventName);
2223             }
2224
2225
2226             if ("unload" == eventName) {
2227
2228                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2229                     var li = unloadListeners[i];
2230                     if (li &&
2231                         li[0] == el &&
2232                         li[1] == eventName &&
2233                         li[2] == fn) {
2234                         unloadListeners.splice(i, 1);
2235                         return true;
2236                     }
2237                 }
2238
2239                 return false;
2240             }
2241
2242             var cacheItem = null;
2243
2244
2245             var index = arguments[3];
2246
2247             if ("undefined" == typeof index) {
2248                 index = this._getCacheIndex(el, eventName, fn);
2249             }
2250
2251             if (index >= 0) {
2252                 cacheItem = listeners[index];
2253             }
2254
2255             if (!el || !cacheItem) {
2256                 return false;
2257             }
2258
2259             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2260
2261             delete listeners[index][this.WFN];
2262             delete listeners[index][this.FN];
2263             listeners.splice(index, 1);
2264
2265             return true;
2266
2267         },
2268
2269
2270         getTarget: function(ev, resolveTextNode) {
2271             ev = ev.browserEvent || ev;
2272             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2273             var t = ev.target || ev.srcElement;
2274             return this.resolveTextNode(t);
2275         },
2276
2277
2278         resolveTextNode: function(node) {
2279             if (Roo.isSafari && node && 3 == node.nodeType) {
2280                 return node.parentNode;
2281             } else {
2282                 return node;
2283             }
2284         },
2285
2286
2287         getPageX: function(ev) {
2288             ev = ev.browserEvent || ev;
2289             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2290             var x = ev.pageX;
2291             if (!x && 0 !== x) {
2292                 x = ev.clientX || 0;
2293
2294                 if (Roo.isIE) {
2295                     x += this.getScroll()[1];
2296                 }
2297             }
2298
2299             return x;
2300         },
2301
2302
2303         getPageY: function(ev) {
2304             ev = ev.browserEvent || ev;
2305             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2306             var y = ev.pageY;
2307             if (!y && 0 !== y) {
2308                 y = ev.clientY || 0;
2309
2310                 if (Roo.isIE) {
2311                     y += this.getScroll()[0];
2312                 }
2313             }
2314
2315
2316             return y;
2317         },
2318
2319
2320         getXY: function(ev) {
2321             ev = ev.browserEvent || ev;
2322             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2323             return [this.getPageX(ev), this.getPageY(ev)];
2324         },
2325
2326
2327         getRelatedTarget: function(ev) {
2328             ev = ev.browserEvent || ev;
2329             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2330             var t = ev.relatedTarget;
2331             if (!t) {
2332                 if (ev.type == "mouseout") {
2333                     t = ev.toElement;
2334                 } else if (ev.type == "mouseover") {
2335                     t = ev.fromElement;
2336                 }
2337             }
2338
2339             return this.resolveTextNode(t);
2340         },
2341
2342
2343         getTime: function(ev) {
2344             ev = ev.browserEvent || ev;
2345             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2346             if (!ev.time) {
2347                 var t = new Date().getTime();
2348                 try {
2349                     ev.time = t;
2350                 } catch(ex) {
2351                     this.lastError = ex;
2352                     return t;
2353                 }
2354             }
2355
2356             return ev.time;
2357         },
2358
2359
2360         stopEvent: function(ev) {
2361             this.stopPropagation(ev);
2362             this.preventDefault(ev);
2363         },
2364
2365
2366         stopPropagation: function(ev) {
2367             ev = ev.browserEvent || ev;
2368             if (ev.stopPropagation) {
2369                 ev.stopPropagation();
2370             } else {
2371                 ev.cancelBubble = true;
2372             }
2373         },
2374
2375
2376         preventDefault: function(ev) {
2377             ev = ev.browserEvent || ev;
2378             if(ev.preventDefault) {
2379                 ev.preventDefault();
2380             } else {
2381                 ev.returnValue = false;
2382             }
2383         },
2384
2385
2386         getEvent: function(e) {
2387             var ev = e || window.event;
2388             if (!ev) {
2389                 var c = this.getEvent.caller;
2390                 while (c) {
2391                     ev = c.arguments[0];
2392                     if (ev && Event == ev.constructor) {
2393                         break;
2394                     }
2395                     c = c.caller;
2396                 }
2397             }
2398             return ev;
2399         },
2400
2401
2402         getCharCode: function(ev) {
2403             ev = ev.browserEvent || ev;
2404             return ev.charCode || ev.keyCode || 0;
2405         },
2406
2407
2408         _getCacheIndex: function(el, eventName, fn) {
2409             for (var i = 0,len = listeners.length; i < len; ++i) {
2410                 var li = listeners[i];
2411                 if (li &&
2412                     li[this.FN] == fn &&
2413                     li[this.EL] == el &&
2414                     li[this.TYPE] == eventName) {
2415                     return i;
2416                 }
2417             }
2418
2419             return -1;
2420         },
2421
2422
2423         elCache: {},
2424
2425
2426         getEl: function(id) {
2427             return document.getElementById(id);
2428         },
2429
2430
2431         clearCache: function() {
2432         },
2433
2434
2435         _load: function(e) {
2436             loadComplete = true;
2437             var EU = Roo.lib.Event;
2438
2439
2440             if (Roo.isIE) {
2441                 EU.doRemove(window, "load", EU._load);
2442             }
2443         },
2444
2445
2446         _tryPreloadAttach: function() {
2447
2448             if (this.locked) {
2449                 return false;
2450             }
2451
2452             this.locked = true;
2453
2454
2455             var tryAgain = !loadComplete;
2456             if (!tryAgain) {
2457                 tryAgain = (retryCount > 0);
2458             }
2459
2460
2461             var notAvail = [];
2462             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2463                 var item = onAvailStack[i];
2464                 if (item) {
2465                     var el = this.getEl(item.id);
2466
2467                     if (el) {
2468                         if (!item.checkReady ||
2469                             loadComplete ||
2470                             el.nextSibling ||
2471                             (document && document.body)) {
2472
2473                             var scope = el;
2474                             if (item.override) {
2475                                 if (item.override === true) {
2476                                     scope = item.obj;
2477                                 } else {
2478                                     scope = item.override;
2479                                 }
2480                             }
2481                             item.fn.call(scope, item.obj);
2482                             onAvailStack[i] = null;
2483                         }
2484                     } else {
2485                         notAvail.push(item);
2486                     }
2487                 }
2488             }
2489
2490             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2491
2492             if (tryAgain) {
2493
2494                 this.startInterval();
2495             } else {
2496                 clearInterval(this._interval);
2497                 this._interval = null;
2498             }
2499
2500             this.locked = false;
2501
2502             return true;
2503
2504         },
2505
2506
2507         purgeElement: function(el, recurse, eventName) {
2508             var elListeners = this.getListeners(el, eventName);
2509             if (elListeners) {
2510                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2511                     var l = elListeners[i];
2512                     this.removeListener(el, l.type, l.fn);
2513                 }
2514             }
2515
2516             if (recurse && el && el.childNodes) {
2517                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2518                     this.purgeElement(el.childNodes[i], recurse, eventName);
2519                 }
2520             }
2521         },
2522
2523
2524         getListeners: function(el, eventName) {
2525             var results = [], searchLists;
2526             if (!eventName) {
2527                 searchLists = [listeners, unloadListeners];
2528             } else if (eventName == "unload") {
2529                 searchLists = [unloadListeners];
2530             } else {
2531                 searchLists = [listeners];
2532             }
2533
2534             for (var j = 0; j < searchLists.length; ++j) {
2535                 var searchList = searchLists[j];
2536                 if (searchList && searchList.length > 0) {
2537                     for (var i = 0,len = searchList.length; i < len; ++i) {
2538                         var l = searchList[i];
2539                         if (l && l[this.EL] === el &&
2540                             (!eventName || eventName === l[this.TYPE])) {
2541                             results.push({
2542                                 type:   l[this.TYPE],
2543                                 fn:     l[this.FN],
2544                                 obj:    l[this.OBJ],
2545                                 adjust: l[this.ADJ_SCOPE],
2546                                 index:  i
2547                             });
2548                         }
2549                     }
2550                 }
2551             }
2552
2553             return (results.length) ? results : null;
2554         },
2555
2556
2557         _unload: function(e) {
2558
2559             var EU = Roo.lib.Event, i, j, l, len, index;
2560
2561             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2562                 l = unloadListeners[i];
2563                 if (l) {
2564                     var scope = window;
2565                     if (l[EU.ADJ_SCOPE]) {
2566                         if (l[EU.ADJ_SCOPE] === true) {
2567                             scope = l[EU.OBJ];
2568                         } else {
2569                             scope = l[EU.ADJ_SCOPE];
2570                         }
2571                     }
2572                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2573                     unloadListeners[i] = null;
2574                     l = null;
2575                     scope = null;
2576                 }
2577             }
2578
2579             unloadListeners = null;
2580
2581             if (listeners && listeners.length > 0) {
2582                 j = listeners.length;
2583                 while (j) {
2584                     index = j - 1;
2585                     l = listeners[index];
2586                     if (l) {
2587                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2588                                 l[EU.FN], index);
2589                     }
2590                     j = j - 1;
2591                 }
2592                 l = null;
2593
2594                 EU.clearCache();
2595             }
2596
2597             EU.doRemove(window, "unload", EU._unload);
2598
2599         },
2600
2601
2602         getScroll: function() {
2603             var dd = document.documentElement, db = document.body;
2604             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2605                 return [dd.scrollTop, dd.scrollLeft];
2606             } else if (db) {
2607                 return [db.scrollTop, db.scrollLeft];
2608             } else {
2609                 return [0, 0];
2610             }
2611         },
2612
2613
2614         doAdd: function () {
2615             if (window.addEventListener) {
2616                 return function(el, eventName, fn, capture) {
2617                     el.addEventListener(eventName, fn, (capture));
2618                 };
2619             } else if (window.attachEvent) {
2620                 return function(el, eventName, fn, capture) {
2621                     el.attachEvent("on" + eventName, fn);
2622                 };
2623             } else {
2624                 return function() {
2625                 };
2626             }
2627         }(),
2628
2629
2630         doRemove: function() {
2631             if (window.removeEventListener) {
2632                 return function (el, eventName, fn, capture) {
2633                     el.removeEventListener(eventName, fn, (capture));
2634                 };
2635             } else if (window.detachEvent) {
2636                 return function (el, eventName, fn) {
2637                     el.detachEvent("on" + eventName, fn);
2638                 };
2639             } else {
2640                 return function() {
2641                 };
2642             }
2643         }()
2644     };
2645     
2646 }();
2647 (function() {     
2648    
2649     var E = Roo.lib.Event;
2650     E.on = E.addListener;
2651     E.un = E.removeListener;
2652
2653     if (document && document.body) {
2654         E._load();
2655     } else {
2656         E.doAdd(window, "load", E._load);
2657     }
2658     E.doAdd(window, "unload", E._unload);
2659     E._tryPreloadAttach();
2660 })();
2661
2662  
2663
2664 (function() {
2665     /**
2666      * @class Roo.lib.Ajax
2667      *
2668      * provide a simple Ajax request utility functions
2669      * 
2670      * Portions of this file are based on pieces of Yahoo User Interface Library
2671     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2672     * YUI licensed under the BSD License:
2673     * http://developer.yahoo.net/yui/license.txt
2674     * <script type="text/javascript">
2675     *
2676      *
2677      */
2678     Roo.lib.Ajax = {
2679         /**
2680          * @static 
2681          */
2682         request : function(method, uri, cb, data, options) {
2683             if(options){
2684                 var hs = options.headers;
2685                 if(hs){
2686                     for(var h in hs){
2687                         if(hs.hasOwnProperty(h)){
2688                             this.initHeader(h, hs[h], false);
2689                         }
2690                     }
2691                 }
2692                 if(options.xmlData){
2693                     this.initHeader('Content-Type', 'text/xml', false);
2694                     method = 'POST';
2695                     data = options.xmlData;
2696                 }
2697             }
2698
2699             return this.asyncRequest(method, uri, cb, data);
2700         },
2701         /**
2702          * serialize a form
2703          *
2704          * @static
2705          * @param {DomForm} form element
2706          * @return {String} urlencode form output.
2707          */
2708         serializeForm : function(form, include_disabled) {
2709             
2710             include_disabled = typeof(include_disabled) == 'undefined' ? false : include_disabled;
2711
2712             if(typeof form == 'string') {
2713                 form = (document.getElementById(form) || document.forms[form]);
2714             }
2715
2716             var el, name, val, disabled, data = '', hasSubmit = false;
2717             for (var i = 0; i < form.elements.length; i++) {
2718                 el = form.elements[i];
2719                 disabled = include_disabled ? false : form.elements[i].disabled;
2720                 name = form.elements[i].name;
2721                 val = form.elements[i].value;
2722
2723                 if (!disabled && name){
2724                     switch (el.type)
2725                             {
2726                         case 'select-one':
2727                         case 'select-multiple':
2728                             for (var j = 0; j < el.options.length; j++) {
2729                                 if (el.options[j].selected) {
2730                                     if (Roo.isIE) {
2731                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2732                                     }
2733                                     else {
2734                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2735                                     }
2736                                 }
2737                             }
2738                             break;
2739                         case 'radio':
2740                         case 'checkbox':
2741                             if (el.checked) {
2742                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2743                             }
2744                             break;
2745                         case 'file':
2746
2747                         case undefined:
2748
2749                         case 'reset':
2750
2751                         case 'button':
2752
2753                             break;
2754                         case 'submit':
2755                             if(hasSubmit == false) {
2756                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2757                                 hasSubmit = true;
2758                             }
2759                             break;
2760                         default:
2761                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2762                             break;
2763                     }
2764                 }
2765             }
2766             data = data.substr(0, data.length - 1);
2767             return data;
2768         },
2769
2770         headers:{},
2771
2772         hasHeaders:false,
2773
2774         useDefaultHeader:true,
2775
2776         defaultPostHeader:'application/x-www-form-urlencoded',
2777
2778         useDefaultXhrHeader:true,
2779
2780         defaultXhrHeader:'XMLHttpRequest',
2781
2782         hasDefaultHeaders:true,
2783
2784         defaultHeaders:{},
2785
2786         poll:{},
2787
2788         timeout:{},
2789
2790         pollInterval:50,
2791
2792         transactionId:0,
2793
2794         setProgId:function(id)
2795         {
2796             this.activeX.unshift(id);
2797         },
2798
2799         setDefaultPostHeader:function(b)
2800         {
2801             this.useDefaultHeader = b;
2802         },
2803
2804         setDefaultXhrHeader:function(b)
2805         {
2806             this.useDefaultXhrHeader = b;
2807         },
2808
2809         setPollingInterval:function(i)
2810         {
2811             if (typeof i == 'number' && isFinite(i)) {
2812                 this.pollInterval = i;
2813             }
2814         },
2815
2816         createXhrObject:function(transactionId)
2817         {
2818             var obj,http;
2819             try
2820             {
2821
2822                 http = new XMLHttpRequest();
2823
2824                 obj = { conn:http, tId:transactionId };
2825             }
2826             catch(e)
2827             {
2828                 for (var i = 0; i < this.activeX.length; ++i) {
2829                     try
2830                     {
2831
2832                         http = new ActiveXObject(this.activeX[i]);
2833
2834                         obj = { conn:http, tId:transactionId };
2835                         break;
2836                     }
2837                     catch(e) {
2838                     }
2839                 }
2840             }
2841             finally
2842             {
2843                 return obj;
2844             }
2845         },
2846
2847         getConnectionObject:function()
2848         {
2849             var o;
2850             var tId = this.transactionId;
2851
2852             try
2853             {
2854                 o = this.createXhrObject(tId);
2855                 if (o) {
2856                     this.transactionId++;
2857                 }
2858             }
2859             catch(e) {
2860             }
2861             finally
2862             {
2863                 return o;
2864             }
2865         },
2866
2867         asyncRequest:function(method, uri, callback, postData)
2868         {
2869             var o = this.getConnectionObject();
2870
2871             if (!o) {
2872                 return null;
2873             }
2874             else {
2875                 o.conn.open(method, uri, true);
2876
2877                 if (this.useDefaultXhrHeader) {
2878                     if (!this.defaultHeaders['X-Requested-With']) {
2879                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2880                     }
2881                 }
2882
2883                 if(postData && this.useDefaultHeader){
2884                     this.initHeader('Content-Type', this.defaultPostHeader);
2885                 }
2886
2887                  if (this.hasDefaultHeaders || this.hasHeaders) {
2888                     this.setHeader(o);
2889                 }
2890
2891                 this.handleReadyState(o, callback);
2892                 o.conn.send(postData || null);
2893
2894                 return o;
2895             }
2896         },
2897
2898         handleReadyState:function(o, callback)
2899         {
2900             var oConn = this;
2901
2902             if (callback && callback.timeout) {
2903                 
2904                 this.timeout[o.tId] = window.setTimeout(function() {
2905                     oConn.abort(o, callback, true);
2906                 }, callback.timeout);
2907             }
2908
2909             this.poll[o.tId] = window.setInterval(
2910                     function() {
2911                         if (o.conn && o.conn.readyState == 4) {
2912                             window.clearInterval(oConn.poll[o.tId]);
2913                             delete oConn.poll[o.tId];
2914
2915                             if(callback && callback.timeout) {
2916                                 window.clearTimeout(oConn.timeout[o.tId]);
2917                                 delete oConn.timeout[o.tId];
2918                             }
2919
2920                             oConn.handleTransactionResponse(o, callback);
2921                         }
2922                     }
2923                     , this.pollInterval);
2924         },
2925
2926         handleTransactionResponse:function(o, callback, isAbort)
2927         {
2928
2929             if (!callback) {
2930                 this.releaseObject(o);
2931                 return;
2932             }
2933
2934             var httpStatus, responseObject;
2935
2936             try
2937             {
2938                 if (o.conn.status !== undefined && o.conn.status != 0) {
2939                     httpStatus = o.conn.status;
2940                 }
2941                 else {
2942                     httpStatus = 13030;
2943                 }
2944             }
2945             catch(e) {
2946
2947
2948                 httpStatus = 13030;
2949             }
2950
2951             if (httpStatus >= 200 && httpStatus < 300) {
2952                 responseObject = this.createResponseObject(o, callback.argument);
2953                 if (callback.success) {
2954                     if (!callback.scope) {
2955                         callback.success(responseObject);
2956                     }
2957                     else {
2958
2959
2960                         callback.success.apply(callback.scope, [responseObject]);
2961                     }
2962                 }
2963             }
2964             else {
2965                 switch (httpStatus) {
2966
2967                     case 12002:
2968                     case 12029:
2969                     case 12030:
2970                     case 12031:
2971                     case 12152:
2972                     case 13030:
2973                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2974                         if (callback.failure) {
2975                             if (!callback.scope) {
2976                                 callback.failure(responseObject);
2977                             }
2978                             else {
2979                                 callback.failure.apply(callback.scope, [responseObject]);
2980                             }
2981                         }
2982                         break;
2983                     default:
2984                         responseObject = this.createResponseObject(o, callback.argument);
2985                         if (callback.failure) {
2986                             if (!callback.scope) {
2987                                 callback.failure(responseObject);
2988                             }
2989                             else {
2990                                 callback.failure.apply(callback.scope, [responseObject]);
2991                             }
2992                         }
2993                 }
2994             }
2995
2996             this.releaseObject(o);
2997             responseObject = null;
2998         },
2999
3000         createResponseObject:function(o, callbackArg)
3001         {
3002             var obj = {};
3003             var headerObj = {};
3004
3005             try
3006             {
3007                 var headerStr = o.conn.getAllResponseHeaders();
3008                 var header = headerStr.split('\n');
3009                 for (var i = 0; i < header.length; i++) {
3010                     var delimitPos = header[i].indexOf(':');
3011                     if (delimitPos != -1) {
3012                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3013                     }
3014                 }
3015             }
3016             catch(e) {
3017             }
3018
3019             obj.tId = o.tId;
3020             obj.status = o.conn.status;
3021             obj.statusText = o.conn.statusText;
3022             obj.getResponseHeader = headerObj;
3023             obj.getAllResponseHeaders = headerStr;
3024             obj.responseText = o.conn.responseText;
3025             obj.responseXML = o.conn.responseXML;
3026
3027             if (typeof callbackArg !== undefined) {
3028                 obj.argument = callbackArg;
3029             }
3030
3031             return obj;
3032         },
3033
3034         createExceptionObject:function(tId, callbackArg, isAbort)
3035         {
3036             var COMM_CODE = 0;
3037             var COMM_ERROR = 'communication failure';
3038             var ABORT_CODE = -1;
3039             var ABORT_ERROR = 'transaction aborted';
3040
3041             var obj = {};
3042
3043             obj.tId = tId;
3044             if (isAbort) {
3045                 obj.status = ABORT_CODE;
3046                 obj.statusText = ABORT_ERROR;
3047             }
3048             else {
3049                 obj.status = COMM_CODE;
3050                 obj.statusText = COMM_ERROR;
3051             }
3052
3053             if (callbackArg) {
3054                 obj.argument = callbackArg;
3055             }
3056
3057             return obj;
3058         },
3059
3060         initHeader:function(label, value, isDefault)
3061         {
3062             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3063
3064             if (headerObj[label] === undefined) {
3065                 headerObj[label] = value;
3066             }
3067             else {
3068
3069
3070                 headerObj[label] = value + "," + headerObj[label];
3071             }
3072
3073             if (isDefault) {
3074                 this.hasDefaultHeaders = true;
3075             }
3076             else {
3077                 this.hasHeaders = true;
3078             }
3079         },
3080
3081
3082         setHeader:function(o)
3083         {
3084             if (this.hasDefaultHeaders) {
3085                 for (var prop in this.defaultHeaders) {
3086                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3087                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3088                     }
3089                 }
3090             }
3091
3092             if (this.hasHeaders) {
3093                 for (var prop in this.headers) {
3094                     if (this.headers.hasOwnProperty(prop)) {
3095                         o.conn.setRequestHeader(prop, this.headers[prop]);
3096                     }
3097                 }
3098                 this.headers = {};
3099                 this.hasHeaders = false;
3100             }
3101         },
3102
3103         resetDefaultHeaders:function() {
3104             delete this.defaultHeaders;
3105             this.defaultHeaders = {};
3106             this.hasDefaultHeaders = false;
3107         },
3108
3109         abort:function(o, callback, isTimeout)
3110         {
3111             if(this.isCallInProgress(o)) {
3112                 o.conn.abort();
3113                 window.clearInterval(this.poll[o.tId]);
3114                 delete this.poll[o.tId];
3115                 if (isTimeout) {
3116                     delete this.timeout[o.tId];
3117                 }
3118
3119                 this.handleTransactionResponse(o, callback, true);
3120
3121                 return true;
3122             }
3123             else {
3124                 return false;
3125             }
3126         },
3127
3128
3129         isCallInProgress:function(o)
3130         {
3131             if (o && o.conn) {
3132                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3133             }
3134             else {
3135
3136                 return false;
3137             }
3138         },
3139
3140
3141         releaseObject:function(o)
3142         {
3143
3144             o.conn = null;
3145
3146             o = null;
3147         },
3148
3149         activeX:[
3150         'MSXML2.XMLHTTP.3.0',
3151         'MSXML2.XMLHTTP',
3152         'Microsoft.XMLHTTP'
3153         ]
3154
3155
3156     };
3157 })();/*
3158  * Portions of this file are based on pieces of Yahoo User Interface Library
3159  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3160  * YUI licensed under the BSD License:
3161  * http://developer.yahoo.net/yui/license.txt
3162  * <script type="text/javascript">
3163  *
3164  */
3165
3166 Roo.lib.Region = function(t, r, b, l) {
3167     this.top = t;
3168     this[1] = t;
3169     this.right = r;
3170     this.bottom = b;
3171     this.left = l;
3172     this[0] = l;
3173 };
3174
3175
3176 Roo.lib.Region.prototype = {
3177     contains : function(region) {
3178         return ( region.left >= this.left &&
3179                  region.right <= this.right &&
3180                  region.top >= this.top &&
3181                  region.bottom <= this.bottom    );
3182
3183     },
3184
3185     getArea : function() {
3186         return ( (this.bottom - this.top) * (this.right - this.left) );
3187     },
3188
3189     intersect : function(region) {
3190         var t = Math.max(this.top, region.top);
3191         var r = Math.min(this.right, region.right);
3192         var b = Math.min(this.bottom, region.bottom);
3193         var l = Math.max(this.left, region.left);
3194
3195         if (b >= t && r >= l) {
3196             return new Roo.lib.Region(t, r, b, l);
3197         } else {
3198             return null;
3199         }
3200     },
3201     union : function(region) {
3202         var t = Math.min(this.top, region.top);
3203         var r = Math.max(this.right, region.right);
3204         var b = Math.max(this.bottom, region.bottom);
3205         var l = Math.min(this.left, region.left);
3206
3207         return new Roo.lib.Region(t, r, b, l);
3208     },
3209
3210     adjust : function(t, l, b, r) {
3211         this.top += t;
3212         this.left += l;
3213         this.right += r;
3214         this.bottom += b;
3215         return this;
3216     }
3217 };
3218
3219 Roo.lib.Region.getRegion = function(el) {
3220     var p = Roo.lib.Dom.getXY(el);
3221
3222     var t = p[1];
3223     var r = p[0] + el.offsetWidth;
3224     var b = p[1] + el.offsetHeight;
3225     var l = p[0];
3226
3227     return new Roo.lib.Region(t, r, b, l);
3228 };
3229 /*
3230  * Portions of this file are based on pieces of Yahoo User Interface Library
3231  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3232  * YUI licensed under the BSD License:
3233  * http://developer.yahoo.net/yui/license.txt
3234  * <script type="text/javascript">
3235  *
3236  */
3237 //@@dep Roo.lib.Region
3238
3239
3240 Roo.lib.Point = function(x, y) {
3241     if (x instanceof Array) {
3242         y = x[1];
3243         x = x[0];
3244     }
3245     this.x = this.right = this.left = this[0] = x;
3246     this.y = this.top = this.bottom = this[1] = y;
3247 };
3248
3249 Roo.lib.Point.prototype = new Roo.lib.Region();
3250 /*
3251  * Portions of this file are based on pieces of Yahoo User Interface Library
3252  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3253  * YUI licensed under the BSD License:
3254  * http://developer.yahoo.net/yui/license.txt
3255  * <script type="text/javascript">
3256  *
3257  */
3258  
3259 (function() {   
3260
3261     Roo.lib.Anim = {
3262         scroll : function(el, args, duration, easing, cb, scope) {
3263             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3264         },
3265
3266         motion : function(el, args, duration, easing, cb, scope) {
3267             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3268         },
3269
3270         color : function(el, args, duration, easing, cb, scope) {
3271             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3272         },
3273
3274         run : function(el, args, duration, easing, cb, scope, type) {
3275             type = type || Roo.lib.AnimBase;
3276             if (typeof easing == "string") {
3277                 easing = Roo.lib.Easing[easing];
3278             }
3279             var anim = new type(el, args, duration, easing);
3280             anim.animateX(function() {
3281                 Roo.callback(cb, scope);
3282             });
3283             return anim;
3284         }
3285     };
3286 })();/*
3287  * Portions of this file are based on pieces of Yahoo User Interface Library
3288  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3289  * YUI licensed under the BSD License:
3290  * http://developer.yahoo.net/yui/license.txt
3291  * <script type="text/javascript">
3292  *
3293  */
3294
3295 (function() {    
3296     var libFlyweight;
3297     
3298     function fly(el) {
3299         if (!libFlyweight) {
3300             libFlyweight = new Roo.Element.Flyweight();
3301         }
3302         libFlyweight.dom = el;
3303         return libFlyweight;
3304     }
3305
3306     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3307     
3308    
3309     
3310     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3311         if (el) {
3312             this.init(el, attributes, duration, method);
3313         }
3314     };
3315
3316     Roo.lib.AnimBase.fly = fly;
3317     
3318     
3319     
3320     Roo.lib.AnimBase.prototype = {
3321
3322         toString: function() {
3323             var el = this.getEl();
3324             var id = el.id || el.tagName;
3325             return ("Anim " + id);
3326         },
3327
3328         patterns: {
3329             noNegatives:        /width|height|opacity|padding/i,
3330             offsetAttribute:  /^((width|height)|(top|left))$/,
3331             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3332             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3333         },
3334
3335
3336         doMethod: function(attr, start, end) {
3337             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3338         },
3339
3340
3341         setAttribute: function(attr, val, unit) {
3342             if (this.patterns.noNegatives.test(attr)) {
3343                 val = (val > 0) ? val : 0;
3344             }
3345
3346             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3347         },
3348
3349
3350         getAttribute: function(attr) {
3351             var el = this.getEl();
3352             var val = fly(el).getStyle(attr);
3353
3354             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3355                 return parseFloat(val);
3356             }
3357
3358             var a = this.patterns.offsetAttribute.exec(attr) || [];
3359             var pos = !!( a[3] );
3360             var box = !!( a[2] );
3361
3362
3363             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3364                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3365             } else {
3366                 val = 0;
3367             }
3368
3369             return val;
3370         },
3371
3372
3373         getDefaultUnit: function(attr) {
3374             if (this.patterns.defaultUnit.test(attr)) {
3375                 return 'px';
3376             }
3377
3378             return '';
3379         },
3380
3381         animateX : function(callback, scope) {
3382             var f = function() {
3383                 this.onComplete.removeListener(f);
3384                 if (typeof callback == "function") {
3385                     callback.call(scope || this, this);
3386                 }
3387             };
3388             this.onComplete.addListener(f, this);
3389             this.animate();
3390         },
3391
3392
3393         setRuntimeAttribute: function(attr) {
3394             var start;
3395             var end;
3396             var attributes = this.attributes;
3397
3398             this.runtimeAttributes[attr] = {};
3399
3400             var isset = function(prop) {
3401                 return (typeof prop !== 'undefined');
3402             };
3403
3404             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3405                 return false;
3406             }
3407
3408             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3409
3410
3411             if (isset(attributes[attr]['to'])) {
3412                 end = attributes[attr]['to'];
3413             } else if (isset(attributes[attr]['by'])) {
3414                 if (start.constructor == Array) {
3415                     end = [];
3416                     for (var i = 0, len = start.length; i < len; ++i) {
3417                         end[i] = start[i] + attributes[attr]['by'][i];
3418                     }
3419                 } else {
3420                     end = start + attributes[attr]['by'];
3421                 }
3422             }
3423
3424             this.runtimeAttributes[attr].start = start;
3425             this.runtimeAttributes[attr].end = end;
3426
3427
3428             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3429         },
3430
3431
3432         init: function(el, attributes, duration, method) {
3433
3434             var isAnimated = false;
3435
3436
3437             var startTime = null;
3438
3439
3440             var actualFrames = 0;
3441
3442
3443             el = Roo.getDom(el);
3444
3445
3446             this.attributes = attributes || {};
3447
3448
3449             this.duration = duration || 1;
3450
3451
3452             this.method = method || Roo.lib.Easing.easeNone;
3453
3454
3455             this.useSeconds = true;
3456
3457
3458             this.currentFrame = 0;
3459
3460
3461             this.totalFrames = Roo.lib.AnimMgr.fps;
3462
3463
3464             this.getEl = function() {
3465                 return el;
3466             };
3467
3468
3469             this.isAnimated = function() {
3470                 return isAnimated;
3471             };
3472
3473
3474             this.getStartTime = function() {
3475                 return startTime;
3476             };
3477
3478             this.runtimeAttributes = {};
3479
3480
3481             this.animate = function() {
3482                 if (this.isAnimated()) {
3483                     return false;
3484                 }
3485
3486                 this.currentFrame = 0;
3487
3488                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3489
3490                 Roo.lib.AnimMgr.registerElement(this);
3491             };
3492
3493
3494             this.stop = function(finish) {
3495                 if (finish) {
3496                     this.currentFrame = this.totalFrames;
3497                     this._onTween.fire();
3498                 }
3499                 Roo.lib.AnimMgr.stop(this);
3500             };
3501
3502             var onStart = function() {
3503                 this.onStart.fire();
3504
3505                 this.runtimeAttributes = {};
3506                 for (var attr in this.attributes) {
3507                     this.setRuntimeAttribute(attr);
3508                 }
3509
3510                 isAnimated = true;
3511                 actualFrames = 0;
3512                 startTime = new Date();
3513             };
3514
3515
3516             var onTween = function() {
3517                 var data = {
3518                     duration: new Date() - this.getStartTime(),
3519                     currentFrame: this.currentFrame
3520                 };
3521
3522                 data.toString = function() {
3523                     return (
3524                             'duration: ' + data.duration +
3525                             ', currentFrame: ' + data.currentFrame
3526                             );
3527                 };
3528
3529                 this.onTween.fire(data);
3530
3531                 var runtimeAttributes = this.runtimeAttributes;
3532
3533                 for (var attr in runtimeAttributes) {
3534                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3535                 }
3536
3537                 actualFrames += 1;
3538             };
3539
3540             var onComplete = function() {
3541                 var actual_duration = (new Date() - startTime) / 1000 ;
3542
3543                 var data = {
3544                     duration: actual_duration,
3545                     frames: actualFrames,
3546                     fps: actualFrames / actual_duration
3547                 };
3548
3549                 data.toString = function() {
3550                     return (
3551                             'duration: ' + data.duration +
3552                             ', frames: ' + data.frames +
3553                             ', fps: ' + data.fps
3554                             );
3555                 };
3556
3557                 isAnimated = false;
3558                 actualFrames = 0;
3559                 this.onComplete.fire(data);
3560             };
3561
3562
3563             this._onStart = new Roo.util.Event(this);
3564             this.onStart = new Roo.util.Event(this);
3565             this.onTween = new Roo.util.Event(this);
3566             this._onTween = new Roo.util.Event(this);
3567             this.onComplete = new Roo.util.Event(this);
3568             this._onComplete = new Roo.util.Event(this);
3569             this._onStart.addListener(onStart);
3570             this._onTween.addListener(onTween);
3571             this._onComplete.addListener(onComplete);
3572         }
3573     };
3574 })();
3575 /*
3576  * Portions of this file are based on pieces of Yahoo User Interface Library
3577  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3578  * YUI licensed under the BSD License:
3579  * http://developer.yahoo.net/yui/license.txt
3580  * <script type="text/javascript">
3581  *
3582  */
3583
3584 Roo.lib.AnimMgr = new function() {
3585
3586     var thread = null;
3587
3588
3589     var queue = [];
3590
3591
3592     var tweenCount = 0;
3593
3594
3595     this.fps = 1000;
3596
3597
3598     this.delay = 1;
3599
3600
3601     this.registerElement = function(tween) {
3602         queue[queue.length] = tween;
3603         tweenCount += 1;
3604         tween._onStart.fire();
3605         this.start();
3606     };
3607
3608
3609     this.unRegister = function(tween, index) {
3610         tween._onComplete.fire();
3611         index = index || getIndex(tween);
3612         if (index != -1) {
3613             queue.splice(index, 1);
3614         }
3615
3616         tweenCount -= 1;
3617         if (tweenCount <= 0) {
3618             this.stop();
3619         }
3620     };
3621
3622
3623     this.start = function() {
3624         if (thread === null) {
3625             thread = setInterval(this.run, this.delay);
3626         }
3627     };
3628
3629
3630     this.stop = function(tween) {
3631         if (!tween) {
3632             clearInterval(thread);
3633
3634             for (var i = 0, len = queue.length; i < len; ++i) {
3635                 if (queue[0].isAnimated()) {
3636                     this.unRegister(queue[0], 0);
3637                 }
3638             }
3639
3640             queue = [];
3641             thread = null;
3642             tweenCount = 0;
3643         }
3644         else {
3645             this.unRegister(tween);
3646         }
3647     };
3648
3649
3650     this.run = function() {
3651         for (var i = 0, len = queue.length; i < len; ++i) {
3652             var tween = queue[i];
3653             if (!tween || !tween.isAnimated()) {
3654                 continue;
3655             }
3656
3657             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3658             {
3659                 tween.currentFrame += 1;
3660
3661                 if (tween.useSeconds) {
3662                     correctFrame(tween);
3663                 }
3664                 tween._onTween.fire();
3665             }
3666             else {
3667                 Roo.lib.AnimMgr.stop(tween, i);
3668             }
3669         }
3670     };
3671
3672     var getIndex = function(anim) {
3673         for (var i = 0, len = queue.length; i < len; ++i) {
3674             if (queue[i] == anim) {
3675                 return i;
3676             }
3677         }
3678         return -1;
3679     };
3680
3681
3682     var correctFrame = function(tween) {
3683         var frames = tween.totalFrames;
3684         var frame = tween.currentFrame;
3685         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3686         var elapsed = (new Date() - tween.getStartTime());
3687         var tweak = 0;
3688
3689         if (elapsed < tween.duration * 1000) {
3690             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3691         } else {
3692             tweak = frames - (frame + 1);
3693         }
3694         if (tweak > 0 && isFinite(tweak)) {
3695             if (tween.currentFrame + tweak >= frames) {
3696                 tweak = frames - (frame + 1);
3697             }
3698
3699             tween.currentFrame += tweak;
3700         }
3701     };
3702 };
3703
3704     /*
3705  * Portions of this file are based on pieces of Yahoo User Interface Library
3706  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3707  * YUI licensed under the BSD License:
3708  * http://developer.yahoo.net/yui/license.txt
3709  * <script type="text/javascript">
3710  *
3711  */
3712 Roo.lib.Bezier = new function() {
3713
3714         this.getPosition = function(points, t) {
3715             var n = points.length;
3716             var tmp = [];
3717
3718             for (var i = 0; i < n; ++i) {
3719                 tmp[i] = [points[i][0], points[i][1]];
3720             }
3721
3722             for (var j = 1; j < n; ++j) {
3723                 for (i = 0; i < n - j; ++i) {
3724                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3725                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3726                 }
3727             }
3728
3729             return [ tmp[0][0], tmp[0][1] ];
3730
3731         };
3732     }; 
3733
3734 /**
3735  * @class Roo.lib.Color
3736  * @constructor
3737  * An abstract Color implementation. Concrete Color implementations should use
3738  * an instance of this function as their prototype, and implement the getRGB and
3739  * getHSL functions. getRGB should return an object representing the RGB
3740  * components of this Color, with the red, green, and blue components in the
3741  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3742  * return an object representing the HSL components of this Color, with the hue
3743  * component in the range [0,360), the saturation and lightness components in
3744  * the range [0,100], and the alpha component in the range [0,1].
3745  *
3746  *
3747  * Color.js
3748  *
3749  * Functions for Color handling and processing.
3750  *
3751  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3752  *
3753  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3754  * rights to this program, with the intention of it becoming part of the public
3755  * domain. Because this program is released into the public domain, it comes with
3756  * no warranty either expressed or implied, to the extent permitted by law.
3757  * 
3758  * For more free and public domain JavaScript code by the same author, visit:
3759  * http://www.safalra.com/web-design/javascript/
3760  * 
3761  */
3762 Roo.lib.Color = function() { }
3763
3764
3765 Roo.apply(Roo.lib.Color.prototype, {
3766   
3767   rgb : null,
3768   hsv : null,
3769   hsl : null,
3770   
3771   /**
3772    * getIntegerRGB
3773    * @return {Object} an object representing the RGBA components of this Color. The red,
3774    * green, and blue components are converted to integers in the range [0,255].
3775    * The alpha is a value in the range [0,1].
3776    */
3777   getIntegerRGB : function(){
3778
3779     // get the RGB components of this Color
3780     var rgb = this.getRGB();
3781
3782     // return the integer components
3783     return {
3784       'r' : Math.round(rgb.r),
3785       'g' : Math.round(rgb.g),
3786       'b' : Math.round(rgb.b),
3787       'a' : rgb.a
3788     };
3789
3790   },
3791
3792   /**
3793    * getPercentageRGB
3794    * @return {Object} an object representing the RGBA components of this Color. The red,
3795    * green, and blue components are converted to numbers in the range [0,100].
3796    * The alpha is a value in the range [0,1].
3797    */
3798   getPercentageRGB : function(){
3799
3800     // get the RGB components of this Color
3801     var rgb = this.getRGB();
3802
3803     // return the percentage components
3804     return {
3805       'r' : 100 * rgb.r / 255,
3806       'g' : 100 * rgb.g / 255,
3807       'b' : 100 * rgb.b / 255,
3808       'a' : rgb.a
3809     };
3810
3811   },
3812
3813   /**
3814    * getCSSHexadecimalRGB
3815    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3816    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3817    * are two-digit hexadecimal numbers.
3818    */
3819   getCSSHexadecimalRGB : function()
3820   {
3821
3822     // get the integer RGB components
3823     var rgb = this.getIntegerRGB();
3824
3825     // determine the hexadecimal equivalents
3826     var r16 = rgb.r.toString(16);
3827     var g16 = rgb.g.toString(16);
3828     var b16 = rgb.b.toString(16);
3829
3830     // return the CSS RGB Color value
3831     return '#'
3832         + (r16.length == 2 ? r16 : '0' + r16)
3833         + (g16.length == 2 ? g16 : '0' + g16)
3834         + (b16.length == 2 ? b16 : '0' + b16);
3835
3836   },
3837
3838   /**
3839    * getCSSIntegerRGB
3840    * @return {String} a string representing this Color as a CSS integer RGB Color
3841    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3842    * are integers in the range [0,255].
3843    */
3844   getCSSIntegerRGB : function(){
3845
3846     // get the integer RGB components
3847     var rgb = this.getIntegerRGB();
3848
3849     // return the CSS RGB Color value
3850     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3851
3852   },
3853
3854   /**
3855    * getCSSIntegerRGBA
3856    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3857    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3858    * b are integers in the range [0,255] and a is in the range [0,1].
3859    */
3860   getCSSIntegerRGBA : function(){
3861
3862     // get the integer RGB components
3863     var rgb = this.getIntegerRGB();
3864
3865     // return the CSS integer RGBA Color value
3866     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3867
3868   },
3869
3870   /**
3871    * getCSSPercentageRGB
3872    * @return {String} a string representing this Color as a CSS percentage RGB Color
3873    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3874    * b are in the range [0,100].
3875    */
3876   getCSSPercentageRGB : function(){
3877
3878     // get the percentage RGB components
3879     var rgb = this.getPercentageRGB();
3880
3881     // return the CSS RGB Color value
3882     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3883
3884   },
3885
3886   /**
3887    * getCSSPercentageRGBA
3888    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3889    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3890    * and b are in the range [0,100] and a is in the range [0,1].
3891    */
3892   getCSSPercentageRGBA : function(){
3893
3894     // get the percentage RGB components
3895     var rgb = this.getPercentageRGB();
3896
3897     // return the CSS percentage RGBA Color value
3898     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3899
3900   },
3901
3902   /**
3903    * getCSSHSL
3904    * @return {String} a string representing this Color as a CSS HSL Color value - that
3905    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3906    * s and l are in the range [0,100].
3907    */
3908   getCSSHSL : function(){
3909
3910     // get the HSL components
3911     var hsl = this.getHSL();
3912
3913     // return the CSS HSL Color value
3914     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3915
3916   },
3917
3918   /**
3919    * getCSSHSLA
3920    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3921    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3922    * s and l are in the range [0,100], and a is in the range [0,1].
3923    */
3924   getCSSHSLA : function(){
3925
3926     // get the HSL components
3927     var hsl = this.getHSL();
3928
3929     // return the CSS HSL Color value
3930     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3931
3932   },
3933
3934   /**
3935    * Sets the Color of the specified node to this Color. This functions sets
3936    * the CSS 'color' property for the node. The parameter is:
3937    * 
3938    * @param {DomElement} node - the node whose Color should be set
3939    */
3940   setNodeColor : function(node){
3941
3942     // set the Color of the node
3943     node.style.color = this.getCSSHexadecimalRGB();
3944
3945   },
3946
3947   /**
3948    * Sets the background Color of the specified node to this Color. This
3949    * functions sets the CSS 'background-color' property for the node. The
3950    * parameter is:
3951    *
3952    * @param {DomElement} node - the node whose background Color should be set
3953    */
3954   setNodeBackgroundColor : function(node){
3955
3956     // set the background Color of the node
3957     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3958
3959   },
3960   // convert between formats..
3961   toRGB: function()
3962   {
3963     var r = this.getIntegerRGB();
3964     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3965     
3966   },
3967   toHSL : function()
3968   {
3969      var hsl = this.getHSL();
3970   // return the CSS HSL Color value
3971     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3972     
3973   },
3974   
3975   toHSV : function()
3976   {
3977     var rgb = this.toRGB();
3978     var hsv = rgb.getHSV();
3979    // return the CSS HSL Color value
3980     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3981     
3982   },
3983   
3984   // modify  v = 0 ... 1 (eg. 0.5)
3985   saturate : function(v)
3986   {
3987       var rgb = this.toRGB();
3988       var hsv = rgb.getHSV();
3989       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3990       
3991   
3992   },
3993   
3994    
3995   /**
3996    * getRGB
3997    * @return {Object} the RGB and alpha components of this Color as an object with r,
3998    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3999    * the range [0,1].
4000    */
4001   getRGB: function(){
4002    
4003     // return the RGB components
4004     return {
4005       'r' : this.rgb.r,
4006       'g' : this.rgb.g,
4007       'b' : this.rgb.b,
4008       'a' : this.alpha
4009     };
4010
4011   },
4012
4013   /**
4014    * getHSV
4015    * @return {Object} the HSV and alpha components of this Color as an object with h,
4016    * s, v, and a properties. h is in the range [0,360), s and v are in the range
4017    * [0,100], and a is in the range [0,1].
4018    */
4019   getHSV : function()
4020   {
4021     
4022     // calculate the HSV components if necessary
4023     if (this.hsv == null) {
4024       this.calculateHSV();
4025     }
4026
4027     // return the HSV components
4028     return {
4029       'h' : this.hsv.h,
4030       's' : this.hsv.s,
4031       'v' : this.hsv.v,
4032       'a' : this.alpha
4033     };
4034
4035   },
4036
4037   /**
4038    * getHSL
4039    * @return {Object} the HSL and alpha components of this Color as an object with h,
4040    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4041    * [0,100], and a is in the range [0,1].
4042    */
4043   getHSL : function(){
4044     
4045      
4046     // calculate the HSV components if necessary
4047     if (this.hsl == null) { this.calculateHSL(); }
4048
4049     // return the HSL components
4050     return {
4051       'h' : this.hsl.h,
4052       's' : this.hsl.s,
4053       'l' : this.hsl.l,
4054       'a' : this.alpha
4055     };
4056
4057   }
4058   
4059
4060 });
4061
4062
4063 /**
4064  * @class Roo.lib.RGBColor
4065  * @extends Roo.lib.Color
4066  * Creates a Color specified in the RGB Color space, with an optional alpha
4067  * component. The parameters are:
4068  * @constructor
4069  * 
4070
4071  * @param {Number} r - the red component, clipped to the range [0,255]
4072  * @param {Number} g - the green component, clipped to the range [0,255]
4073  * @param {Number} b - the blue component, clipped to the range [0,255]
4074  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4075  *     optional and defaults to 1
4076  */
4077 Roo.lib.RGBColor = function (r, g, b, a){
4078
4079   // store the alpha component after clipping it if necessary
4080   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4081
4082   // store the RGB components after clipping them if necessary
4083   this.rgb =
4084       {
4085         'r' : Math.max(0, Math.min(255, r)),
4086         'g' : Math.max(0, Math.min(255, g)),
4087         'b' : Math.max(0, Math.min(255, b))
4088       };
4089
4090   // initialise the HSV and HSL components to null
4091   
4092
4093   /* 
4094    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4095    * range [0,360). The parameters are:
4096    *
4097    * maximum - the maximum of the RGB component values
4098    * range   - the range of the RGB component values
4099    */
4100    
4101
4102 }
4103 // this does an 'exteds'
4104 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4105
4106   
4107     getHue  : function(maximum, range)
4108     {
4109       var rgb = this.rgb;
4110        
4111       // check whether the range is zero
4112       if (range == 0){
4113   
4114         // set the hue to zero (any hue is acceptable as the Color is grey)
4115         var hue = 0;
4116   
4117       }else{
4118   
4119         // determine which of the components has the highest value and set the hue
4120         switch (maximum){
4121   
4122           // red has the highest value
4123           case rgb.r:
4124             var hue = (rgb.g - rgb.b) / range * 60;
4125             if (hue < 0) { hue += 360; }
4126             break;
4127   
4128           // green has the highest value
4129           case rgb.g:
4130             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4131             break;
4132   
4133           // blue has the highest value
4134           case rgb.b:
4135             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4136             break;
4137   
4138         }
4139   
4140       }
4141   
4142       // return the hue
4143       return hue;
4144   
4145     },
4146
4147   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4148    * be returned be the getHSV function.
4149    */
4150    calculateHSV : function(){
4151     var rgb = this.rgb;
4152     // get the maximum and range of the RGB component values
4153     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4154     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4155
4156     // store the HSV components
4157     this.hsv =
4158         {
4159           'h' : this.getHue(maximum, range),
4160           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4161           'v' : maximum / 2.55
4162         };
4163
4164   },
4165
4166   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4167    * be returned be the getHSL function.
4168    */
4169    calculateHSL : function(){
4170     var rgb = this.rgb;
4171     // get the maximum and range of the RGB component values
4172     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4173     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4174
4175     // determine the lightness in the range [0,1]
4176     var l = maximum / 255 - range / 510;
4177
4178     // store the HSL components
4179     this.hsl =
4180         {
4181           'h' : this.getHue(maximum, range),
4182           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4183           'l' : 100 * l
4184         };
4185
4186   }
4187
4188 });
4189
4190 /**
4191  * @class Roo.lib.HSVColor
4192  * @extends Roo.lib.Color
4193  * Creates a Color specified in the HSV Color space, with an optional alpha
4194  * component. The parameters are:
4195  * @constructor
4196  *
4197  * @param {Number} h - the hue component, wrapped to the range [0,360)
4198  * @param {Number} s - the saturation component, clipped to the range [0,100]
4199  * @param {Number} v - the value component, clipped to the range [0,100]
4200  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4201  *     optional and defaults to 1
4202  */
4203 Roo.lib.HSVColor = function (h, s, v, a){
4204
4205   // store the alpha component after clipping it if necessary
4206   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4207
4208   // store the HSV components after clipping or wrapping them if necessary
4209   this.hsv =
4210       {
4211         'h' : (h % 360 + 360) % 360,
4212         's' : Math.max(0, Math.min(100, s)),
4213         'v' : Math.max(0, Math.min(100, v))
4214       };
4215
4216   // initialise the RGB and HSL components to null
4217   this.rgb = null;
4218   this.hsl = null;
4219 }
4220
4221 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4222   /* Calculates and stores the RGB components of this HSVColor so that they can
4223    * be returned be the getRGB function.
4224    */
4225   calculateRGB: function ()
4226   {
4227     var hsv = this.hsv;
4228     // check whether the saturation is zero
4229     if (hsv.s == 0){
4230
4231       // set the Color to the appropriate shade of grey
4232       var r = hsv.v;
4233       var g = hsv.v;
4234       var b = hsv.v;
4235
4236     }else{
4237
4238       // set some temporary values
4239       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4240       var p  = hsv.v * (1 - hsv.s / 100);
4241       var q  = hsv.v * (1 - hsv.s / 100 * f);
4242       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4243
4244       // set the RGB Color components to their temporary values
4245       switch (Math.floor(hsv.h / 60)){
4246         case 0: var r = hsv.v; var g = t; var b = p; break;
4247         case 1: var r = q; var g = hsv.v; var b = p; break;
4248         case 2: var r = p; var g = hsv.v; var b = t; break;
4249         case 3: var r = p; var g = q; var b = hsv.v; break;
4250         case 4: var r = t; var g = p; var b = hsv.v; break;
4251         case 5: var r = hsv.v; var g = p; var b = q; break;
4252       }
4253
4254     }
4255
4256     // store the RGB components
4257     this.rgb =
4258         {
4259           'r' : r * 2.55,
4260           'g' : g * 2.55,
4261           'b' : b * 2.55
4262         };
4263
4264   },
4265
4266   /* Calculates and stores the HSL components of this HSVColor so that they can
4267    * be returned be the getHSL function.
4268    */
4269   calculateHSL : function (){
4270
4271     var hsv = this.hsv;
4272     // determine the lightness in the range [0,100]
4273     var l = (2 - hsv.s / 100) * hsv.v / 2;
4274
4275     // store the HSL components
4276     this.hsl =
4277         {
4278           'h' : hsv.h,
4279           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4280           'l' : l
4281         };
4282
4283     // correct a division-by-zero error
4284     if (isNaN(hsl.s)) { hsl.s = 0; }
4285
4286   } 
4287  
4288
4289 });
4290  
4291
4292 /**
4293  * @class Roo.lib.HSLColor
4294  * @extends Roo.lib.Color
4295  *
4296  * @constructor
4297  * Creates a Color specified in the HSL Color space, with an optional alpha
4298  * component. The parameters are:
4299  *
4300  * @param {Number} h - the hue component, wrapped to the range [0,360)
4301  * @param {Number} s - the saturation component, clipped to the range [0,100]
4302  * @param {Number} l - the lightness component, clipped to the range [0,100]
4303  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4304  *     optional and defaults to 1
4305  */
4306
4307 Roo.lib.HSLColor = function(h, s, l, a){
4308
4309   // store the alpha component after clipping it if necessary
4310   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4311
4312   // store the HSL components after clipping or wrapping them if necessary
4313   this.hsl =
4314       {
4315         'h' : (h % 360 + 360) % 360,
4316         's' : Math.max(0, Math.min(100, s)),
4317         'l' : Math.max(0, Math.min(100, l))
4318       };
4319
4320   // initialise the RGB and HSV components to null
4321 }
4322
4323 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4324
4325   /* Calculates and stores the RGB components of this HSLColor so that they can
4326    * be returned be the getRGB function.
4327    */
4328   calculateRGB: function (){
4329
4330     // check whether the saturation is zero
4331     if (this.hsl.s == 0){
4332
4333       // store the RGB components representing the appropriate shade of grey
4334       this.rgb =
4335           {
4336             'r' : this.hsl.l * 2.55,
4337             'g' : this.hsl.l * 2.55,
4338             'b' : this.hsl.l * 2.55
4339           };
4340
4341     }else{
4342
4343       // set some temporary values
4344       var p = this.hsl.l < 50
4345             ? this.hsl.l * (1 + hsl.s / 100)
4346             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4347       var q = 2 * hsl.l - p;
4348
4349       // initialise the RGB components
4350       this.rgb =
4351           {
4352             'r' : (h + 120) / 60 % 6,
4353             'g' : h / 60,
4354             'b' : (h + 240) / 60 % 6
4355           };
4356
4357       // loop over the RGB components
4358       for (var key in this.rgb){
4359
4360         // ensure that the property is not inherited from the root object
4361         if (this.rgb.hasOwnProperty(key)){
4362
4363           // set the component to its value in the range [0,100]
4364           if (this.rgb[key] < 1){
4365             this.rgb[key] = q + (p - q) * this.rgb[key];
4366           }else if (this.rgb[key] < 3){
4367             this.rgb[key] = p;
4368           }else if (this.rgb[key] < 4){
4369             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4370           }else{
4371             this.rgb[key] = q;
4372           }
4373
4374           // set the component to its value in the range [0,255]
4375           this.rgb[key] *= 2.55;
4376
4377         }
4378
4379       }
4380
4381     }
4382
4383   },
4384
4385   /* Calculates and stores the HSV components of this HSLColor so that they can
4386    * be returned be the getHSL function.
4387    */
4388    calculateHSV : function(){
4389
4390     // set a temporary value
4391     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4392
4393     // store the HSV components
4394     this.hsv =
4395         {
4396           'h' : this.hsl.h,
4397           's' : 200 * t / (this.hsl.l + t),
4398           'v' : t + this.hsl.l
4399         };
4400
4401     // correct a division-by-zero error
4402     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4403
4404   }
4405  
4406
4407 });
4408 /*
4409  * Portions of this file are based on pieces of Yahoo User Interface Library
4410  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4411  * YUI licensed under the BSD License:
4412  * http://developer.yahoo.net/yui/license.txt
4413  * <script type="text/javascript">
4414  *
4415  */
4416 (function() {
4417
4418     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4419         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4420     };
4421
4422     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4423
4424     var fly = Roo.lib.AnimBase.fly;
4425     var Y = Roo.lib;
4426     var superclass = Y.ColorAnim.superclass;
4427     var proto = Y.ColorAnim.prototype;
4428
4429     proto.toString = function() {
4430         var el = this.getEl();
4431         var id = el.id || el.tagName;
4432         return ("ColorAnim " + id);
4433     };
4434
4435     proto.patterns.color = /color$/i;
4436     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4437     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4438     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4439     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4440
4441
4442     proto.parseColor = function(s) {
4443         if (s.length == 3) {
4444             return s;
4445         }
4446
4447         var c = this.patterns.hex.exec(s);
4448         if (c && c.length == 4) {
4449             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4450         }
4451
4452         c = this.patterns.rgb.exec(s);
4453         if (c && c.length == 4) {
4454             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4455         }
4456
4457         c = this.patterns.hex3.exec(s);
4458         if (c && c.length == 4) {
4459             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4460         }
4461
4462         return null;
4463     };
4464     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4465     proto.getAttribute = function(attr) {
4466         var el = this.getEl();
4467         if (this.patterns.color.test(attr)) {
4468             var val = fly(el).getStyle(attr);
4469
4470             if (this.patterns.transparent.test(val)) {
4471                 var parent = el.parentNode;
4472                 val = fly(parent).getStyle(attr);
4473
4474                 while (parent && this.patterns.transparent.test(val)) {
4475                     parent = parent.parentNode;
4476                     val = fly(parent).getStyle(attr);
4477                     if (parent.tagName.toUpperCase() == 'HTML') {
4478                         val = '#fff';
4479                     }
4480                 }
4481             }
4482         } else {
4483             val = superclass.getAttribute.call(this, attr);
4484         }
4485
4486         return val;
4487     };
4488     proto.getAttribute = function(attr) {
4489         var el = this.getEl();
4490         if (this.patterns.color.test(attr)) {
4491             var val = fly(el).getStyle(attr);
4492
4493             if (this.patterns.transparent.test(val)) {
4494                 var parent = el.parentNode;
4495                 val = fly(parent).getStyle(attr);
4496
4497                 while (parent && this.patterns.transparent.test(val)) {
4498                     parent = parent.parentNode;
4499                     val = fly(parent).getStyle(attr);
4500                     if (parent.tagName.toUpperCase() == 'HTML') {
4501                         val = '#fff';
4502                     }
4503                 }
4504             }
4505         } else {
4506             val = superclass.getAttribute.call(this, attr);
4507         }
4508
4509         return val;
4510     };
4511
4512     proto.doMethod = function(attr, start, end) {
4513         var val;
4514
4515         if (this.patterns.color.test(attr)) {
4516             val = [];
4517             for (var i = 0, len = start.length; i < len; ++i) {
4518                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4519             }
4520
4521             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4522         }
4523         else {
4524             val = superclass.doMethod.call(this, attr, start, end);
4525         }
4526
4527         return val;
4528     };
4529
4530     proto.setRuntimeAttribute = function(attr) {
4531         superclass.setRuntimeAttribute.call(this, attr);
4532
4533         if (this.patterns.color.test(attr)) {
4534             var attributes = this.attributes;
4535             var start = this.parseColor(this.runtimeAttributes[attr].start);
4536             var end = this.parseColor(this.runtimeAttributes[attr].end);
4537
4538             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4539                 end = this.parseColor(attributes[attr].by);
4540
4541                 for (var i = 0, len = start.length; i < len; ++i) {
4542                     end[i] = start[i] + end[i];
4543                 }
4544             }
4545
4546             this.runtimeAttributes[attr].start = start;
4547             this.runtimeAttributes[attr].end = end;
4548         }
4549     };
4550 })();
4551
4552 /*
4553  * Portions of this file are based on pieces of Yahoo User Interface Library
4554  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4555  * YUI licensed under the BSD License:
4556  * http://developer.yahoo.net/yui/license.txt
4557  * <script type="text/javascript">
4558  *
4559  */
4560 Roo.lib.Easing = {
4561
4562
4563     easeNone: function (t, b, c, d) {
4564         return c * t / d + b;
4565     },
4566
4567
4568     easeIn: function (t, b, c, d) {
4569         return c * (t /= d) * t + b;
4570     },
4571
4572
4573     easeOut: function (t, b, c, d) {
4574         return -c * (t /= d) * (t - 2) + b;
4575     },
4576
4577
4578     easeBoth: function (t, b, c, d) {
4579         if ((t /= d / 2) < 1) {
4580             return c / 2 * t * t + b;
4581         }
4582
4583         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4584     },
4585
4586
4587     easeInStrong: function (t, b, c, d) {
4588         return c * (t /= d) * t * t * t + b;
4589     },
4590
4591
4592     easeOutStrong: function (t, b, c, d) {
4593         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4594     },
4595
4596
4597     easeBothStrong: function (t, b, c, d) {
4598         if ((t /= d / 2) < 1) {
4599             return c / 2 * t * t * t * t + b;
4600         }
4601
4602         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4603     },
4604
4605
4606
4607     elasticIn: function (t, b, c, d, a, p) {
4608         if (t == 0) {
4609             return b;
4610         }
4611         if ((t /= d) == 1) {
4612             return b + c;
4613         }
4614         if (!p) {
4615             p = d * .3;
4616         }
4617
4618         if (!a || a < Math.abs(c)) {
4619             a = c;
4620             var s = p / 4;
4621         }
4622         else {
4623             var s = p / (2 * Math.PI) * Math.asin(c / a);
4624         }
4625
4626         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4627     },
4628
4629
4630     elasticOut: function (t, b, c, d, a, p) {
4631         if (t == 0) {
4632             return b;
4633         }
4634         if ((t /= d) == 1) {
4635             return b + c;
4636         }
4637         if (!p) {
4638             p = d * .3;
4639         }
4640
4641         if (!a || a < Math.abs(c)) {
4642             a = c;
4643             var s = p / 4;
4644         }
4645         else {
4646             var s = p / (2 * Math.PI) * Math.asin(c / a);
4647         }
4648
4649         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4650     },
4651
4652
4653     elasticBoth: function (t, b, c, d, a, p) {
4654         if (t == 0) {
4655             return b;
4656         }
4657
4658         if ((t /= d / 2) == 2) {
4659             return b + c;
4660         }
4661
4662         if (!p) {
4663             p = d * (.3 * 1.5);
4664         }
4665
4666         if (!a || a < Math.abs(c)) {
4667             a = c;
4668             var s = p / 4;
4669         }
4670         else {
4671             var s = p / (2 * Math.PI) * Math.asin(c / a);
4672         }
4673
4674         if (t < 1) {
4675             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4676                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4677         }
4678         return a * Math.pow(2, -10 * (t -= 1)) *
4679                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4680     },
4681
4682
4683
4684     backIn: function (t, b, c, d, s) {
4685         if (typeof s == 'undefined') {
4686             s = 1.70158;
4687         }
4688         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4689     },
4690
4691
4692     backOut: function (t, b, c, d, s) {
4693         if (typeof s == 'undefined') {
4694             s = 1.70158;
4695         }
4696         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4697     },
4698
4699
4700     backBoth: function (t, b, c, d, s) {
4701         if (typeof s == 'undefined') {
4702             s = 1.70158;
4703         }
4704
4705         if ((t /= d / 2 ) < 1) {
4706             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4707         }
4708         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4709     },
4710
4711
4712     bounceIn: function (t, b, c, d) {
4713         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4714     },
4715
4716
4717     bounceOut: function (t, b, c, d) {
4718         if ((t /= d) < (1 / 2.75)) {
4719             return c * (7.5625 * t * t) + b;
4720         } else if (t < (2 / 2.75)) {
4721             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4722         } else if (t < (2.5 / 2.75)) {
4723             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4724         }
4725         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4726     },
4727
4728
4729     bounceBoth: function (t, b, c, d) {
4730         if (t < d / 2) {
4731             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4732         }
4733         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4734     }
4735 };/*
4736  * Portions of this file are based on pieces of Yahoo User Interface Library
4737  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4738  * YUI licensed under the BSD License:
4739  * http://developer.yahoo.net/yui/license.txt
4740  * <script type="text/javascript">
4741  *
4742  */
4743     (function() {
4744         Roo.lib.Motion = function(el, attributes, duration, method) {
4745             if (el) {
4746                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4747             }
4748         };
4749
4750         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4751
4752
4753         var Y = Roo.lib;
4754         var superclass = Y.Motion.superclass;
4755         var proto = Y.Motion.prototype;
4756
4757         proto.toString = function() {
4758             var el = this.getEl();
4759             var id = el.id || el.tagName;
4760             return ("Motion " + id);
4761         };
4762
4763         proto.patterns.points = /^points$/i;
4764
4765         proto.setAttribute = function(attr, val, unit) {
4766             if (this.patterns.points.test(attr)) {
4767                 unit = unit || 'px';
4768                 superclass.setAttribute.call(this, 'left', val[0], unit);
4769                 superclass.setAttribute.call(this, 'top', val[1], unit);
4770             } else {
4771                 superclass.setAttribute.call(this, attr, val, unit);
4772             }
4773         };
4774
4775         proto.getAttribute = function(attr) {
4776             if (this.patterns.points.test(attr)) {
4777                 var val = [
4778                         superclass.getAttribute.call(this, 'left'),
4779                         superclass.getAttribute.call(this, 'top')
4780                         ];
4781             } else {
4782                 val = superclass.getAttribute.call(this, attr);
4783             }
4784
4785             return val;
4786         };
4787
4788         proto.doMethod = function(attr, start, end) {
4789             var val = null;
4790
4791             if (this.patterns.points.test(attr)) {
4792                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4793                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4794             } else {
4795                 val = superclass.doMethod.call(this, attr, start, end);
4796             }
4797             return val;
4798         };
4799
4800         proto.setRuntimeAttribute = function(attr) {
4801             if (this.patterns.points.test(attr)) {
4802                 var el = this.getEl();
4803                 var attributes = this.attributes;
4804                 var start;
4805                 var control = attributes['points']['control'] || [];
4806                 var end;
4807                 var i, len;
4808
4809                 if (control.length > 0 && !(control[0] instanceof Array)) {
4810                     control = [control];
4811                 } else {
4812                     var tmp = [];
4813                     for (i = 0,len = control.length; i < len; ++i) {
4814                         tmp[i] = control[i];
4815                     }
4816                     control = tmp;
4817                 }
4818
4819                 Roo.fly(el).position();
4820
4821                 if (isset(attributes['points']['from'])) {
4822                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4823                 }
4824                 else {
4825                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4826                 }
4827
4828                 start = this.getAttribute('points');
4829
4830
4831                 if (isset(attributes['points']['to'])) {
4832                     end = translateValues.call(this, attributes['points']['to'], start);
4833
4834                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4835                     for (i = 0,len = control.length; i < len; ++i) {
4836                         control[i] = translateValues.call(this, control[i], start);
4837                     }
4838
4839
4840                 } else if (isset(attributes['points']['by'])) {
4841                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4842
4843                     for (i = 0,len = control.length; i < len; ++i) {
4844                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4845                     }
4846                 }
4847
4848                 this.runtimeAttributes[attr] = [start];
4849
4850                 if (control.length > 0) {
4851                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4852                 }
4853
4854                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4855             }
4856             else {
4857                 superclass.setRuntimeAttribute.call(this, attr);
4858             }
4859         };
4860
4861         var translateValues = function(val, start) {
4862             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4863             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4864
4865             return val;
4866         };
4867
4868         var isset = function(prop) {
4869             return (typeof prop !== 'undefined');
4870         };
4871     })();
4872 /*
4873  * Portions of this file are based on pieces of Yahoo User Interface Library
4874  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4875  * YUI licensed under the BSD License:
4876  * http://developer.yahoo.net/yui/license.txt
4877  * <script type="text/javascript">
4878  *
4879  */
4880     (function() {
4881         Roo.lib.Scroll = function(el, attributes, duration, method) {
4882             if (el) {
4883                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4884             }
4885         };
4886
4887         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4888
4889
4890         var Y = Roo.lib;
4891         var superclass = Y.Scroll.superclass;
4892         var proto = Y.Scroll.prototype;
4893
4894         proto.toString = function() {
4895             var el = this.getEl();
4896             var id = el.id || el.tagName;
4897             return ("Scroll " + id);
4898         };
4899
4900         proto.doMethod = function(attr, start, end) {
4901             var val = null;
4902
4903             if (attr == 'scroll') {
4904                 val = [
4905                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4906                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4907                         ];
4908
4909             } else {
4910                 val = superclass.doMethod.call(this, attr, start, end);
4911             }
4912             return val;
4913         };
4914
4915         proto.getAttribute = function(attr) {
4916             var val = null;
4917             var el = this.getEl();
4918
4919             if (attr == 'scroll') {
4920                 val = [ el.scrollLeft, el.scrollTop ];
4921             } else {
4922                 val = superclass.getAttribute.call(this, attr);
4923             }
4924
4925             return val;
4926         };
4927
4928         proto.setAttribute = function(attr, val, unit) {
4929             var el = this.getEl();
4930
4931             if (attr == 'scroll') {
4932                 el.scrollLeft = val[0];
4933                 el.scrollTop = val[1];
4934             } else {
4935                 superclass.setAttribute.call(this, attr, val, unit);
4936             }
4937         };
4938     })();
4939 /**
4940  * Originally based of this code... - refactored for Roo...
4941  * https://github.com/aaalsaleh/undo-manager
4942  
4943  * undo-manager.js
4944  * @author  Abdulrahman Alsaleh 
4945  * @copyright 2015 Abdulrahman Alsaleh 
4946  * @license  MIT License (c) 
4947  *
4948  * Hackily modifyed by alan@roojs.com
4949  *
4950  *
4951  *  
4952  *
4953  *  TOTALLY UNTESTED...
4954  *
4955  *  Documentation to be done....
4956  */
4957  
4958
4959 /**
4960 * @class Roo.lib.UndoManager
4961 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4962 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4963
4964  * Usage:
4965  * <pre><code>
4966
4967
4968 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4969  
4970 </code></pre>
4971
4972 * For more information see this blog post with examples:
4973 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4974      - Create Elements using DOM, HTML fragments and Templates</a>. 
4975 * @constructor
4976 * @param {Number} limit how far back to go ... use 1000?
4977 * @param {Object} scope usually use document..
4978 */
4979
4980 Roo.lib.UndoManager = function (limit, undoScopeHost)
4981 {
4982     this.stack = [];
4983     this.limit = limit;
4984     this.scope = undoScopeHost;
4985     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4986     if (this.fireEvent) {
4987         this.bindEvents();
4988     }
4989     this.reset();
4990     
4991 };
4992         
4993 Roo.lib.UndoManager.prototype = {
4994     
4995     limit : false,
4996     stack : false,
4997     scope :  false,
4998     fireEvent : false,
4999     position : 0,
5000     length : 0,
5001     
5002     
5003      /**
5004      * To push and execute a transaction, the method undoManager.transact
5005      * must be called by passing a transaction object as the first argument, and a merge
5006      * flag as the second argument. A transaction object has the following properties:
5007      *
5008      * Usage:
5009 <pre><code>
5010 undoManager.transact({
5011     label: 'Typing',
5012     execute: function() { ... },
5013     undo: function() { ... },
5014     // redo same as execute
5015     redo: function() { this.execute(); }
5016 }, false);
5017
5018 // merge transaction
5019 undoManager.transact({
5020     label: 'Typing',
5021     execute: function() { ... },  // this will be run...
5022     undo: function() { ... }, // what to do when undo is run.
5023     // redo same as execute
5024     redo: function() { this.execute(); }
5025 }, true); 
5026 </code></pre> 
5027      *
5028      * 
5029      * @param {Object} transaction The transaction to add to the stack.
5030      * @return {String} The HTML fragment
5031      */
5032     
5033     
5034     transact : function (transaction, merge)
5035     {
5036         if (arguments.length < 2) {
5037             throw new TypeError('Not enough arguments to UndoManager.transact.');
5038         }
5039
5040         transaction.execute();
5041
5042         this.stack.splice(0, this.position);
5043         if (merge && this.length) {
5044             this.stack[0].push(transaction);
5045         } else {
5046             this.stack.unshift([transaction]);
5047         }
5048     
5049         this.position = 0;
5050
5051         if (this.limit && this.stack.length > this.limit) {
5052             this.length = this.stack.length = this.limit;
5053         } else {
5054             this.length = this.stack.length;
5055         }
5056
5057         if (this.fireEvent) {
5058             this.scope.dispatchEvent(
5059                 new CustomEvent('DOMTransaction', {
5060                     detail: {
5061                         transactions: this.stack[0].slice()
5062                     },
5063                     bubbles: true,
5064                     cancelable: false
5065                 })
5066             );
5067         }
5068         
5069         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5070       
5071         
5072     },
5073
5074     undo : function ()
5075     {
5076         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5077         
5078         if (this.position < this.length) {
5079             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5080                 this.stack[this.position][i].undo();
5081             }
5082             this.position++;
5083
5084             if (this.fireEvent) {
5085                 this.scope.dispatchEvent(
5086                     new CustomEvent('undo', {
5087                         detail: {
5088                             transactions: this.stack[this.position - 1].slice()
5089                         },
5090                         bubbles: true,
5091                         cancelable: false
5092                     })
5093                 );
5094             }
5095         }
5096     },
5097
5098     redo : function ()
5099     {
5100         if (this.position > 0) {
5101             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5102                 this.stack[this.position - 1][i].redo();
5103             }
5104             this.position--;
5105
5106             if (this.fireEvent) {
5107                 this.scope.dispatchEvent(
5108                     new CustomEvent('redo', {
5109                         detail: {
5110                             transactions: this.stack[this.position].slice()
5111                         },
5112                         bubbles: true,
5113                         cancelable: false
5114                     })
5115                 );
5116             }
5117         }
5118     },
5119
5120     item : function (index)
5121     {
5122         if (index >= 0 && index < this.length) {
5123             return this.stack[index].slice();
5124         }
5125         return null;
5126     },
5127
5128     clearUndo : function () {
5129         this.stack.length = this.length = this.position;
5130     },
5131
5132     clearRedo : function () {
5133         this.stack.splice(0, this.position);
5134         this.position = 0;
5135         this.length = this.stack.length;
5136     },
5137     /**
5138      * Reset the undo - probaly done on load to clear all history.
5139      */
5140     reset : function()
5141     {
5142         this.stack = [];
5143         this.position = 0;
5144         this.length = 0;
5145         this.current_html = this.scope.innerHTML;
5146         if (this.timer !== false) {
5147             clearTimeout(this.timer);
5148         }
5149         this.timer = false;
5150         this.merge = false;
5151         this.addEvent();
5152         
5153     },
5154     current_html : '',
5155     timer : false,
5156     merge : false,
5157     
5158     
5159     // this will handle the undo/redo on the element.?
5160     bindEvents : function()
5161     {
5162         var el  = this.scope;
5163         el.undoManager = this;
5164         
5165         
5166         this.scope.addEventListener('keydown', function(e) {
5167             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5168                 if (e.shiftKey) {
5169                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5170                 } else {
5171                     el.undoManager.undo(); // Ctrl/Command + Z
5172                 }
5173         
5174                 e.preventDefault();
5175             }
5176         });
5177         /// ignore keyup..
5178         this.scope.addEventListener('keyup', function(e) {
5179             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5180                 e.preventDefault();
5181             }
5182         });
5183         
5184         
5185         
5186         var t = this;
5187         
5188         el.addEventListener('input', function(e) {
5189             if(el.innerHTML == t.current_html) {
5190                 return;
5191             }
5192             // only record events every second.
5193             if (t.timer !== false) {
5194                clearTimeout(t.timer);
5195                t.timer = false;
5196             }
5197             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5198             
5199             t.addEvent(t.merge);
5200             t.merge = true; // ignore changes happening every second..
5201         });
5202         },
5203     /**
5204      * Manually add an event.
5205      * Normall called without arguements - and it will just get added to the stack.
5206      * 
5207      */
5208     
5209     addEvent : function(merge)
5210     {
5211         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5212         // not sure if this should clear the timer 
5213         merge = typeof(merge) == 'undefined' ? false : merge; 
5214         
5215         this.scope.undoManager.transact({
5216             scope : this.scope,
5217             oldHTML: this.current_html,
5218             newHTML: this.scope.innerHTML,
5219             // nothing to execute (content already changed when input is fired)
5220             execute: function() { },
5221             undo: function() {
5222                 this.scope.innerHTML = this.current_html = this.oldHTML;
5223             },
5224             redo: function() {
5225                 this.scope.innerHTML = this.current_html = this.newHTML;
5226             }
5227         }, false); //merge);
5228         
5229         this.merge = merge;
5230         
5231         this.current_html = this.scope.innerHTML;
5232     }
5233     
5234     
5235      
5236     
5237     
5238     
5239 };
5240 /**
5241  * @class Roo.lib.Range
5242  * @constructor
5243  * This is a toolkit, normally used to copy features into a Dom Range element
5244  * Roo.lib.Range.wrap(x);
5245  *
5246  *
5247  *
5248  */
5249 Roo.lib.Range = function() { };
5250
5251 /**
5252  * Wrap a Dom Range object, to give it new features...
5253  * @static
5254  * @param {Range} the range to wrap
5255  */
5256 Roo.lib.Range.wrap = function(r) {
5257     return Roo.apply(r, Roo.lib.Range.prototype);
5258 };
5259 /**
5260  * find a parent node eg. LI / OL
5261  * @param {string|Array} node name or array of nodenames
5262  * @return {DomElement|false}
5263  */
5264 Roo.apply(Roo.lib.Range.prototype,
5265 {
5266     
5267     closest : function(str)
5268     {
5269         if (typeof(str) != 'string') {
5270             // assume it's a array.
5271             for(var i = 0;i < str.length;i++) {
5272                 var r = this.closest(str[i]);
5273                 if (r !== false) {
5274                     return r;
5275                 }
5276                 
5277             }
5278             return false;
5279         }
5280         str = str.toLowerCase();
5281         var n = this.commonAncestorContainer; // might not be a node
5282         while (n.nodeType != 1) {
5283             n = n.parentNode;
5284         }
5285         
5286         if (n.nodeName.toLowerCase() == str ) {
5287             return n;
5288         }
5289         if (n.nodeName.toLowerCase() == 'body') {
5290             return false;
5291         }
5292             
5293         return n.closest(str) || false;
5294         
5295     },
5296     cloneRange : function()
5297     {
5298         return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5299     }
5300 });/**
5301  * @class Roo.lib.Selection
5302  * @constructor
5303  * This is a toolkit, normally used to copy features into a Dom Selection element
5304  * Roo.lib.Selection.wrap(x);
5305  *
5306  *
5307  *
5308  */
5309 Roo.lib.Selection = function() { };
5310
5311 /**
5312  * Wrap a Dom Range object, to give it new features...
5313  * @static
5314  * @param {Range} the range to wrap
5315  */
5316 Roo.lib.Selection.wrap = function(r, doc) {
5317     Roo.apply(r, Roo.lib.Selection.prototype);
5318     r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5319     return r;
5320 };
5321 /**
5322  * find a parent node eg. LI / OL
5323  * @param {string|Array} node name or array of nodenames
5324  * @return {DomElement|false}
5325  */
5326 Roo.apply(Roo.lib.Selection.prototype,
5327 {
5328     /**
5329      * the owner document
5330      */
5331     ownerDocument : false,
5332     
5333     getRangeAt : function(n)
5334     {
5335         return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5336     },
5337     
5338     /**
5339      * insert node at selection 
5340      * @param {DomElement|string} node
5341      * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5342      */
5343     insertNode: function(node, cursor)
5344     {
5345         if (typeof(node) == 'string') {
5346             node = this.ownerDocument.createElement(node);
5347             if (cursor == 'in') {
5348                 node.innerHTML = '&nbsp;';
5349             }
5350         }
5351         
5352         var range = this.getRangeAt(0);
5353         
5354         if (this.type != 'Caret') {
5355             range.deleteContents();
5356         }
5357         var sn = node.childNodes[0]; // select the contents.
5358
5359         
5360         
5361         range.insertNode(node);
5362         if (cursor == 'after') {
5363             node.insertAdjacentHTML('afterend', '&nbsp;');
5364             sn = node.nextSibling;
5365         }
5366         
5367         if (cursor == 'none') {
5368             return;
5369         }
5370         
5371         this.cursorText(sn);
5372     },
5373     
5374     cursorText : function(n)
5375     {
5376        
5377         //var range = this.getRangeAt(0);
5378         range = Roo.lib.Range.wrap(new Range());
5379         //range.selectNode(n);
5380         
5381         var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5382         range.setStart(n.parentNode,ix);
5383         range.setEnd(n.parentNode,ix+1);
5384         //range.collapse(false);
5385          
5386         this.removeAllRanges();
5387         this.addRange(range);
5388         
5389         Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5390     },
5391     cursorAfter : function(n)
5392     {
5393         if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
5394             n.insertAdjacentHTML('afterend', '&nbsp;');
5395         }
5396         this.cursorText (n.nextSibling);
5397     }
5398         
5399     
5400 });/*
5401  * Based on:
5402  * Ext JS Library 1.1.1
5403  * Copyright(c) 2006-2007, Ext JS, LLC.
5404  *
5405  * Originally Released Under LGPL - original licence link has changed is not relivant.
5406  *
5407  * Fork - LGPL
5408  * <script type="text/javascript">
5409  */
5410
5411
5412 // nasty IE9 hack - what a pile of crap that is..
5413
5414  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5415     Range.prototype.createContextualFragment = function (html) {
5416         var doc = window.document;
5417         var container = doc.createElement("div");
5418         container.innerHTML = html;
5419         var frag = doc.createDocumentFragment(), n;
5420         while ((n = container.firstChild)) {
5421             frag.appendChild(n);
5422         }
5423         return frag;
5424     };
5425 }
5426
5427 /**
5428  * @class Roo.DomHelper
5429  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5430  * 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>.
5431  * @static
5432  */
5433 Roo.DomHelper = function(){
5434     var tempTableEl = null;
5435     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5436     var tableRe = /^table|tbody|tr|td$/i;
5437     var xmlns = {};
5438     // build as innerHTML where available
5439     /** @ignore */
5440     var createHtml = function(o){
5441         if(typeof o == 'string'){
5442             return o;
5443         }
5444         var b = "";
5445         if(!o.tag){
5446             o.tag = "div";
5447         }
5448         b += "<" + o.tag;
5449         for(var attr in o){
5450             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5451             if(attr == "style"){
5452                 var s = o["style"];
5453                 if(typeof s == "function"){
5454                     s = s.call();
5455                 }
5456                 if(typeof s == "string"){
5457                     b += ' style="' + s + '"';
5458                 }else if(typeof s == "object"){
5459                     b += ' style="';
5460                     for(var key in s){
5461                         if(typeof s[key] != "function"){
5462                             b += key + ":" + s[key] + ";";
5463                         }
5464                     }
5465                     b += '"';
5466                 }
5467             }else{
5468                 if(attr == "cls"){
5469                     b += ' class="' + o["cls"] + '"';
5470                 }else if(attr == "htmlFor"){
5471                     b += ' for="' + o["htmlFor"] + '"';
5472                 }else{
5473                     b += " " + attr + '="' + o[attr] + '"';
5474                 }
5475             }
5476         }
5477         if(emptyTags.test(o.tag)){
5478             b += "/>";
5479         }else{
5480             b += ">";
5481             var cn = o.children || o.cn;
5482             if(cn){
5483                 //http://bugs.kde.org/show_bug.cgi?id=71506
5484                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5485                     for(var i = 0, len = cn.length; i < len; i++) {
5486                         b += createHtml(cn[i], b);
5487                     }
5488                 }else{
5489                     b += createHtml(cn, b);
5490                 }
5491             }
5492             if(o.html){
5493                 b += o.html;
5494             }
5495             b += "</" + o.tag + ">";
5496         }
5497         return b;
5498     };
5499
5500     // build as dom
5501     /** @ignore */
5502     var createDom = function(o, parentNode){
5503          
5504         // defininition craeted..
5505         var ns = false;
5506         if (o.ns && o.ns != 'html') {
5507                
5508             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5509                 xmlns[o.ns] = o.xmlns;
5510                 ns = o.xmlns;
5511             }
5512             if (typeof(xmlns[o.ns]) == 'undefined') {
5513                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5514             }
5515             ns = xmlns[o.ns];
5516         }
5517         
5518         
5519         if (typeof(o) == 'string') {
5520             return parentNode.appendChild(document.createTextNode(o));
5521         }
5522         o.tag = o.tag || 'div';
5523         if (o.ns && Roo.isIE) {
5524             ns = false;
5525             o.tag = o.ns + ':' + o.tag;
5526             
5527         }
5528         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5529         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5530         for(var attr in o){
5531             
5532             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5533                     attr == "style" || typeof o[attr] == "function") { continue; }
5534                     
5535             if(attr=="cls" && Roo.isIE){
5536                 el.className = o["cls"];
5537             }else{
5538                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5539                 else { 
5540                     el[attr] = o[attr];
5541                 }
5542             }
5543         }
5544         Roo.DomHelper.applyStyles(el, o.style);
5545         var cn = o.children || o.cn;
5546         if(cn){
5547             //http://bugs.kde.org/show_bug.cgi?id=71506
5548              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5549                 for(var i = 0, len = cn.length; i < len; i++) {
5550                     createDom(cn[i], el);
5551                 }
5552             }else{
5553                 createDom(cn, el);
5554             }
5555         }
5556         if(o.html){
5557             el.innerHTML = o.html;
5558         }
5559         if(parentNode){
5560            parentNode.appendChild(el);
5561         }
5562         return el;
5563     };
5564
5565     var ieTable = function(depth, s, h, e){
5566         tempTableEl.innerHTML = [s, h, e].join('');
5567         var i = -1, el = tempTableEl;
5568         while(++i < depth && el.firstChild){
5569             el = el.firstChild;
5570         }
5571         return el;
5572     };
5573
5574     // kill repeat to save bytes
5575     var ts = '<table>',
5576         te = '</table>',
5577         tbs = ts+'<tbody>',
5578         tbe = '</tbody>'+te,
5579         trs = tbs + '<tr>',
5580         tre = '</tr>'+tbe;
5581
5582     /**
5583      * @ignore
5584      * Nasty code for IE's broken table implementation
5585      */
5586     var insertIntoTable = function(tag, where, el, html){
5587         if(!tempTableEl){
5588             tempTableEl = document.createElement('div');
5589         }
5590         var node;
5591         var before = null;
5592         if(tag == 'td'){
5593             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5594                 return;
5595             }
5596             if(where == 'beforebegin'){
5597                 before = el;
5598                 el = el.parentNode;
5599             } else{
5600                 before = el.nextSibling;
5601                 el = el.parentNode;
5602             }
5603             node = ieTable(4, trs, html, tre);
5604         }
5605         else if(tag == 'tr'){
5606             if(where == 'beforebegin'){
5607                 before = el;
5608                 el = el.parentNode;
5609                 node = ieTable(3, tbs, html, tbe);
5610             } else if(where == 'afterend'){
5611                 before = el.nextSibling;
5612                 el = el.parentNode;
5613                 node = ieTable(3, tbs, html, tbe);
5614             } else{ // INTO a TR
5615                 if(where == 'afterbegin'){
5616                     before = el.firstChild;
5617                 }
5618                 node = ieTable(4, trs, html, tre);
5619             }
5620         } else if(tag == 'tbody'){
5621             if(where == 'beforebegin'){
5622                 before = el;
5623                 el = el.parentNode;
5624                 node = ieTable(2, ts, html, te);
5625             } else if(where == 'afterend'){
5626                 before = el.nextSibling;
5627                 el = el.parentNode;
5628                 node = ieTable(2, ts, html, te);
5629             } else{
5630                 if(where == 'afterbegin'){
5631                     before = el.firstChild;
5632                 }
5633                 node = ieTable(3, tbs, html, tbe);
5634             }
5635         } else{ // TABLE
5636             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5637                 return;
5638             }
5639             if(where == 'afterbegin'){
5640                 before = el.firstChild;
5641             }
5642             node = ieTable(2, ts, html, te);
5643         }
5644         el.insertBefore(node, before);
5645         return node;
5646     };
5647     
5648     // this is a bit like the react update code...
5649     // 
5650     
5651     var updateNode = function(from, to)
5652     {
5653         // should we handle non-standard elements?
5654         Roo.log(["UpdateNode" , from, to]);
5655         if (from.nodeType != to.nodeType) {
5656             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5657             from.parentNode.replaceChild(to, from);
5658         }
5659         
5660         if (from.nodeType == 3) {
5661             // assume it's text?!
5662             if (from.data == to.data) {
5663                 return;
5664             }
5665             from.data = to.data;
5666             return;
5667         }
5668         if (!from.parentNode) {
5669             // not sure why this is happening?
5670             return;
5671         }
5672         // assume 'to' doesnt have '1/3 nodetypes!
5673         // not sure why, by from, parent node might not exist?
5674         if (from.nodeType !=1 || from.tagName != to.tagName) {
5675             Roo.log(["ReplaceChild" , from, to ]);
5676             
5677             from.parentNode.replaceChild(to, from);
5678             return;
5679         }
5680         // compare attributes
5681         var ar = Array.from(from.attributes);
5682         for(var i = 0; i< ar.length;i++) {
5683             if (to.hasAttribute(ar[i].name)) {
5684                 continue;
5685             }
5686             if (ar[i].name == 'id') { // always keep ids?
5687                continue;
5688             }
5689             //if (ar[i].name == 'style') {
5690             //   throw "style removed?";
5691             //}
5692             Roo.log("removeAttribute" + ar[i].name);
5693             from.removeAttribute(ar[i].name);
5694         }
5695         ar = to.attributes;
5696         for(var i = 0; i< ar.length;i++) {
5697             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5698                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5699                 continue;
5700             }
5701             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5702             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5703         }
5704         // children
5705         var far = Array.from(from.childNodes);
5706         var tar = Array.from(to.childNodes);
5707         // if the lengths are different.. then it's probably a editable content change, rather than
5708         // a change of the block definition..
5709         
5710         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5711          /*if (from.innerHTML == to.innerHTML) {
5712             return;
5713         }
5714         if (far.length != tar.length) {
5715             from.innerHTML = to.innerHTML;
5716             return;
5717         }
5718         */
5719         
5720         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5721             if (i >= far.length) {
5722                 from.appendChild(tar[i]);
5723                 Roo.log(["add", tar[i]]);
5724                 
5725             } else if ( i  >= tar.length) {
5726                 from.removeChild(far[i]);
5727                 Roo.log(["remove", far[i]]);
5728             } else {
5729                 
5730                 updateNode(far[i], tar[i]);
5731             }    
5732         }
5733         
5734         
5735         
5736         
5737     };
5738     
5739     
5740
5741     return {
5742         /** True to force the use of DOM instead of html fragments @type Boolean */
5743         useDom : false,
5744     
5745         /**
5746          * Returns the markup for the passed Element(s) config
5747          * @param {Object} o The Dom object spec (and children)
5748          * @return {String}
5749          */
5750         markup : function(o){
5751             return createHtml(o);
5752         },
5753     
5754         /**
5755          * Applies a style specification to an element
5756          * @param {String/HTMLElement} el The element to apply styles to
5757          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5758          * a function which returns such a specification.
5759          */
5760         applyStyles : function(el, styles){
5761             if(styles){
5762                el = Roo.fly(el);
5763                if(typeof styles == "string"){
5764                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5765                    var matches;
5766                    while ((matches = re.exec(styles)) != null){
5767                        el.setStyle(matches[1], matches[2]);
5768                    }
5769                }else if (typeof styles == "object"){
5770                    for (var style in styles){
5771                       el.setStyle(style, styles[style]);
5772                    }
5773                }else if (typeof styles == "function"){
5774                     Roo.DomHelper.applyStyles(el, styles.call());
5775                }
5776             }
5777         },
5778     
5779         /**
5780          * Inserts an HTML fragment into the Dom
5781          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5782          * @param {HTMLElement} el The context element
5783          * @param {String} html The HTML fragmenet
5784          * @return {HTMLElement} The new node
5785          */
5786         insertHtml : function(where, el, html){
5787             where = where.toLowerCase();
5788             if(el.insertAdjacentHTML){
5789                 if(tableRe.test(el.tagName)){
5790                     var rs;
5791                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5792                         return rs;
5793                     }
5794                 }
5795                 switch(where){
5796                     case "beforebegin":
5797                         el.insertAdjacentHTML('BeforeBegin', html);
5798                         return el.previousSibling;
5799                     case "afterbegin":
5800                         el.insertAdjacentHTML('AfterBegin', html);
5801                         return el.firstChild;
5802                     case "beforeend":
5803                         el.insertAdjacentHTML('BeforeEnd', html);
5804                         return el.lastChild;
5805                     case "afterend":
5806                         el.insertAdjacentHTML('AfterEnd', html);
5807                         return el.nextSibling;
5808                 }
5809                 throw 'Illegal insertion point -> "' + where + '"';
5810             }
5811             var range = el.ownerDocument.createRange();
5812             var frag;
5813             switch(where){
5814                  case "beforebegin":
5815                     range.setStartBefore(el);
5816                     frag = range.createContextualFragment(html);
5817                     el.parentNode.insertBefore(frag, el);
5818                     return el.previousSibling;
5819                  case "afterbegin":
5820                     if(el.firstChild){
5821                         range.setStartBefore(el.firstChild);
5822                         frag = range.createContextualFragment(html);
5823                         el.insertBefore(frag, el.firstChild);
5824                         return el.firstChild;
5825                     }else{
5826                         el.innerHTML = html;
5827                         return el.firstChild;
5828                     }
5829                 case "beforeend":
5830                     if(el.lastChild){
5831                         range.setStartAfter(el.lastChild);
5832                         frag = range.createContextualFragment(html);
5833                         el.appendChild(frag);
5834                         return el.lastChild;
5835                     }else{
5836                         el.innerHTML = html;
5837                         return el.lastChild;
5838                     }
5839                 case "afterend":
5840                     range.setStartAfter(el);
5841                     frag = range.createContextualFragment(html);
5842                     el.parentNode.insertBefore(frag, el.nextSibling);
5843                     return el.nextSibling;
5844                 }
5845                 throw 'Illegal insertion point -> "' + where + '"';
5846         },
5847     
5848         /**
5849          * Creates new Dom element(s) and inserts them before el
5850          * @param {String/HTMLElement/Element} el The context element
5851          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5852          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5853          * @return {HTMLElement/Roo.Element} The new node
5854          */
5855         insertBefore : function(el, o, returnElement){
5856             return this.doInsert(el, o, returnElement, "beforeBegin");
5857         },
5858     
5859         /**
5860          * Creates new Dom element(s) and inserts them after el
5861          * @param {String/HTMLElement/Element} el The context element
5862          * @param {Object} o The Dom object spec (and children)
5863          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5864          * @return {HTMLElement/Roo.Element} The new node
5865          */
5866         insertAfter : function(el, o, returnElement){
5867             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5868         },
5869     
5870         /**
5871          * Creates new Dom element(s) and inserts them as the first child of el
5872          * @param {String/HTMLElement/Element} el The context element
5873          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5874          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5875          * @return {HTMLElement/Roo.Element} The new node
5876          */
5877         insertFirst : function(el, o, returnElement){
5878             return this.doInsert(el, o, returnElement, "afterBegin");
5879         },
5880     
5881         // private
5882         doInsert : function(el, o, returnElement, pos, sibling){
5883             el = Roo.getDom(el);
5884             var newNode;
5885             if(this.useDom || o.ns){
5886                 newNode = createDom(o, null);
5887                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5888             }else{
5889                 var html = createHtml(o);
5890                 newNode = this.insertHtml(pos, el, html);
5891             }
5892             return returnElement ? Roo.get(newNode, true) : newNode;
5893         },
5894     
5895         /**
5896          * Creates new Dom element(s) and appends them to el
5897          * @param {String/HTMLElement/Element} el The context element
5898          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5899          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5900          * @return {HTMLElement/Roo.Element} The new node
5901          */
5902         append : function(el, o, returnElement){
5903             el = Roo.getDom(el);
5904             var newNode;
5905             if(this.useDom || o.ns){
5906                 newNode = createDom(o, null);
5907                 el.appendChild(newNode);
5908             }else{
5909                 var html = createHtml(o);
5910                 newNode = this.insertHtml("beforeEnd", el, html);
5911             }
5912             return returnElement ? Roo.get(newNode, true) : newNode;
5913         },
5914     
5915         /**
5916          * Creates new Dom element(s) and overwrites the contents of el with them
5917          * @param {String/HTMLElement/Element} el The context element
5918          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5919          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5920          * @return {HTMLElement/Roo.Element} The new node
5921          */
5922         overwrite : function(el, o, returnElement)
5923         {
5924             el = Roo.getDom(el);
5925             if (o.ns) {
5926               
5927                 while (el.childNodes.length) {
5928                     el.removeChild(el.firstChild);
5929                 }
5930                 createDom(o, el);
5931             } else {
5932                 el.innerHTML = createHtml(o);   
5933             }
5934             
5935             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5936         },
5937     
5938         /**
5939          * Creates a new Roo.DomHelper.Template from the Dom object spec
5940          * @param {Object} o The Dom object spec (and children)
5941          * @return {Roo.DomHelper.Template} The new template
5942          */
5943         createTemplate : function(o){
5944             var html = createHtml(o);
5945             return new Roo.Template(html);
5946         },
5947          /**
5948          * Updates the first element with the spec from the o (replacing if necessary)
5949          * This iterates through the children, and updates attributes / children etc..
5950          * @param {String/HTMLElement/Element} el The context element
5951          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5952          */
5953         
5954         update : function(el, o)
5955         {
5956             updateNode(Roo.getDom(el), createDom(o));
5957             
5958         }
5959         
5960         
5961     };
5962 }();
5963 /*
5964  * Based on:
5965  * Ext JS Library 1.1.1
5966  * Copyright(c) 2006-2007, Ext JS, LLC.
5967  *
5968  * Originally Released Under LGPL - original licence link has changed is not relivant.
5969  *
5970  * Fork - LGPL
5971  * <script type="text/javascript">
5972  */
5973  
5974 /**
5975 * @class Roo.Template
5976 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5977 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5978 * Usage:
5979 <pre><code>
5980 var t = new Roo.Template({
5981     html :  '&lt;div name="{id}"&gt;' + 
5982         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5983         '&lt;/div&gt;',
5984     myformat: function (value, allValues) {
5985         return 'XX' + value;
5986     }
5987 });
5988 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5989 </code></pre>
5990 * For more information see this blog post with examples:
5991 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5992      - Create Elements using DOM, HTML fragments and Templates</a>. 
5993 * @constructor
5994 * @param {Object} cfg - Configuration object.
5995 */
5996 Roo.Template = function(cfg){
5997     // BC!
5998     if(cfg instanceof Array){
5999         cfg = cfg.join("");
6000     }else if(arguments.length > 1){
6001         cfg = Array.prototype.join.call(arguments, "");
6002     }
6003     
6004     
6005     if (typeof(cfg) == 'object') {
6006         Roo.apply(this,cfg)
6007     } else {
6008         // bc
6009         this.html = cfg;
6010     }
6011     if (this.url) {
6012         this.load();
6013     }
6014     
6015 };
6016 Roo.Template.prototype = {
6017     
6018     /**
6019      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6020      */
6021     onLoad : false,
6022     
6023     
6024     /**
6025      * @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..
6026      *                    it should be fixed so that template is observable...
6027      */
6028     url : false,
6029     /**
6030      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6031      */
6032     html : '',
6033     
6034     
6035     compiled : false,
6036     loaded : false,
6037     /**
6038      * Returns an HTML fragment of this template with the specified values applied.
6039      * @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'})
6040      * @return {String} The HTML fragment
6041      */
6042     
6043    
6044     
6045     applyTemplate : function(values){
6046         //Roo.log(["applyTemplate", values]);
6047         try {
6048            
6049             if(this.compiled){
6050                 return this.compiled(values);
6051             }
6052             var useF = this.disableFormats !== true;
6053             var fm = Roo.util.Format, tpl = this;
6054             var fn = function(m, name, format, args){
6055                 if(format && useF){
6056                     if(format.substr(0, 5) == "this."){
6057                         return tpl.call(format.substr(5), values[name], values);
6058                     }else{
6059                         if(args){
6060                             // quoted values are required for strings in compiled templates, 
6061                             // but for non compiled we need to strip them
6062                             // quoted reversed for jsmin
6063                             var re = /^\s*['"](.*)["']\s*$/;
6064                             args = args.split(',');
6065                             for(var i = 0, len = args.length; i < len; i++){
6066                                 args[i] = args[i].replace(re, "$1");
6067                             }
6068                             args = [values[name]].concat(args);
6069                         }else{
6070                             args = [values[name]];
6071                         }
6072                         return fm[format].apply(fm, args);
6073                     }
6074                 }else{
6075                     return values[name] !== undefined ? values[name] : "";
6076                 }
6077             };
6078             return this.html.replace(this.re, fn);
6079         } catch (e) {
6080             Roo.log(e);
6081             throw e;
6082         }
6083          
6084     },
6085     
6086     loading : false,
6087       
6088     load : function ()
6089     {
6090          
6091         if (this.loading) {
6092             return;
6093         }
6094         var _t = this;
6095         
6096         this.loading = true;
6097         this.compiled = false;
6098         
6099         var cx = new Roo.data.Connection();
6100         cx.request({
6101             url : this.url,
6102             method : 'GET',
6103             success : function (response) {
6104                 _t.loading = false;
6105                 _t.url = false;
6106                 
6107                 _t.set(response.responseText,true);
6108                 _t.loaded = true;
6109                 if (_t.onLoad) {
6110                     _t.onLoad();
6111                 }
6112              },
6113             failure : function(response) {
6114                 Roo.log("Template failed to load from " + _t.url);
6115                 _t.loading = false;
6116             }
6117         });
6118     },
6119
6120     /**
6121      * Sets the HTML used as the template and optionally compiles it.
6122      * @param {String} html
6123      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6124      * @return {Roo.Template} this
6125      */
6126     set : function(html, compile){
6127         this.html = html;
6128         this.compiled = false;
6129         if(compile){
6130             this.compile();
6131         }
6132         return this;
6133     },
6134     
6135     /**
6136      * True to disable format functions (defaults to false)
6137      * @type Boolean
6138      */
6139     disableFormats : false,
6140     
6141     /**
6142     * The regular expression used to match template variables 
6143     * @type RegExp
6144     * @property 
6145     */
6146     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6147     
6148     /**
6149      * Compiles the template into an internal function, eliminating the RegEx overhead.
6150      * @return {Roo.Template} this
6151      */
6152     compile : function(){
6153         var fm = Roo.util.Format;
6154         var useF = this.disableFormats !== true;
6155         var sep = Roo.isGecko ? "+" : ",";
6156         var fn = function(m, name, format, args){
6157             if(format && useF){
6158                 args = args ? ',' + args : "";
6159                 if(format.substr(0, 5) != "this."){
6160                     format = "fm." + format + '(';
6161                 }else{
6162                     format = 'this.call("'+ format.substr(5) + '", ';
6163                     args = ", values";
6164                 }
6165             }else{
6166                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6167             }
6168             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6169         };
6170         var body;
6171         // branched to use + in gecko and [].join() in others
6172         if(Roo.isGecko){
6173             body = "this.compiled = function(values){ return '" +
6174                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6175                     "';};";
6176         }else{
6177             body = ["this.compiled = function(values){ return ['"];
6178             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6179             body.push("'].join('');};");
6180             body = body.join('');
6181         }
6182         /**
6183          * eval:var:values
6184          * eval:var:fm
6185          */
6186         eval(body);
6187         return this;
6188     },
6189     
6190     // private function used to call members
6191     call : function(fnName, value, allValues){
6192         return this[fnName](value, allValues);
6193     },
6194     
6195     /**
6196      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6197      * @param {String/HTMLElement/Roo.Element} el The context element
6198      * @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'})
6199      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6200      * @return {HTMLElement/Roo.Element} The new node or Element
6201      */
6202     insertFirst: function(el, values, returnElement){
6203         return this.doInsert('afterBegin', el, values, returnElement);
6204     },
6205
6206     /**
6207      * Applies the supplied values to the template and inserts the new node(s) before el.
6208      * @param {String/HTMLElement/Roo.Element} el The context element
6209      * @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'})
6210      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6211      * @return {HTMLElement/Roo.Element} The new node or Element
6212      */
6213     insertBefore: function(el, values, returnElement){
6214         return this.doInsert('beforeBegin', el, values, returnElement);
6215     },
6216
6217     /**
6218      * Applies the supplied values to the template and inserts the new node(s) after el.
6219      * @param {String/HTMLElement/Roo.Element} el The context element
6220      * @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'})
6221      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6222      * @return {HTMLElement/Roo.Element} The new node or Element
6223      */
6224     insertAfter : function(el, values, returnElement){
6225         return this.doInsert('afterEnd', el, values, returnElement);
6226     },
6227     
6228     /**
6229      * Applies the supplied values to the template and appends the new node(s) to el.
6230      * @param {String/HTMLElement/Roo.Element} el The context element
6231      * @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'})
6232      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6233      * @return {HTMLElement/Roo.Element} The new node or Element
6234      */
6235     append : function(el, values, returnElement){
6236         return this.doInsert('beforeEnd', el, values, returnElement);
6237     },
6238
6239     doInsert : function(where, el, values, returnEl){
6240         el = Roo.getDom(el);
6241         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6242         return returnEl ? Roo.get(newNode, true) : newNode;
6243     },
6244
6245     /**
6246      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6247      * @param {String/HTMLElement/Roo.Element} el The context element
6248      * @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'})
6249      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6250      * @return {HTMLElement/Roo.Element} The new node or Element
6251      */
6252     overwrite : function(el, values, returnElement){
6253         el = Roo.getDom(el);
6254         el.innerHTML = this.applyTemplate(values);
6255         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6256     }
6257 };
6258 /**
6259  * Alias for {@link #applyTemplate}
6260  * @method
6261  */
6262 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6263
6264 // backwards compat
6265 Roo.DomHelper.Template = Roo.Template;
6266
6267 /**
6268  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6269  * @param {String/HTMLElement} el A DOM element or its id
6270  * @returns {Roo.Template} The created template
6271  * @static
6272  */
6273 Roo.Template.from = function(el){
6274     el = Roo.getDom(el);
6275     return new Roo.Template(el.value || el.innerHTML);
6276 };/*
6277  * Based on:
6278  * Ext JS Library 1.1.1
6279  * Copyright(c) 2006-2007, Ext JS, LLC.
6280  *
6281  * Originally Released Under LGPL - original licence link has changed is not relivant.
6282  *
6283  * Fork - LGPL
6284  * <script type="text/javascript">
6285  */
6286  
6287
6288 /*
6289  * This is code is also distributed under MIT license for use
6290  * with jQuery and prototype JavaScript libraries.
6291  */
6292 /**
6293  * @class Roo.DomQuery
6294 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).
6295 <p>
6296 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>
6297
6298 <p>
6299 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.
6300 </p>
6301 <h4>Element Selectors:</h4>
6302 <ul class="list">
6303     <li> <b>*</b> any element</li>
6304     <li> <b>E</b> an element with the tag E</li>
6305     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6306     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6307     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6308     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6309 </ul>
6310 <h4>Attribute Selectors:</h4>
6311 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6312 <ul class="list">
6313     <li> <b>E[foo]</b> has an attribute "foo"</li>
6314     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6315     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6316     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6317     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6318     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6319     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6320 </ul>
6321 <h4>Pseudo Classes:</h4>
6322 <ul class="list">
6323     <li> <b>E:first-child</b> E is the first child of its parent</li>
6324     <li> <b>E:last-child</b> E is the last child of its parent</li>
6325     <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>
6326     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6327     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6328     <li> <b>E:only-child</b> E is the only child of its parent</li>
6329     <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>
6330     <li> <b>E:first</b> the first E in the resultset</li>
6331     <li> <b>E:last</b> the last E in the resultset</li>
6332     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6333     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6334     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6335     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6336     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6337     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6338     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6339     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6340     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6341 </ul>
6342 <h4>CSS Value Selectors:</h4>
6343 <ul class="list">
6344     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6345     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6346     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6347     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6348     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6349     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6350 </ul>
6351  * @static
6352  */
6353 Roo.DomQuery = function(){
6354     var cache = {}, simpleCache = {}, valueCache = {};
6355     var nonSpace = /\S/;
6356     var trimRe = /^\s+|\s+$/g;
6357     var tplRe = /\{(\d+)\}/g;
6358     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6359     var tagTokenRe = /^(#)?([\w-\*]+)/;
6360     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6361
6362     function child(p, index){
6363         var i = 0;
6364         var n = p.firstChild;
6365         while(n){
6366             if(n.nodeType == 1){
6367                if(++i == index){
6368                    return n;
6369                }
6370             }
6371             n = n.nextSibling;
6372         }
6373         return null;
6374     };
6375
6376     function next(n){
6377         while((n = n.nextSibling) && n.nodeType != 1);
6378         return n;
6379     };
6380
6381     function prev(n){
6382         while((n = n.previousSibling) && n.nodeType != 1);
6383         return n;
6384     };
6385
6386     function children(d){
6387         var n = d.firstChild, ni = -1;
6388             while(n){
6389                 var nx = n.nextSibling;
6390                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6391                     d.removeChild(n);
6392                 }else{
6393                     n.nodeIndex = ++ni;
6394                 }
6395                 n = nx;
6396             }
6397             return this;
6398         };
6399
6400     function byClassName(c, a, v){
6401         if(!v){
6402             return c;
6403         }
6404         var r = [], ri = -1, cn;
6405         for(var i = 0, ci; ci = c[i]; i++){
6406             
6407             
6408             if((' '+
6409                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6410                  +' ').indexOf(v) != -1){
6411                 r[++ri] = ci;
6412             }
6413         }
6414         return r;
6415     };
6416
6417     function attrValue(n, attr){
6418         if(!n.tagName && typeof n.length != "undefined"){
6419             n = n[0];
6420         }
6421         if(!n){
6422             return null;
6423         }
6424         if(attr == "for"){
6425             return n.htmlFor;
6426         }
6427         if(attr == "class" || attr == "className"){
6428             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6429         }
6430         return n.getAttribute(attr) || n[attr];
6431
6432     };
6433
6434     function getNodes(ns, mode, tagName){
6435         var result = [], ri = -1, cs;
6436         if(!ns){
6437             return result;
6438         }
6439         tagName = tagName || "*";
6440         if(typeof ns.getElementsByTagName != "undefined"){
6441             ns = [ns];
6442         }
6443         if(!mode){
6444             for(var i = 0, ni; ni = ns[i]; i++){
6445                 cs = ni.getElementsByTagName(tagName);
6446                 for(var j = 0, ci; ci = cs[j]; j++){
6447                     result[++ri] = ci;
6448                 }
6449             }
6450         }else if(mode == "/" || mode == ">"){
6451             var utag = tagName.toUpperCase();
6452             for(var i = 0, ni, cn; ni = ns[i]; i++){
6453                 cn = ni.children || ni.childNodes;
6454                 for(var j = 0, cj; cj = cn[j]; j++){
6455                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6456                         result[++ri] = cj;
6457                     }
6458                 }
6459             }
6460         }else if(mode == "+"){
6461             var utag = tagName.toUpperCase();
6462             for(var i = 0, n; n = ns[i]; i++){
6463                 while((n = n.nextSibling) && n.nodeType != 1);
6464                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6465                     result[++ri] = n;
6466                 }
6467             }
6468         }else if(mode == "~"){
6469             for(var i = 0, n; n = ns[i]; i++){
6470                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6471                 if(n){
6472                     result[++ri] = n;
6473                 }
6474             }
6475         }
6476         return result;
6477     };
6478
6479     function concat(a, b){
6480         if(b.slice){
6481             return a.concat(b);
6482         }
6483         for(var i = 0, l = b.length; i < l; i++){
6484             a[a.length] = b[i];
6485         }
6486         return a;
6487     }
6488
6489     function byTag(cs, tagName){
6490         if(cs.tagName || cs == document){
6491             cs = [cs];
6492         }
6493         if(!tagName){
6494             return cs;
6495         }
6496         var r = [], ri = -1;
6497         tagName = tagName.toLowerCase();
6498         for(var i = 0, ci; ci = cs[i]; i++){
6499             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6500                 r[++ri] = ci;
6501             }
6502         }
6503         return r;
6504     };
6505
6506     function byId(cs, attr, id){
6507         if(cs.tagName || cs == document){
6508             cs = [cs];
6509         }
6510         if(!id){
6511             return cs;
6512         }
6513         var r = [], ri = -1;
6514         for(var i = 0,ci; ci = cs[i]; i++){
6515             if(ci && ci.id == id){
6516                 r[++ri] = ci;
6517                 return r;
6518             }
6519         }
6520         return r;
6521     };
6522
6523     function byAttribute(cs, attr, value, op, custom){
6524         var r = [], ri = -1, st = custom=="{";
6525         var f = Roo.DomQuery.operators[op];
6526         for(var i = 0, ci; ci = cs[i]; i++){
6527             var a;
6528             if(st){
6529                 a = Roo.DomQuery.getStyle(ci, attr);
6530             }
6531             else if(attr == "class" || attr == "className"){
6532                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6533             }else if(attr == "for"){
6534                 a = ci.htmlFor;
6535             }else if(attr == "href"){
6536                 a = ci.getAttribute("href", 2);
6537             }else{
6538                 a = ci.getAttribute(attr);
6539             }
6540             if((f && f(a, value)) || (!f && a)){
6541                 r[++ri] = ci;
6542             }
6543         }
6544         return r;
6545     };
6546
6547     function byPseudo(cs, name, value){
6548         return Roo.DomQuery.pseudos[name](cs, value);
6549     };
6550
6551     // This is for IE MSXML which does not support expandos.
6552     // IE runs the same speed using setAttribute, however FF slows way down
6553     // and Safari completely fails so they need to continue to use expandos.
6554     var isIE = window.ActiveXObject ? true : false;
6555
6556     // this eval is stop the compressor from
6557     // renaming the variable to something shorter
6558     
6559     /** eval:var:batch */
6560     var batch = 30803; 
6561
6562     var key = 30803;
6563
6564     function nodupIEXml(cs){
6565         var d = ++key;
6566         cs[0].setAttribute("_nodup", d);
6567         var r = [cs[0]];
6568         for(var i = 1, len = cs.length; i < len; i++){
6569             var c = cs[i];
6570             if(!c.getAttribute("_nodup") != d){
6571                 c.setAttribute("_nodup", d);
6572                 r[r.length] = c;
6573             }
6574         }
6575         for(var i = 0, len = cs.length; i < len; i++){
6576             cs[i].removeAttribute("_nodup");
6577         }
6578         return r;
6579     }
6580
6581     function nodup(cs){
6582         if(!cs){
6583             return [];
6584         }
6585         var len = cs.length, c, i, r = cs, cj, ri = -1;
6586         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6587             return cs;
6588         }
6589         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6590             return nodupIEXml(cs);
6591         }
6592         var d = ++key;
6593         cs[0]._nodup = d;
6594         for(i = 1; c = cs[i]; i++){
6595             if(c._nodup != d){
6596                 c._nodup = d;
6597             }else{
6598                 r = [];
6599                 for(var j = 0; j < i; j++){
6600                     r[++ri] = cs[j];
6601                 }
6602                 for(j = i+1; cj = cs[j]; j++){
6603                     if(cj._nodup != d){
6604                         cj._nodup = d;
6605                         r[++ri] = cj;
6606                     }
6607                 }
6608                 return r;
6609             }
6610         }
6611         return r;
6612     }
6613
6614     function quickDiffIEXml(c1, c2){
6615         var d = ++key;
6616         for(var i = 0, len = c1.length; i < len; i++){
6617             c1[i].setAttribute("_qdiff", d);
6618         }
6619         var r = [];
6620         for(var i = 0, len = c2.length; i < len; i++){
6621             if(c2[i].getAttribute("_qdiff") != d){
6622                 r[r.length] = c2[i];
6623             }
6624         }
6625         for(var i = 0, len = c1.length; i < len; i++){
6626            c1[i].removeAttribute("_qdiff");
6627         }
6628         return r;
6629     }
6630
6631     function quickDiff(c1, c2){
6632         var len1 = c1.length;
6633         if(!len1){
6634             return c2;
6635         }
6636         if(isIE && c1[0].selectSingleNode){
6637             return quickDiffIEXml(c1, c2);
6638         }
6639         var d = ++key;
6640         for(var i = 0; i < len1; i++){
6641             c1[i]._qdiff = d;
6642         }
6643         var r = [];
6644         for(var i = 0, len = c2.length; i < len; i++){
6645             if(c2[i]._qdiff != d){
6646                 r[r.length] = c2[i];
6647             }
6648         }
6649         return r;
6650     }
6651
6652     function quickId(ns, mode, root, id){
6653         if(ns == root){
6654            var d = root.ownerDocument || root;
6655            return d.getElementById(id);
6656         }
6657         ns = getNodes(ns, mode, "*");
6658         return byId(ns, null, id);
6659     }
6660
6661     return {
6662         getStyle : function(el, name){
6663             return Roo.fly(el).getStyle(name);
6664         },
6665         /**
6666          * Compiles a selector/xpath query into a reusable function. The returned function
6667          * takes one parameter "root" (optional), which is the context node from where the query should start.
6668          * @param {String} selector The selector/xpath query
6669          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6670          * @return {Function}
6671          */
6672         compile : function(path, type){
6673             type = type || "select";
6674             
6675             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6676             var q = path, mode, lq;
6677             var tk = Roo.DomQuery.matchers;
6678             var tklen = tk.length;
6679             var mm;
6680
6681             // accept leading mode switch
6682             var lmode = q.match(modeRe);
6683             if(lmode && lmode[1]){
6684                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6685                 q = q.replace(lmode[1], "");
6686             }
6687             // strip leading slashes
6688             while(path.substr(0, 1)=="/"){
6689                 path = path.substr(1);
6690             }
6691
6692             while(q && lq != q){
6693                 lq = q;
6694                 var tm = q.match(tagTokenRe);
6695                 if(type == "select"){
6696                     if(tm){
6697                         if(tm[1] == "#"){
6698                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6699                         }else{
6700                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6701                         }
6702                         q = q.replace(tm[0], "");
6703                     }else if(q.substr(0, 1) != '@'){
6704                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6705                     }
6706                 }else{
6707                     if(tm){
6708                         if(tm[1] == "#"){
6709                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6710                         }else{
6711                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6712                         }
6713                         q = q.replace(tm[0], "");
6714                     }
6715                 }
6716                 while(!(mm = q.match(modeRe))){
6717                     var matched = false;
6718                     for(var j = 0; j < tklen; j++){
6719                         var t = tk[j];
6720                         var m = q.match(t.re);
6721                         if(m){
6722                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6723                                                     return m[i];
6724                                                 });
6725                             q = q.replace(m[0], "");
6726                             matched = true;
6727                             break;
6728                         }
6729                     }
6730                     // prevent infinite loop on bad selector
6731                     if(!matched){
6732                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6733                     }
6734                 }
6735                 if(mm[1]){
6736                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6737                     q = q.replace(mm[1], "");
6738                 }
6739             }
6740             fn[fn.length] = "return nodup(n);\n}";
6741             
6742              /** 
6743               * list of variables that need from compression as they are used by eval.
6744              *  eval:var:batch 
6745              *  eval:var:nodup
6746              *  eval:var:byTag
6747              *  eval:var:ById
6748              *  eval:var:getNodes
6749              *  eval:var:quickId
6750              *  eval:var:mode
6751              *  eval:var:root
6752              *  eval:var:n
6753              *  eval:var:byClassName
6754              *  eval:var:byPseudo
6755              *  eval:var:byAttribute
6756              *  eval:var:attrValue
6757              * 
6758              **/ 
6759             eval(fn.join(""));
6760             return f;
6761         },
6762
6763         /**
6764          * Selects a group of elements.
6765          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6766          * @param {Node} root (optional) The start of the query (defaults to document).
6767          * @return {Array}
6768          */
6769         select : function(path, root, type){
6770             if(!root || root == document){
6771                 root = document;
6772             }
6773             if(typeof root == "string"){
6774                 root = document.getElementById(root);
6775             }
6776             var paths = path.split(",");
6777             var results = [];
6778             for(var i = 0, len = paths.length; i < len; i++){
6779                 var p = paths[i].replace(trimRe, "");
6780                 if(!cache[p]){
6781                     cache[p] = Roo.DomQuery.compile(p);
6782                     if(!cache[p]){
6783                         throw p + " is not a valid selector";
6784                     }
6785                 }
6786                 var result = cache[p](root);
6787                 if(result && result != document){
6788                     results = results.concat(result);
6789                 }
6790             }
6791             if(paths.length > 1){
6792                 return nodup(results);
6793             }
6794             return results;
6795         },
6796
6797         /**
6798          * Selects a single element.
6799          * @param {String} selector The selector/xpath query
6800          * @param {Node} root (optional) The start of the query (defaults to document).
6801          * @return {Element}
6802          */
6803         selectNode : function(path, root){
6804             return Roo.DomQuery.select(path, root)[0];
6805         },
6806
6807         /**
6808          * Selects the value of a node, optionally replacing null with the defaultValue.
6809          * @param {String} selector The selector/xpath query
6810          * @param {Node} root (optional) The start of the query (defaults to document).
6811          * @param {String} defaultValue
6812          */
6813         selectValue : function(path, root, defaultValue){
6814             path = path.replace(trimRe, "");
6815             if(!valueCache[path]){
6816                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6817             }
6818             var n = valueCache[path](root);
6819             n = n[0] ? n[0] : n;
6820             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6821             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6822         },
6823
6824         /**
6825          * Selects the value of a node, parsing integers and floats.
6826          * @param {String} selector The selector/xpath query
6827          * @param {Node} root (optional) The start of the query (defaults to document).
6828          * @param {Number} defaultValue
6829          * @return {Number}
6830          */
6831         selectNumber : function(path, root, defaultValue){
6832             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6833             return parseFloat(v);
6834         },
6835
6836         /**
6837          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6838          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6839          * @param {String} selector The simple selector to test
6840          * @return {Boolean}
6841          */
6842         is : function(el, ss){
6843             if(typeof el == "string"){
6844                 el = document.getElementById(el);
6845             }
6846             var isArray = (el instanceof Array);
6847             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6848             return isArray ? (result.length == el.length) : (result.length > 0);
6849         },
6850
6851         /**
6852          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6853          * @param {Array} el An array of elements to filter
6854          * @param {String} selector The simple selector to test
6855          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6856          * the selector instead of the ones that match
6857          * @return {Array}
6858          */
6859         filter : function(els, ss, nonMatches){
6860             ss = ss.replace(trimRe, "");
6861             if(!simpleCache[ss]){
6862                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6863             }
6864             var result = simpleCache[ss](els);
6865             return nonMatches ? quickDiff(result, els) : result;
6866         },
6867
6868         /**
6869          * Collection of matching regular expressions and code snippets.
6870          */
6871         matchers : [{
6872                 re: /^\.([\w-]+)/,
6873                 select: 'n = byClassName(n, null, " {1} ");'
6874             }, {
6875                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6876                 select: 'n = byPseudo(n, "{1}", "{2}");'
6877             },{
6878                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6879                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6880             }, {
6881                 re: /^#([\w-]+)/,
6882                 select: 'n = byId(n, null, "{1}");'
6883             },{
6884                 re: /^@([\w-]+)/,
6885                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6886             }
6887         ],
6888
6889         /**
6890          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6891          * 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;.
6892          */
6893         operators : {
6894             "=" : function(a, v){
6895                 return a == v;
6896             },
6897             "!=" : function(a, v){
6898                 return a != v;
6899             },
6900             "^=" : function(a, v){
6901                 return a && a.substr(0, v.length) == v;
6902             },
6903             "$=" : function(a, v){
6904                 return a && a.substr(a.length-v.length) == v;
6905             },
6906             "*=" : function(a, v){
6907                 return a && a.indexOf(v) !== -1;
6908             },
6909             "%=" : function(a, v){
6910                 return (a % v) == 0;
6911             },
6912             "|=" : function(a, v){
6913                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6914             },
6915             "~=" : function(a, v){
6916                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6917             }
6918         },
6919
6920         /**
6921          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6922          * and the argument (if any) supplied in the selector.
6923          */
6924         pseudos : {
6925             "first-child" : function(c){
6926                 var r = [], ri = -1, n;
6927                 for(var i = 0, ci; ci = n = c[i]; i++){
6928                     while((n = n.previousSibling) && n.nodeType != 1);
6929                     if(!n){
6930                         r[++ri] = ci;
6931                     }
6932                 }
6933                 return r;
6934             },
6935
6936             "last-child" : function(c){
6937                 var r = [], ri = -1, n;
6938                 for(var i = 0, ci; ci = n = c[i]; i++){
6939                     while((n = n.nextSibling) && n.nodeType != 1);
6940                     if(!n){
6941                         r[++ri] = ci;
6942                     }
6943                 }
6944                 return r;
6945             },
6946
6947             "nth-child" : function(c, a) {
6948                 var r = [], ri = -1;
6949                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6950                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6951                 for(var i = 0, n; n = c[i]; i++){
6952                     var pn = n.parentNode;
6953                     if (batch != pn._batch) {
6954                         var j = 0;
6955                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6956                             if(cn.nodeType == 1){
6957                                cn.nodeIndex = ++j;
6958                             }
6959                         }
6960                         pn._batch = batch;
6961                     }
6962                     if (f == 1) {
6963                         if (l == 0 || n.nodeIndex == l){
6964                             r[++ri] = n;
6965                         }
6966                     } else if ((n.nodeIndex + l) % f == 0){
6967                         r[++ri] = n;
6968                     }
6969                 }
6970
6971                 return r;
6972             },
6973
6974             "only-child" : function(c){
6975                 var r = [], ri = -1;;
6976                 for(var i = 0, ci; ci = c[i]; i++){
6977                     if(!prev(ci) && !next(ci)){
6978                         r[++ri] = ci;
6979                     }
6980                 }
6981                 return r;
6982             },
6983
6984             "empty" : function(c){
6985                 var r = [], ri = -1;
6986                 for(var i = 0, ci; ci = c[i]; i++){
6987                     var cns = ci.childNodes, j = 0, cn, empty = true;
6988                     while(cn = cns[j]){
6989                         ++j;
6990                         if(cn.nodeType == 1 || cn.nodeType == 3){
6991                             empty = false;
6992                             break;
6993                         }
6994                     }
6995                     if(empty){
6996                         r[++ri] = ci;
6997                     }
6998                 }
6999                 return r;
7000             },
7001
7002             "contains" : function(c, v){
7003                 var r = [], ri = -1;
7004                 for(var i = 0, ci; ci = c[i]; i++){
7005                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7006                         r[++ri] = ci;
7007                     }
7008                 }
7009                 return r;
7010             },
7011
7012             "nodeValue" : function(c, v){
7013                 var r = [], ri = -1;
7014                 for(var i = 0, ci; ci = c[i]; i++){
7015                     if(ci.firstChild && ci.firstChild.nodeValue == v){
7016                         r[++ri] = ci;
7017                     }
7018                 }
7019                 return r;
7020             },
7021
7022             "checked" : function(c){
7023                 var r = [], ri = -1;
7024                 for(var i = 0, ci; ci = c[i]; i++){
7025                     if(ci.checked == true){
7026                         r[++ri] = ci;
7027                     }
7028                 }
7029                 return r;
7030             },
7031
7032             "not" : function(c, ss){
7033                 return Roo.DomQuery.filter(c, ss, true);
7034             },
7035
7036             "odd" : function(c){
7037                 return this["nth-child"](c, "odd");
7038             },
7039
7040             "even" : function(c){
7041                 return this["nth-child"](c, "even");
7042             },
7043
7044             "nth" : function(c, a){
7045                 return c[a-1] || [];
7046             },
7047
7048             "first" : function(c){
7049                 return c[0] || [];
7050             },
7051
7052             "last" : function(c){
7053                 return c[c.length-1] || [];
7054             },
7055
7056             "has" : function(c, ss){
7057                 var s = Roo.DomQuery.select;
7058                 var r = [], ri = -1;
7059                 for(var i = 0, ci; ci = c[i]; i++){
7060                     if(s(ss, ci).length > 0){
7061                         r[++ri] = ci;
7062                     }
7063                 }
7064                 return r;
7065             },
7066
7067             "next" : function(c, ss){
7068                 var is = Roo.DomQuery.is;
7069                 var r = [], ri = -1;
7070                 for(var i = 0, ci; ci = c[i]; i++){
7071                     var n = next(ci);
7072                     if(n && is(n, ss)){
7073                         r[++ri] = ci;
7074                     }
7075                 }
7076                 return r;
7077             },
7078
7079             "prev" : function(c, ss){
7080                 var is = Roo.DomQuery.is;
7081                 var r = [], ri = -1;
7082                 for(var i = 0, ci; ci = c[i]; i++){
7083                     var n = prev(ci);
7084                     if(n && is(n, ss)){
7085                         r[++ri] = ci;
7086                     }
7087                 }
7088                 return r;
7089             }
7090         }
7091     };
7092 }();
7093
7094 /**
7095  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7096  * @param {String} path The selector/xpath query
7097  * @param {Node} root (optional) The start of the query (defaults to document).
7098  * @return {Array}
7099  * @member Roo
7100  * @method query
7101  */
7102 Roo.query = Roo.DomQuery.select;
7103 /*
7104  * Based on:
7105  * Ext JS Library 1.1.1
7106  * Copyright(c) 2006-2007, Ext JS, LLC.
7107  *
7108  * Originally Released Under LGPL - original licence link has changed is not relivant.
7109  *
7110  * Fork - LGPL
7111  * <script type="text/javascript">
7112  */
7113
7114 /**
7115  * @class Roo.util.Observable
7116  * Base class that provides a common interface for publishing events. Subclasses are expected to
7117  * to have a property "events" with all the events defined.<br>
7118  * For example:
7119  * <pre><code>
7120  Employee = function(name){
7121     this.name = name;
7122     this.addEvents({
7123         "fired" : true,
7124         "quit" : true
7125     });
7126  }
7127  Roo.extend(Employee, Roo.util.Observable);
7128 </code></pre>
7129  * @param {Object} config properties to use (incuding events / listeners)
7130  */
7131
7132 Roo.util.Observable = function(cfg){
7133     
7134     cfg = cfg|| {};
7135     this.addEvents(cfg.events || {});
7136     if (cfg.events) {
7137         delete cfg.events; // make sure
7138     }
7139      
7140     Roo.apply(this, cfg);
7141     
7142     if(this.listeners){
7143         this.on(this.listeners);
7144         delete this.listeners;
7145     }
7146 };
7147 Roo.util.Observable.prototype = {
7148     /** 
7149  * @cfg {Object} listeners  list of events and functions to call for this object, 
7150  * For example :
7151  * <pre><code>
7152     listeners :  { 
7153        'click' : function(e) {
7154            ..... 
7155         } ,
7156         .... 
7157     } 
7158   </code></pre>
7159  */
7160     
7161     
7162     /**
7163      * Fires the specified event with the passed parameters (minus the event name).
7164      * @param {String} eventName
7165      * @param {Object...} args Variable number of parameters are passed to handlers
7166      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7167      */
7168     fireEvent : function(){
7169         var ce = this.events[arguments[0].toLowerCase()];
7170         if(typeof ce == "object"){
7171             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7172         }else{
7173             return true;
7174         }
7175     },
7176
7177     // private
7178     filterOptRe : /^(?:scope|delay|buffer|single)$/,
7179
7180     /**
7181      * Appends an event handler to this component
7182      * @param {String}   eventName The type of event to listen for
7183      * @param {Function} handler The method the event invokes
7184      * @param {Object}   scope (optional) The scope in which to execute the handler
7185      * function. The handler function's "this" context.
7186      * @param {Object}   options (optional) An object containing handler configuration
7187      * properties. This may contain any of the following properties:<ul>
7188      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7189      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7190      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7191      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7192      * by the specified number of milliseconds. If the event fires again within that time, the original
7193      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7194      * </ul><br>
7195      * <p>
7196      * <b>Combining Options</b><br>
7197      * Using the options argument, it is possible to combine different types of listeners:<br>
7198      * <br>
7199      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7200                 <pre><code>
7201                 el.on('click', this.onClick, this, {
7202                         single: true,
7203                 delay: 100,
7204                 forumId: 4
7205                 });
7206                 </code></pre>
7207      * <p>
7208      * <b>Attaching multiple handlers in 1 call</b><br>
7209      * The method also allows for a single argument to be passed which is a config object containing properties
7210      * which specify multiple handlers.
7211      * <pre><code>
7212                 el.on({
7213                         'click': {
7214                         fn: this.onClick,
7215                         scope: this,
7216                         delay: 100
7217                 }, 
7218                 'mouseover': {
7219                         fn: this.onMouseOver,
7220                         scope: this
7221                 },
7222                 'mouseout': {
7223                         fn: this.onMouseOut,
7224                         scope: this
7225                 }
7226                 });
7227                 </code></pre>
7228      * <p>
7229      * Or a shorthand syntax which passes the same scope object to all handlers:
7230         <pre><code>
7231                 el.on({
7232                         'click': this.onClick,
7233                 'mouseover': this.onMouseOver,
7234                 'mouseout': this.onMouseOut,
7235                 scope: this
7236                 });
7237                 </code></pre>
7238      */
7239     addListener : function(eventName, fn, scope, o){
7240         if(typeof eventName == "object"){
7241             o = eventName;
7242             for(var e in o){
7243                 if(this.filterOptRe.test(e)){
7244                     continue;
7245                 }
7246                 if(typeof o[e] == "function"){
7247                     // shared options
7248                     this.addListener(e, o[e], o.scope,  o);
7249                 }else{
7250                     // individual options
7251                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7252                 }
7253             }
7254             return;
7255         }
7256         o = (!o || typeof o == "boolean") ? {} : o;
7257         eventName = eventName.toLowerCase();
7258         var ce = this.events[eventName] || true;
7259         if(typeof ce == "boolean"){
7260             ce = new Roo.util.Event(this, eventName);
7261             this.events[eventName] = ce;
7262         }
7263         ce.addListener(fn, scope, o);
7264     },
7265
7266     /**
7267      * Removes a listener
7268      * @param {String}   eventName     The type of event to listen for
7269      * @param {Function} handler        The handler to remove
7270      * @param {Object}   scope  (optional) The scope (this object) for the handler
7271      */
7272     removeListener : function(eventName, fn, scope){
7273         var ce = this.events[eventName.toLowerCase()];
7274         if(typeof ce == "object"){
7275             ce.removeListener(fn, scope);
7276         }
7277     },
7278
7279     /**
7280      * Removes all listeners for this object
7281      */
7282     purgeListeners : function(){
7283         for(var evt in this.events){
7284             if(typeof this.events[evt] == "object"){
7285                  this.events[evt].clearListeners();
7286             }
7287         }
7288     },
7289
7290     relayEvents : function(o, events){
7291         var createHandler = function(ename){
7292             return function(){
7293                  
7294                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7295             };
7296         };
7297         for(var i = 0, len = events.length; i < len; i++){
7298             var ename = events[i];
7299             if(!this.events[ename]){
7300                 this.events[ename] = true;
7301             };
7302             o.on(ename, createHandler(ename), this);
7303         }
7304     },
7305
7306     /**
7307      * Used to define events on this Observable
7308      * @param {Object} object The object with the events defined
7309      */
7310     addEvents : function(o){
7311         if(!this.events){
7312             this.events = {};
7313         }
7314         Roo.applyIf(this.events, o);
7315     },
7316
7317     /**
7318      * Checks to see if this object has any listeners for a specified event
7319      * @param {String} eventName The name of the event to check for
7320      * @return {Boolean} True if the event is being listened for, else false
7321      */
7322     hasListener : function(eventName){
7323         var e = this.events[eventName];
7324         return typeof e == "object" && e.listeners.length > 0;
7325     }
7326 };
7327 /**
7328  * Appends an event handler to this element (shorthand for addListener)
7329  * @param {String}   eventName     The type of event to listen for
7330  * @param {Function} handler        The method the event invokes
7331  * @param {Object}   scope (optional) The scope in which to execute the handler
7332  * function. The handler function's "this" context.
7333  * @param {Object}   options  (optional)
7334  * @method
7335  */
7336 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7337 /**
7338  * Removes a listener (shorthand for removeListener)
7339  * @param {String}   eventName     The type of event to listen for
7340  * @param {Function} handler        The handler to remove
7341  * @param {Object}   scope  (optional) The scope (this object) for the handler
7342  * @method
7343  */
7344 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7345
7346 /**
7347  * Starts capture on the specified Observable. All events will be passed
7348  * to the supplied function with the event name + standard signature of the event
7349  * <b>before</b> the event is fired. If the supplied function returns false,
7350  * the event will not fire.
7351  * @param {Observable} o The Observable to capture
7352  * @param {Function} fn The function to call
7353  * @param {Object} scope (optional) The scope (this object) for the fn
7354  * @static
7355  */
7356 Roo.util.Observable.capture = function(o, fn, scope){
7357     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7358 };
7359
7360 /**
7361  * Removes <b>all</b> added captures from the Observable.
7362  * @param {Observable} o The Observable to release
7363  * @static
7364  */
7365 Roo.util.Observable.releaseCapture = function(o){
7366     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7367 };
7368
7369 (function(){
7370
7371     var createBuffered = function(h, o, scope){
7372         var task = new Roo.util.DelayedTask();
7373         return function(){
7374             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7375         };
7376     };
7377
7378     var createSingle = function(h, e, fn, scope){
7379         return function(){
7380             e.removeListener(fn, scope);
7381             return h.apply(scope, arguments);
7382         };
7383     };
7384
7385     var createDelayed = function(h, o, scope){
7386         return function(){
7387             var args = Array.prototype.slice.call(arguments, 0);
7388             setTimeout(function(){
7389                 h.apply(scope, args);
7390             }, o.delay || 10);
7391         };
7392     };
7393
7394     Roo.util.Event = function(obj, name){
7395         this.name = name;
7396         this.obj = obj;
7397         this.listeners = [];
7398     };
7399
7400     Roo.util.Event.prototype = {
7401         addListener : function(fn, scope, options){
7402             var o = options || {};
7403             scope = scope || this.obj;
7404             if(!this.isListening(fn, scope)){
7405                 var l = {fn: fn, scope: scope, options: o};
7406                 var h = fn;
7407                 if(o.delay){
7408                     h = createDelayed(h, o, scope);
7409                 }
7410                 if(o.single){
7411                     h = createSingle(h, this, fn, scope);
7412                 }
7413                 if(o.buffer){
7414                     h = createBuffered(h, o, scope);
7415                 }
7416                 l.fireFn = h;
7417                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7418                     this.listeners.push(l);
7419                 }else{
7420                     this.listeners = this.listeners.slice(0);
7421                     this.listeners.push(l);
7422                 }
7423             }
7424         },
7425
7426         findListener : function(fn, scope){
7427             scope = scope || this.obj;
7428             var ls = this.listeners;
7429             for(var i = 0, len = ls.length; i < len; i++){
7430                 var l = ls[i];
7431                 if(l.fn == fn && l.scope == scope){
7432                     return i;
7433                 }
7434             }
7435             return -1;
7436         },
7437
7438         isListening : function(fn, scope){
7439             return this.findListener(fn, scope) != -1;
7440         },
7441
7442         removeListener : function(fn, scope){
7443             var index;
7444             if((index = this.findListener(fn, scope)) != -1){
7445                 if(!this.firing){
7446                     this.listeners.splice(index, 1);
7447                 }else{
7448                     this.listeners = this.listeners.slice(0);
7449                     this.listeners.splice(index, 1);
7450                 }
7451                 return true;
7452             }
7453             return false;
7454         },
7455
7456         clearListeners : function(){
7457             this.listeners = [];
7458         },
7459
7460         fire : function(){
7461             var ls = this.listeners, scope, len = ls.length;
7462             if(len > 0){
7463                 this.firing = true;
7464                 var args = Array.prototype.slice.call(arguments, 0);                
7465                 for(var i = 0; i < len; i++){
7466                     var l = ls[i];
7467                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7468                         this.firing = false;
7469                         return false;
7470                     }
7471                 }
7472                 this.firing = false;
7473             }
7474             return true;
7475         }
7476     };
7477 })();/*
7478  * RooJS Library 
7479  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7480  *
7481  * Licence LGPL 
7482  *
7483  */
7484  
7485 /**
7486  * @class Roo.Document
7487  * @extends Roo.util.Observable
7488  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7489  * 
7490  * @param {Object} config the methods and properties of the 'base' class for the application.
7491  * 
7492  *  Generic Page handler - implement this to start your app..
7493  * 
7494  * eg.
7495  *  MyProject = new Roo.Document({
7496         events : {
7497             'load' : true // your events..
7498         },
7499         listeners : {
7500             'ready' : function() {
7501                 // fired on Roo.onReady()
7502             }
7503         }
7504  * 
7505  */
7506 Roo.Document = function(cfg) {
7507      
7508     this.addEvents({ 
7509         'ready' : true
7510     });
7511     Roo.util.Observable.call(this,cfg);
7512     
7513     var _this = this;
7514     
7515     Roo.onReady(function() {
7516         _this.fireEvent('ready');
7517     },null,false);
7518     
7519     
7520 }
7521
7522 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7523  * Based on:
7524  * Ext JS Library 1.1.1
7525  * Copyright(c) 2006-2007, Ext JS, LLC.
7526  *
7527  * Originally Released Under LGPL - original licence link has changed is not relivant.
7528  *
7529  * Fork - LGPL
7530  * <script type="text/javascript">
7531  */
7532
7533 /**
7534  * @class Roo.EventManager
7535  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7536  * several useful events directly.
7537  * See {@link Roo.EventObject} for more details on normalized event objects.
7538  * @static
7539  */
7540 Roo.EventManager = function(){
7541     var docReadyEvent, docReadyProcId, docReadyState = false;
7542     var resizeEvent, resizeTask, textEvent, textSize;
7543     var E = Roo.lib.Event;
7544     var D = Roo.lib.Dom;
7545
7546     
7547     
7548
7549     var fireDocReady = function(){
7550         if(!docReadyState){
7551             docReadyState = true;
7552             Roo.isReady = true;
7553             if(docReadyProcId){
7554                 clearInterval(docReadyProcId);
7555             }
7556             if(Roo.isGecko || Roo.isOpera) {
7557                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7558             }
7559             if(Roo.isIE){
7560                 var defer = document.getElementById("ie-deferred-loader");
7561                 if(defer){
7562                     defer.onreadystatechange = null;
7563                     defer.parentNode.removeChild(defer);
7564                 }
7565             }
7566             if(docReadyEvent){
7567                 docReadyEvent.fire();
7568                 docReadyEvent.clearListeners();
7569             }
7570         }
7571     };
7572     
7573     var initDocReady = function(){
7574         docReadyEvent = new Roo.util.Event();
7575         if(Roo.isGecko || Roo.isOpera) {
7576             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7577         }else if(Roo.isIE){
7578             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7579             var defer = document.getElementById("ie-deferred-loader");
7580             defer.onreadystatechange = function(){
7581                 if(this.readyState == "complete"){
7582                     fireDocReady();
7583                 }
7584             };
7585         }else if(Roo.isSafari){ 
7586             docReadyProcId = setInterval(function(){
7587                 var rs = document.readyState;
7588                 if(rs == "complete") {
7589                     fireDocReady();     
7590                  }
7591             }, 10);
7592         }
7593         // no matter what, make sure it fires on load
7594         E.on(window, "load", fireDocReady);
7595     };
7596
7597     var createBuffered = function(h, o){
7598         var task = new Roo.util.DelayedTask(h);
7599         return function(e){
7600             // create new event object impl so new events don't wipe out properties
7601             e = new Roo.EventObjectImpl(e);
7602             task.delay(o.buffer, h, null, [e]);
7603         };
7604     };
7605
7606     var createSingle = function(h, el, ename, fn){
7607         return function(e){
7608             Roo.EventManager.removeListener(el, ename, fn);
7609             h(e);
7610         };
7611     };
7612
7613     var createDelayed = function(h, o){
7614         return function(e){
7615             // create new event object impl so new events don't wipe out properties
7616             e = new Roo.EventObjectImpl(e);
7617             setTimeout(function(){
7618                 h(e);
7619             }, o.delay || 10);
7620         };
7621     };
7622     var transitionEndVal = false;
7623     
7624     var transitionEnd = function()
7625     {
7626         if (transitionEndVal) {
7627             return transitionEndVal;
7628         }
7629         var el = document.createElement('div');
7630
7631         var transEndEventNames = {
7632             WebkitTransition : 'webkitTransitionEnd',
7633             MozTransition    : 'transitionend',
7634             OTransition      : 'oTransitionEnd otransitionend',
7635             transition       : 'transitionend'
7636         };
7637     
7638         for (var name in transEndEventNames) {
7639             if (el.style[name] !== undefined) {
7640                 transitionEndVal = transEndEventNames[name];
7641                 return  transitionEndVal ;
7642             }
7643         }
7644     }
7645     
7646   
7647
7648     var listen = function(element, ename, opt, fn, scope)
7649     {
7650         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7651         fn = fn || o.fn; scope = scope || o.scope;
7652         var el = Roo.getDom(element);
7653         
7654         
7655         if(!el){
7656             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7657         }
7658         
7659         if (ename == 'transitionend') {
7660             ename = transitionEnd();
7661         }
7662         var h = function(e){
7663             e = Roo.EventObject.setEvent(e);
7664             var t;
7665             if(o.delegate){
7666                 t = e.getTarget(o.delegate, el);
7667                 if(!t){
7668                     return;
7669                 }
7670             }else{
7671                 t = e.target;
7672             }
7673             if(o.stopEvent === true){
7674                 e.stopEvent();
7675             }
7676             if(o.preventDefault === true){
7677                e.preventDefault();
7678             }
7679             if(o.stopPropagation === true){
7680                 e.stopPropagation();
7681             }
7682
7683             if(o.normalized === false){
7684                 e = e.browserEvent;
7685             }
7686
7687             fn.call(scope || el, e, t, o);
7688         };
7689         if(o.delay){
7690             h = createDelayed(h, o);
7691         }
7692         if(o.single){
7693             h = createSingle(h, el, ename, fn);
7694         }
7695         if(o.buffer){
7696             h = createBuffered(h, o);
7697         }
7698         
7699         fn._handlers = fn._handlers || [];
7700         
7701         
7702         fn._handlers.push([Roo.id(el), ename, h]);
7703         
7704         
7705          
7706         E.on(el, ename, h); // this adds the actuall listener to the object..
7707         
7708         
7709         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7710             el.addEventListener("DOMMouseScroll", h, false);
7711             E.on(window, 'unload', function(){
7712                 el.removeEventListener("DOMMouseScroll", h, false);
7713             });
7714         }
7715         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7716             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7717         }
7718         return h;
7719     };
7720
7721     var stopListening = function(el, ename, fn){
7722         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7723         if(hds){
7724             for(var i = 0, len = hds.length; i < len; i++){
7725                 var h = hds[i];
7726                 if(h[0] == id && h[1] == ename){
7727                     hd = h[2];
7728                     hds.splice(i, 1);
7729                     break;
7730                 }
7731             }
7732         }
7733         E.un(el, ename, hd);
7734         el = Roo.getDom(el);
7735         if(ename == "mousewheel" && el.addEventListener){
7736             el.removeEventListener("DOMMouseScroll", hd, false);
7737         }
7738         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7739             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7740         }
7741     };
7742
7743     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7744     
7745     var pub = {
7746         
7747         
7748         /** 
7749          * Fix for doc tools
7750          * @scope Roo.EventManager
7751          */
7752         
7753         
7754         /** 
7755          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7756          * object with a Roo.EventObject
7757          * @param {Function} fn        The method the event invokes
7758          * @param {Object}   scope    An object that becomes the scope of the handler
7759          * @param {boolean}  override If true, the obj passed in becomes
7760          *                             the execution scope of the listener
7761          * @return {Function} The wrapped function
7762          * @deprecated
7763          */
7764         wrap : function(fn, scope, override){
7765             return function(e){
7766                 Roo.EventObject.setEvent(e);
7767                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7768             };
7769         },
7770         
7771         /**
7772      * Appends an event handler to an element (shorthand for addListener)
7773      * @param {String/HTMLElement}   element        The html element or id to assign the
7774      * @param {String}   eventName The type of event to listen for
7775      * @param {Function} handler The method the event invokes
7776      * @param {Object}   scope (optional) The scope in which to execute the handler
7777      * function. The handler function's "this" context.
7778      * @param {Object}   options (optional) An object containing handler configuration
7779      * properties. This may contain any of the following properties:<ul>
7780      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7781      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7782      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7783      * <li>preventDefault {Boolean} True to prevent the default action</li>
7784      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7785      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7786      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7787      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7788      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7789      * by the specified number of milliseconds. If the event fires again within that time, the original
7790      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7791      * </ul><br>
7792      * <p>
7793      * <b>Combining Options</b><br>
7794      * Using the options argument, it is possible to combine different types of listeners:<br>
7795      * <br>
7796      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7797      * Code:<pre><code>
7798 el.on('click', this.onClick, this, {
7799     single: true,
7800     delay: 100,
7801     stopEvent : true,
7802     forumId: 4
7803 });</code></pre>
7804      * <p>
7805      * <b>Attaching multiple handlers in 1 call</b><br>
7806       * The method also allows for a single argument to be passed which is a config object containing properties
7807      * which specify multiple handlers.
7808      * <p>
7809      * Code:<pre><code>
7810 el.on({
7811     'click' : {
7812         fn: this.onClick
7813         scope: this,
7814         delay: 100
7815     },
7816     'mouseover' : {
7817         fn: this.onMouseOver
7818         scope: this
7819     },
7820     'mouseout' : {
7821         fn: this.onMouseOut
7822         scope: this
7823     }
7824 });</code></pre>
7825      * <p>
7826      * Or a shorthand syntax:<br>
7827      * Code:<pre><code>
7828 el.on({
7829     'click' : this.onClick,
7830     'mouseover' : this.onMouseOver,
7831     'mouseout' : this.onMouseOut
7832     scope: this
7833 });</code></pre>
7834      */
7835         addListener : function(element, eventName, fn, scope, options){
7836             if(typeof eventName == "object"){
7837                 var o = eventName;
7838                 for(var e in o){
7839                     if(propRe.test(e)){
7840                         continue;
7841                     }
7842                     if(typeof o[e] == "function"){
7843                         // shared options
7844                         listen(element, e, o, o[e], o.scope);
7845                     }else{
7846                         // individual options
7847                         listen(element, e, o[e]);
7848                     }
7849                 }
7850                 return;
7851             }
7852             return listen(element, eventName, options, fn, scope);
7853         },
7854         
7855         /**
7856          * Removes an event handler
7857          *
7858          * @param {String/HTMLElement}   element        The id or html element to remove the 
7859          *                             event from
7860          * @param {String}   eventName     The type of event
7861          * @param {Function} fn
7862          * @return {Boolean} True if a listener was actually removed
7863          */
7864         removeListener : function(element, eventName, fn){
7865             return stopListening(element, eventName, fn);
7866         },
7867         
7868         /**
7869          * Fires when the document is ready (before onload and before images are loaded). Can be 
7870          * accessed shorthanded Roo.onReady().
7871          * @param {Function} fn        The method the event invokes
7872          * @param {Object}   scope    An  object that becomes the scope of the handler
7873          * @param {boolean}  options
7874          */
7875         onDocumentReady : function(fn, scope, options){
7876             if(docReadyState){ // if it already fired
7877                 docReadyEvent.addListener(fn, scope, options);
7878                 docReadyEvent.fire();
7879                 docReadyEvent.clearListeners();
7880                 return;
7881             }
7882             if(!docReadyEvent){
7883                 initDocReady();
7884             }
7885             docReadyEvent.addListener(fn, scope, options);
7886         },
7887         
7888         /**
7889          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7890          * @param {Function} fn        The method the event invokes
7891          * @param {Object}   scope    An object that becomes the scope of the handler
7892          * @param {boolean}  options
7893          */
7894         onWindowResize : function(fn, scope, options)
7895         {
7896             if(!resizeEvent){
7897                 resizeEvent = new Roo.util.Event();
7898                 resizeTask = new Roo.util.DelayedTask(function(){
7899                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7900                 });
7901                 E.on(window, "resize", function()
7902                 {
7903                     if (Roo.isIE) {
7904                         resizeTask.delay(50);
7905                     } else {
7906                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7907                     }
7908                 });
7909             }
7910             resizeEvent.addListener(fn, scope, options);
7911         },
7912
7913         /**
7914          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7915          * @param {Function} fn        The method the event invokes
7916          * @param {Object}   scope    An object that becomes the scope of the handler
7917          * @param {boolean}  options
7918          */
7919         onTextResize : function(fn, scope, options){
7920             if(!textEvent){
7921                 textEvent = new Roo.util.Event();
7922                 var textEl = new Roo.Element(document.createElement('div'));
7923                 textEl.dom.className = 'x-text-resize';
7924                 textEl.dom.innerHTML = 'X';
7925                 textEl.appendTo(document.body);
7926                 textSize = textEl.dom.offsetHeight;
7927                 setInterval(function(){
7928                     if(textEl.dom.offsetHeight != textSize){
7929                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7930                     }
7931                 }, this.textResizeInterval);
7932             }
7933             textEvent.addListener(fn, scope, options);
7934         },
7935
7936         /**
7937          * Removes the passed window resize listener.
7938          * @param {Function} fn        The method the event invokes
7939          * @param {Object}   scope    The scope of handler
7940          */
7941         removeResizeListener : function(fn, scope){
7942             if(resizeEvent){
7943                 resizeEvent.removeListener(fn, scope);
7944             }
7945         },
7946
7947         // private
7948         fireResize : function(){
7949             if(resizeEvent){
7950                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7951             }   
7952         },
7953         /**
7954          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7955          */
7956         ieDeferSrc : false,
7957         /**
7958          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7959          */
7960         textResizeInterval : 50
7961     };
7962     
7963     /**
7964      * Fix for doc tools
7965      * @scopeAlias pub=Roo.EventManager
7966      */
7967     
7968      /**
7969      * Appends an event handler to an element (shorthand for addListener)
7970      * @param {String/HTMLElement}   element        The html element or id to assign the
7971      * @param {String}   eventName The type of event to listen for
7972      * @param {Function} handler The method the event invokes
7973      * @param {Object}   scope (optional) The scope in which to execute the handler
7974      * function. The handler function's "this" context.
7975      * @param {Object}   options (optional) An object containing handler configuration
7976      * properties. This may contain any of the following properties:<ul>
7977      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7978      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7979      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7980      * <li>preventDefault {Boolean} True to prevent the default action</li>
7981      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7982      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7983      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7984      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7985      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7986      * by the specified number of milliseconds. If the event fires again within that time, the original
7987      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7988      * </ul><br>
7989      * <p>
7990      * <b>Combining Options</b><br>
7991      * Using the options argument, it is possible to combine different types of listeners:<br>
7992      * <br>
7993      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7994      * Code:<pre><code>
7995 el.on('click', this.onClick, this, {
7996     single: true,
7997     delay: 100,
7998     stopEvent : true,
7999     forumId: 4
8000 });</code></pre>
8001      * <p>
8002      * <b>Attaching multiple handlers in 1 call</b><br>
8003       * The method also allows for a single argument to be passed which is a config object containing properties
8004      * which specify multiple handlers.
8005      * <p>
8006      * Code:<pre><code>
8007 el.on({
8008     'click' : {
8009         fn: this.onClick
8010         scope: this,
8011         delay: 100
8012     },
8013     'mouseover' : {
8014         fn: this.onMouseOver
8015         scope: this
8016     },
8017     'mouseout' : {
8018         fn: this.onMouseOut
8019         scope: this
8020     }
8021 });</code></pre>
8022      * <p>
8023      * Or a shorthand syntax:<br>
8024      * Code:<pre><code>
8025 el.on({
8026     'click' : this.onClick,
8027     'mouseover' : this.onMouseOver,
8028     'mouseout' : this.onMouseOut
8029     scope: this
8030 });</code></pre>
8031      */
8032     pub.on = pub.addListener;
8033     pub.un = pub.removeListener;
8034
8035     pub.stoppedMouseDownEvent = new Roo.util.Event();
8036     return pub;
8037 }();
8038 /**
8039   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
8040   * @param {Function} fn        The method the event invokes
8041   * @param {Object}   scope    An  object that becomes the scope of the handler
8042   * @param {boolean}  override If true, the obj passed in becomes
8043   *                             the execution scope of the listener
8044   * @member Roo
8045   * @method onReady
8046  */
8047 Roo.onReady = Roo.EventManager.onDocumentReady;
8048
8049 Roo.onReady(function(){
8050     var bd = Roo.get(document.body);
8051     if(!bd){ return; }
8052
8053     var cls = [
8054             Roo.isIE ? "roo-ie"
8055             : Roo.isIE11 ? "roo-ie11"
8056             : Roo.isEdge ? "roo-edge"
8057             : Roo.isGecko ? "roo-gecko"
8058             : Roo.isOpera ? "roo-opera"
8059             : Roo.isSafari ? "roo-safari" : ""];
8060
8061     if(Roo.isMac){
8062         cls.push("roo-mac");
8063     }
8064     if(Roo.isLinux){
8065         cls.push("roo-linux");
8066     }
8067     if(Roo.isIOS){
8068         cls.push("roo-ios");
8069     }
8070     if(Roo.isTouch){
8071         cls.push("roo-touch");
8072     }
8073     if(Roo.isBorderBox){
8074         cls.push('roo-border-box');
8075     }
8076     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8077         var p = bd.dom.parentNode;
8078         if(p){
8079             p.className += ' roo-strict';
8080         }
8081     }
8082     bd.addClass(cls.join(' '));
8083 });
8084
8085 /**
8086  * @class Roo.EventObject
8087  * EventObject exposes the Yahoo! UI Event functionality directly on the object
8088  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
8089  * Example:
8090  * <pre><code>
8091  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8092     e.preventDefault();
8093     var target = e.getTarget();
8094     ...
8095  }
8096  var myDiv = Roo.get("myDiv");
8097  myDiv.on("click", handleClick);
8098  //or
8099  Roo.EventManager.on("myDiv", 'click', handleClick);
8100  Roo.EventManager.addListener("myDiv", 'click', handleClick);
8101  </code></pre>
8102  * @static
8103  */
8104 Roo.EventObject = function(){
8105     
8106     var E = Roo.lib.Event;
8107     
8108     // safari keypress events for special keys return bad keycodes
8109     var safariKeys = {
8110         63234 : 37, // left
8111         63235 : 39, // right
8112         63232 : 38, // up
8113         63233 : 40, // down
8114         63276 : 33, // page up
8115         63277 : 34, // page down
8116         63272 : 46, // delete
8117         63273 : 36, // home
8118         63275 : 35  // end
8119     };
8120
8121     // normalize button clicks
8122     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8123                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8124
8125     Roo.EventObjectImpl = function(e){
8126         if(e){
8127             this.setEvent(e.browserEvent || e);
8128         }
8129     };
8130     Roo.EventObjectImpl.prototype = {
8131         /**
8132          * Used to fix doc tools.
8133          * @scope Roo.EventObject.prototype
8134          */
8135             
8136
8137         
8138         
8139         /** The normal browser event */
8140         browserEvent : null,
8141         /** The button pressed in a mouse event */
8142         button : -1,
8143         /** True if the shift key was down during the event */
8144         shiftKey : false,
8145         /** True if the control key was down during the event */
8146         ctrlKey : false,
8147         /** True if the alt key was down during the event */
8148         altKey : false,
8149
8150         /** Key constant 
8151         * @type Number */
8152         BACKSPACE : 8,
8153         /** Key constant 
8154         * @type Number */
8155         TAB : 9,
8156         /** Key constant 
8157         * @type Number */
8158         RETURN : 13,
8159         /** Key constant 
8160         * @type Number */
8161         ENTER : 13,
8162         /** Key constant 
8163         * @type Number */
8164         SHIFT : 16,
8165         /** Key constant 
8166         * @type Number */
8167         CONTROL : 17,
8168         /** Key constant 
8169         * @type Number */
8170         ESC : 27,
8171         /** Key constant 
8172         * @type Number */
8173         SPACE : 32,
8174         /** Key constant 
8175         * @type Number */
8176         PAGEUP : 33,
8177         /** Key constant 
8178         * @type Number */
8179         PAGEDOWN : 34,
8180         /** Key constant 
8181         * @type Number */
8182         END : 35,
8183         /** Key constant 
8184         * @type Number */
8185         HOME : 36,
8186         /** Key constant 
8187         * @type Number */
8188         LEFT : 37,
8189         /** Key constant 
8190         * @type Number */
8191         UP : 38,
8192         /** Key constant 
8193         * @type Number */
8194         RIGHT : 39,
8195         /** Key constant 
8196         * @type Number */
8197         DOWN : 40,
8198         /** Key constant 
8199         * @type Number */
8200         DELETE : 46,
8201         /** Key constant 
8202         * @type Number */
8203         F5 : 116,
8204
8205            /** @private */
8206         setEvent : function(e){
8207             if(e == this || (e && e.browserEvent)){ // already wrapped
8208                 return e;
8209             }
8210             this.browserEvent = e;
8211             if(e){
8212                 // normalize buttons
8213                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8214                 if(e.type == 'click' && this.button == -1){
8215                     this.button = 0;
8216                 }
8217                 this.type = e.type;
8218                 this.shiftKey = e.shiftKey;
8219                 // mac metaKey behaves like ctrlKey
8220                 this.ctrlKey = e.ctrlKey || e.metaKey;
8221                 this.altKey = e.altKey;
8222                 // in getKey these will be normalized for the mac
8223                 this.keyCode = e.keyCode;
8224                 // keyup warnings on firefox.
8225                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8226                 // cache the target for the delayed and or buffered events
8227                 this.target = E.getTarget(e);
8228                 // same for XY
8229                 this.xy = E.getXY(e);
8230             }else{
8231                 this.button = -1;
8232                 this.shiftKey = false;
8233                 this.ctrlKey = false;
8234                 this.altKey = false;
8235                 this.keyCode = 0;
8236                 this.charCode =0;
8237                 this.target = null;
8238                 this.xy = [0, 0];
8239             }
8240             return this;
8241         },
8242
8243         /**
8244          * Stop the event (preventDefault and stopPropagation)
8245          */
8246         stopEvent : function(){
8247             if(this.browserEvent){
8248                 if(this.browserEvent.type == 'mousedown'){
8249                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8250                 }
8251                 E.stopEvent(this.browserEvent);
8252             }
8253         },
8254
8255         /**
8256          * Prevents the browsers default handling of the event.
8257          */
8258         preventDefault : function(){
8259             if(this.browserEvent){
8260                 E.preventDefault(this.browserEvent);
8261             }
8262         },
8263
8264         /** @private */
8265         isNavKeyPress : function(){
8266             var k = this.keyCode;
8267             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8268             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8269         },
8270
8271         isSpecialKey : function(){
8272             var k = this.keyCode;
8273             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8274             (k == 16) || (k == 17) ||
8275             (k >= 18 && k <= 20) ||
8276             (k >= 33 && k <= 35) ||
8277             (k >= 36 && k <= 39) ||
8278             (k >= 44 && k <= 45);
8279         },
8280         /**
8281          * Cancels bubbling of the event.
8282          */
8283         stopPropagation : function(){
8284             if(this.browserEvent){
8285                 if(this.type == 'mousedown'){
8286                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8287                 }
8288                 E.stopPropagation(this.browserEvent);
8289             }
8290         },
8291
8292         /**
8293          * Gets the key code for the event.
8294          * @return {Number}
8295          */
8296         getCharCode : function(){
8297             return this.charCode || this.keyCode;
8298         },
8299
8300         /**
8301          * Returns a normalized keyCode for the event.
8302          * @return {Number} The key code
8303          */
8304         getKey : function(){
8305             var k = this.keyCode || this.charCode;
8306             return Roo.isSafari ? (safariKeys[k] || k) : k;
8307         },
8308
8309         /**
8310          * Gets the x coordinate of the event.
8311          * @return {Number}
8312          */
8313         getPageX : function(){
8314             return this.xy[0];
8315         },
8316
8317         /**
8318          * Gets the y coordinate of the event.
8319          * @return {Number}
8320          */
8321         getPageY : function(){
8322             return this.xy[1];
8323         },
8324
8325         /**
8326          * Gets the time of the event.
8327          * @return {Number}
8328          */
8329         getTime : function(){
8330             if(this.browserEvent){
8331                 return E.getTime(this.browserEvent);
8332             }
8333             return null;
8334         },
8335
8336         /**
8337          * Gets the page coordinates of the event.
8338          * @return {Array} The xy values like [x, y]
8339          */
8340         getXY : function(){
8341             return this.xy;
8342         },
8343
8344         /**
8345          * Gets the target for the event.
8346          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8347          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8348                 search as a number or element (defaults to 10 || document.body)
8349          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8350          * @return {HTMLelement}
8351          */
8352         getTarget : function(selector, maxDepth, returnEl){
8353             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8354         },
8355         /**
8356          * Gets the related target.
8357          * @return {HTMLElement}
8358          */
8359         getRelatedTarget : function(){
8360             if(this.browserEvent){
8361                 return E.getRelatedTarget(this.browserEvent);
8362             }
8363             return null;
8364         },
8365
8366         /**
8367          * Normalizes mouse wheel delta across browsers
8368          * @return {Number} The delta
8369          */
8370         getWheelDelta : function(){
8371             var e = this.browserEvent;
8372             var delta = 0;
8373             if(e.wheelDelta){ /* IE/Opera. */
8374                 delta = e.wheelDelta/120;
8375             }else if(e.detail){ /* Mozilla case. */
8376                 delta = -e.detail/3;
8377             }
8378             return delta;
8379         },
8380
8381         /**
8382          * Returns true if the control, meta, shift or alt key was pressed during this event.
8383          * @return {Boolean}
8384          */
8385         hasModifier : function(){
8386             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8387         },
8388
8389         /**
8390          * Returns true if the target of this event equals el or is a child of el
8391          * @param {String/HTMLElement/Element} el
8392          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8393          * @return {Boolean}
8394          */
8395         within : function(el, related){
8396             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8397             return t && Roo.fly(el).contains(t);
8398         },
8399
8400         getPoint : function(){
8401             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8402         }
8403     };
8404
8405     return new Roo.EventObjectImpl();
8406 }();
8407             
8408     /*
8409  * Based on:
8410  * Ext JS Library 1.1.1
8411  * Copyright(c) 2006-2007, Ext JS, LLC.
8412  *
8413  * Originally Released Under LGPL - original licence link has changed is not relivant.
8414  *
8415  * Fork - LGPL
8416  * <script type="text/javascript">
8417  */
8418
8419  
8420 // was in Composite Element!??!?!
8421  
8422 (function(){
8423     var D = Roo.lib.Dom;
8424     var E = Roo.lib.Event;
8425     var A = Roo.lib.Anim;
8426
8427     // local style camelizing for speed
8428     var propCache = {};
8429     var camelRe = /(-[a-z])/gi;
8430     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8431     var view = document.defaultView;
8432
8433 /**
8434  * @class Roo.Element
8435  * Represents an Element in the DOM.<br><br>
8436  * Usage:<br>
8437 <pre><code>
8438 var el = Roo.get("my-div");
8439
8440 // or with getEl
8441 var el = getEl("my-div");
8442
8443 // or with a DOM element
8444 var el = Roo.get(myDivElement);
8445 </code></pre>
8446  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8447  * each call instead of constructing a new one.<br><br>
8448  * <b>Animations</b><br />
8449  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8450  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8451 <pre>
8452 Option    Default   Description
8453 --------- --------  ---------------------------------------------
8454 duration  .35       The duration of the animation in seconds
8455 easing    easeOut   The YUI easing method
8456 callback  none      A function to execute when the anim completes
8457 scope     this      The scope (this) of the callback function
8458 </pre>
8459 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8460 * manipulate the animation. Here's an example:
8461 <pre><code>
8462 var el = Roo.get("my-div");
8463
8464 // no animation
8465 el.setWidth(100);
8466
8467 // default animation
8468 el.setWidth(100, true);
8469
8470 // animation with some options set
8471 el.setWidth(100, {
8472     duration: 1,
8473     callback: this.foo,
8474     scope: this
8475 });
8476
8477 // using the "anim" property to get the Anim object
8478 var opt = {
8479     duration: 1,
8480     callback: this.foo,
8481     scope: this
8482 };
8483 el.setWidth(100, opt);
8484 ...
8485 if(opt.anim.isAnimated()){
8486     opt.anim.stop();
8487 }
8488 </code></pre>
8489 * <b> Composite (Collections of) Elements</b><br />
8490  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8491  * @constructor Create a new Element directly.
8492  * @param {String/HTMLElement} element
8493  * @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).
8494  */
8495     Roo.Element = function(element, forceNew)
8496     {
8497         var dom = typeof element == "string" ?
8498                 document.getElementById(element) : element;
8499         
8500         this.listeners = {};
8501         
8502         if(!dom){ // invalid id/element
8503             return null;
8504         }
8505         var id = dom.id;
8506         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8507             return Roo.Element.cache[id];
8508         }
8509
8510         /**
8511          * The DOM element
8512          * @type HTMLElement
8513          */
8514         this.dom = dom;
8515
8516         /**
8517          * The DOM element ID
8518          * @type String
8519          */
8520         this.id = id || Roo.id(dom);
8521         
8522         return this; // assumed for cctor?
8523     };
8524
8525     var El = Roo.Element;
8526
8527     El.prototype = {
8528         /**
8529          * The element's default display mode  (defaults to "") 
8530          * @type String
8531          */
8532         originalDisplay : "",
8533
8534         
8535         // note this is overridden in BS version..
8536         visibilityMode : 1, 
8537         /**
8538          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8539          * @type String
8540          */
8541         defaultUnit : "px",
8542         
8543         /**
8544          * Sets the element's visibility mode. When setVisible() is called it
8545          * will use this to determine whether to set the visibility or the display property.
8546          * @param visMode Element.VISIBILITY or Element.DISPLAY
8547          * @return {Roo.Element} this
8548          */
8549         setVisibilityMode : function(visMode){
8550             this.visibilityMode = visMode;
8551             return this;
8552         },
8553         /**
8554          * Convenience method for setVisibilityMode(Element.DISPLAY)
8555          * @param {String} display (optional) What to set display to when visible
8556          * @return {Roo.Element} this
8557          */
8558         enableDisplayMode : function(display){
8559             this.setVisibilityMode(El.DISPLAY);
8560             if(typeof display != "undefined") { this.originalDisplay = display; }
8561             return this;
8562         },
8563
8564         /**
8565          * 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)
8566          * @param {String} selector The simple selector to test
8567          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8568                 search as a number or element (defaults to 10 || document.body)
8569          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8570          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8571          */
8572         findParent : function(simpleSelector, maxDepth, returnEl){
8573             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8574             maxDepth = maxDepth || 50;
8575             if(typeof maxDepth != "number"){
8576                 stopEl = Roo.getDom(maxDepth);
8577                 maxDepth = 10;
8578             }
8579             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8580                 if(dq.is(p, simpleSelector)){
8581                     return returnEl ? Roo.get(p) : p;
8582                 }
8583                 depth++;
8584                 p = p.parentNode;
8585             }
8586             return null;
8587         },
8588
8589
8590         /**
8591          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8592          * @param {String} selector The simple selector to test
8593          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8594                 search as a number or element (defaults to 10 || document.body)
8595          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8596          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8597          */
8598         findParentNode : function(simpleSelector, maxDepth, returnEl){
8599             var p = Roo.fly(this.dom.parentNode, '_internal');
8600             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8601         },
8602         
8603         /**
8604          * Looks at  the scrollable parent element
8605          */
8606         findScrollableParent : function()
8607         {
8608             var overflowRegex = /(auto|scroll)/;
8609             
8610             if(this.getStyle('position') === 'fixed'){
8611                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8612             }
8613             
8614             var excludeStaticParent = this.getStyle('position') === "absolute";
8615             
8616             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8617                 
8618                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8619                     continue;
8620                 }
8621                 
8622                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8623                     return parent;
8624                 }
8625                 
8626                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8627                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8628                 }
8629             }
8630             
8631             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8632         },
8633
8634         /**
8635          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8636          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8637          * @param {String} selector The simple selector to test
8638          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8639                 search as a number or element (defaults to 10 || document.body)
8640          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8641          */
8642         up : function(simpleSelector, maxDepth){
8643             return this.findParentNode(simpleSelector, maxDepth, true);
8644         },
8645
8646
8647
8648         /**
8649          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8650          * @param {String} selector The simple selector to test
8651          * @return {Boolean} True if this element matches the selector, else false
8652          */
8653         is : function(simpleSelector){
8654             return Roo.DomQuery.is(this.dom, simpleSelector);
8655         },
8656
8657         /**
8658          * Perform animation on this element.
8659          * @param {Object} args The YUI animation control args
8660          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8661          * @param {Function} onComplete (optional) Function to call when animation completes
8662          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8663          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8664          * @return {Roo.Element} this
8665          */
8666         animate : function(args, duration, onComplete, easing, animType){
8667             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8668             return this;
8669         },
8670
8671         /*
8672          * @private Internal animation call
8673          */
8674         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8675             animType = animType || 'run';
8676             opt = opt || {};
8677             var anim = Roo.lib.Anim[animType](
8678                 this.dom, args,
8679                 (opt.duration || defaultDur) || .35,
8680                 (opt.easing || defaultEase) || 'easeOut',
8681                 function(){
8682                     Roo.callback(cb, this);
8683                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8684                 },
8685                 this
8686             );
8687             opt.anim = anim;
8688             return anim;
8689         },
8690
8691         // private legacy anim prep
8692         preanim : function(a, i){
8693             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8694         },
8695
8696         /**
8697          * Removes worthless text nodes
8698          * @param {Boolean} forceReclean (optional) By default the element
8699          * keeps track if it has been cleaned already so
8700          * you can call this over and over. However, if you update the element and
8701          * need to force a reclean, you can pass true.
8702          */
8703         clean : function(forceReclean){
8704             if(this.isCleaned && forceReclean !== true){
8705                 return this;
8706             }
8707             var ns = /\S/;
8708             var d = this.dom, n = d.firstChild, ni = -1;
8709             while(n){
8710                 var nx = n.nextSibling;
8711                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8712                     d.removeChild(n);
8713                 }else{
8714                     n.nodeIndex = ++ni;
8715                 }
8716                 n = nx;
8717             }
8718             this.isCleaned = true;
8719             return this;
8720         },
8721
8722         // private
8723         calcOffsetsTo : function(el){
8724             el = Roo.get(el);
8725             var d = el.dom;
8726             var restorePos = false;
8727             if(el.getStyle('position') == 'static'){
8728                 el.position('relative');
8729                 restorePos = true;
8730             }
8731             var x = 0, y =0;
8732             var op = this.dom;
8733             while(op && op != d && op.tagName != 'HTML'){
8734                 x+= op.offsetLeft;
8735                 y+= op.offsetTop;
8736                 op = op.offsetParent;
8737             }
8738             if(restorePos){
8739                 el.position('static');
8740             }
8741             return [x, y];
8742         },
8743
8744         /**
8745          * Scrolls this element into view within the passed container.
8746          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8747          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8748          * @return {Roo.Element} this
8749          */
8750         scrollIntoView : function(container, hscroll){
8751             var c = Roo.getDom(container) || document.body;
8752             var el = this.dom;
8753
8754             var o = this.calcOffsetsTo(c),
8755                 l = o[0],
8756                 t = o[1],
8757                 b = t+el.offsetHeight,
8758                 r = l+el.offsetWidth;
8759
8760             var ch = c.clientHeight;
8761             var ct = parseInt(c.scrollTop, 10);
8762             var cl = parseInt(c.scrollLeft, 10);
8763             var cb = ct + ch;
8764             var cr = cl + c.clientWidth;
8765
8766             if(t < ct){
8767                 c.scrollTop = t;
8768             }else if(b > cb){
8769                 c.scrollTop = b-ch;
8770             }
8771
8772             if(hscroll !== false){
8773                 if(l < cl){
8774                     c.scrollLeft = l;
8775                 }else if(r > cr){
8776                     c.scrollLeft = r-c.clientWidth;
8777                 }
8778             }
8779             return this;
8780         },
8781
8782         // private
8783         scrollChildIntoView : function(child, hscroll){
8784             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8785         },
8786
8787         /**
8788          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8789          * the new height may not be available immediately.
8790          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8791          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8792          * @param {Function} onComplete (optional) Function to call when animation completes
8793          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8794          * @return {Roo.Element} this
8795          */
8796         autoHeight : function(animate, duration, onComplete, easing){
8797             var oldHeight = this.getHeight();
8798             this.clip();
8799             this.setHeight(1); // force clipping
8800             setTimeout(function(){
8801                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8802                 if(!animate){
8803                     this.setHeight(height);
8804                     this.unclip();
8805                     if(typeof onComplete == "function"){
8806                         onComplete();
8807                     }
8808                 }else{
8809                     this.setHeight(oldHeight); // restore original height
8810                     this.setHeight(height, animate, duration, function(){
8811                         this.unclip();
8812                         if(typeof onComplete == "function") { onComplete(); }
8813                     }.createDelegate(this), easing);
8814                 }
8815             }.createDelegate(this), 0);
8816             return this;
8817         },
8818
8819         /**
8820          * Returns true if this element is an ancestor of the passed element
8821          * @param {HTMLElement/String} el The element to check
8822          * @return {Boolean} True if this element is an ancestor of el, else false
8823          */
8824         contains : function(el){
8825             if(!el){return false;}
8826             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8827         },
8828
8829         /**
8830          * Checks whether the element is currently visible using both visibility and display properties.
8831          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8832          * @return {Boolean} True if the element is currently visible, else false
8833          */
8834         isVisible : function(deep) {
8835             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8836             if(deep !== true || !vis){
8837                 return vis;
8838             }
8839             var p = this.dom.parentNode;
8840             while(p && p.tagName.toLowerCase() != "body"){
8841                 if(!Roo.fly(p, '_isVisible').isVisible()){
8842                     return false;
8843                 }
8844                 p = p.parentNode;
8845             }
8846             return true;
8847         },
8848
8849         /**
8850          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8851          * @param {String} selector The CSS selector
8852          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8853          * @return {CompositeElement/CompositeElementLite} The composite element
8854          */
8855         select : function(selector, unique){
8856             return El.select(selector, unique, this.dom);
8857         },
8858
8859         /**
8860          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8861          * @param {String} selector The CSS selector
8862          * @return {Array} An array of the matched nodes
8863          */
8864         query : function(selector, unique){
8865             return Roo.DomQuery.select(selector, this.dom);
8866         },
8867
8868         /**
8869          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8870          * @param {String} selector The CSS selector
8871          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8872          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8873          */
8874         child : function(selector, returnDom){
8875             var n = Roo.DomQuery.selectNode(selector, this.dom);
8876             return returnDom ? n : Roo.get(n);
8877         },
8878
8879         /**
8880          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8881          * @param {String} selector The CSS selector
8882          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8883          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8884          */
8885         down : function(selector, returnDom){
8886             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8887             return returnDom ? n : Roo.get(n);
8888         },
8889
8890         /**
8891          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8892          * @param {String} group The group the DD object is member of
8893          * @param {Object} config The DD config object
8894          * @param {Object} overrides An object containing methods to override/implement on the DD object
8895          * @return {Roo.dd.DD} The DD object
8896          */
8897         initDD : function(group, config, overrides){
8898             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8899             return Roo.apply(dd, overrides);
8900         },
8901
8902         /**
8903          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8904          * @param {String} group The group the DDProxy object is member of
8905          * @param {Object} config The DDProxy config object
8906          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8907          * @return {Roo.dd.DDProxy} The DDProxy object
8908          */
8909         initDDProxy : function(group, config, overrides){
8910             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8911             return Roo.apply(dd, overrides);
8912         },
8913
8914         /**
8915          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8916          * @param {String} group The group the DDTarget object is member of
8917          * @param {Object} config The DDTarget config object
8918          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8919          * @return {Roo.dd.DDTarget} The DDTarget object
8920          */
8921         initDDTarget : function(group, config, overrides){
8922             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8923             return Roo.apply(dd, overrides);
8924         },
8925
8926         /**
8927          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8928          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8929          * @param {Boolean} visible Whether the element is visible
8930          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8931          * @return {Roo.Element} this
8932          */
8933          setVisible : function(visible, animate){
8934             if(!animate || !A){
8935                 if(this.visibilityMode == El.DISPLAY){
8936                     this.setDisplayed(visible);
8937                 }else{
8938                     this.fixDisplay();
8939                     this.dom.style.visibility = visible ? "visible" : "hidden";
8940                 }
8941             }else{
8942                 // closure for composites
8943                 var dom = this.dom;
8944                 var visMode = this.visibilityMode;
8945                 if(visible){
8946                     this.setOpacity(.01);
8947                     this.setVisible(true);
8948                 }
8949                 this.anim({opacity: { to: (visible?1:0) }},
8950                       this.preanim(arguments, 1),
8951                       null, .35, 'easeIn', function(){
8952                          if(!visible){
8953                              if(visMode == El.DISPLAY){
8954                                  dom.style.display = "none";
8955                              }else{
8956                                  dom.style.visibility = "hidden";
8957                              }
8958                              Roo.get(dom).setOpacity(1);
8959                          }
8960                      });
8961             }
8962             return this;
8963         },
8964
8965         /**
8966          * Returns true if display is not "none"
8967          * @return {Boolean}
8968          */
8969         isDisplayed : function() {
8970             return this.getStyle("display") != "none";
8971         },
8972
8973         /**
8974          * Toggles the element's visibility or display, depending on visibility mode.
8975          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8976          * @return {Roo.Element} this
8977          */
8978         toggle : function(animate){
8979             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8980             return this;
8981         },
8982
8983         /**
8984          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8985          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8986          * @return {Roo.Element} this
8987          */
8988         setDisplayed : function(value) {
8989             if(typeof value == "boolean"){
8990                value = value ? this.originalDisplay : "none";
8991             }
8992             this.setStyle("display", value);
8993             return this;
8994         },
8995
8996         /**
8997          * Tries to focus the element. Any exceptions are caught and ignored.
8998          * @return {Roo.Element} this
8999          */
9000         focus : function() {
9001             try{
9002                 this.dom.focus();
9003             }catch(e){}
9004             return this;
9005         },
9006
9007         /**
9008          * Tries to blur the element. Any exceptions are caught and ignored.
9009          * @return {Roo.Element} this
9010          */
9011         blur : function() {
9012             try{
9013                 this.dom.blur();
9014             }catch(e){}
9015             return this;
9016         },
9017
9018         /**
9019          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
9020          * @param {String/Array} className The CSS class to add, or an array of classes
9021          * @return {Roo.Element} this
9022          */
9023         addClass : function(className){
9024             if(className instanceof Array){
9025                 for(var i = 0, len = className.length; i < len; i++) {
9026                     this.addClass(className[i]);
9027                 }
9028             }else{
9029                 if(className && !this.hasClass(className)){
9030                     if (this.dom instanceof SVGElement) {
9031                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
9032                     } else {
9033                         this.dom.className = this.dom.className + " " + className;
9034                     }
9035                 }
9036             }
9037             return this;
9038         },
9039
9040         /**
9041          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9042          * @param {String/Array} className The CSS class to add, or an array of classes
9043          * @return {Roo.Element} this
9044          */
9045         radioClass : function(className){
9046             var siblings = this.dom.parentNode.childNodes;
9047             for(var i = 0; i < siblings.length; i++) {
9048                 var s = siblings[i];
9049                 if(s.nodeType == 1){
9050                     Roo.get(s).removeClass(className);
9051                 }
9052             }
9053             this.addClass(className);
9054             return this;
9055         },
9056
9057         /**
9058          * Removes one or more CSS classes from the element.
9059          * @param {String/Array} className The CSS class to remove, or an array of classes
9060          * @return {Roo.Element} this
9061          */
9062         removeClass : function(className){
9063             
9064             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9065             if(!className || !cn){
9066                 return this;
9067             }
9068             if(className instanceof Array){
9069                 for(var i = 0, len = className.length; i < len; i++) {
9070                     this.removeClass(className[i]);
9071                 }
9072             }else{
9073                 if(this.hasClass(className)){
9074                     var re = this.classReCache[className];
9075                     if (!re) {
9076                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9077                        this.classReCache[className] = re;
9078                     }
9079                     if (this.dom instanceof SVGElement) {
9080                         this.dom.className.baseVal = cn.replace(re, " ");
9081                     } else {
9082                         this.dom.className = cn.replace(re, " ");
9083                     }
9084                 }
9085             }
9086             return this;
9087         },
9088
9089         // private
9090         classReCache: {},
9091
9092         /**
9093          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9094          * @param {String} className The CSS class to toggle
9095          * @return {Roo.Element} this
9096          */
9097         toggleClass : function(className){
9098             if(this.hasClass(className)){
9099                 this.removeClass(className);
9100             }else{
9101                 this.addClass(className);
9102             }
9103             return this;
9104         },
9105
9106         /**
9107          * Checks if the specified CSS class exists on this element's DOM node.
9108          * @param {String} className The CSS class to check for
9109          * @return {Boolean} True if the class exists, else false
9110          */
9111         hasClass : function(className){
9112             if (this.dom instanceof SVGElement) {
9113                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
9114             } 
9115             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9116         },
9117
9118         /**
9119          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
9120          * @param {String} oldClassName The CSS class to replace
9121          * @param {String} newClassName The replacement CSS class
9122          * @return {Roo.Element} this
9123          */
9124         replaceClass : function(oldClassName, newClassName){
9125             this.removeClass(oldClassName);
9126             this.addClass(newClassName);
9127             return this;
9128         },
9129
9130         /**
9131          * Returns an object with properties matching the styles requested.
9132          * For example, el.getStyles('color', 'font-size', 'width') might return
9133          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9134          * @param {String} style1 A style name
9135          * @param {String} style2 A style name
9136          * @param {String} etc.
9137          * @return {Object} The style object
9138          */
9139         getStyles : function(){
9140             var a = arguments, len = a.length, r = {};
9141             for(var i = 0; i < len; i++){
9142                 r[a[i]] = this.getStyle(a[i]);
9143             }
9144             return r;
9145         },
9146
9147         /**
9148          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9149          * @param {String} property The style property whose value is returned.
9150          * @return {String} The current value of the style property for this element.
9151          */
9152         getStyle : function(){
9153             return view && view.getComputedStyle ?
9154                 function(prop){
9155                     var el = this.dom, v, cs, camel;
9156                     if(prop == 'float'){
9157                         prop = "cssFloat";
9158                     }
9159                     if(el.style && (v = el.style[prop])){
9160                         return v;
9161                     }
9162                     if(cs = view.getComputedStyle(el, "")){
9163                         if(!(camel = propCache[prop])){
9164                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
9165                         }
9166                         return cs[camel];
9167                     }
9168                     return null;
9169                 } :
9170                 function(prop){
9171                     var el = this.dom, v, cs, camel;
9172                     if(prop == 'opacity'){
9173                         if(typeof el.style.filter == 'string'){
9174                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9175                             if(m){
9176                                 var fv = parseFloat(m[1]);
9177                                 if(!isNaN(fv)){
9178                                     return fv ? fv / 100 : 0;
9179                                 }
9180                             }
9181                         }
9182                         return 1;
9183                     }else if(prop == 'float'){
9184                         prop = "styleFloat";
9185                     }
9186                     if(!(camel = propCache[prop])){
9187                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
9188                     }
9189                     if(v = el.style[camel]){
9190                         return v;
9191                     }
9192                     if(cs = el.currentStyle){
9193                         return cs[camel];
9194                     }
9195                     return null;
9196                 };
9197         }(),
9198
9199         /**
9200          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9201          * @param {String/Object} property The style property to be set, or an object of multiple styles.
9202          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9203          * @return {Roo.Element} this
9204          */
9205         setStyle : function(prop, value){
9206             if(typeof prop == "string"){
9207                 
9208                 if (prop == 'float') {
9209                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9210                     return this;
9211                 }
9212                 
9213                 var camel;
9214                 if(!(camel = propCache[prop])){
9215                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9216                 }
9217                 
9218                 if(camel == 'opacity') {
9219                     this.setOpacity(value);
9220                 }else{
9221                     this.dom.style[camel] = value;
9222                 }
9223             }else{
9224                 for(var style in prop){
9225                     if(typeof prop[style] != "function"){
9226                        this.setStyle(style, prop[style]);
9227                     }
9228                 }
9229             }
9230             return this;
9231         },
9232
9233         /**
9234          * More flexible version of {@link #setStyle} for setting style properties.
9235          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9236          * a function which returns such a specification.
9237          * @return {Roo.Element} this
9238          */
9239         applyStyles : function(style){
9240             Roo.DomHelper.applyStyles(this.dom, style);
9241             return this;
9242         },
9243
9244         /**
9245           * 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).
9246           * @return {Number} The X position of the element
9247           */
9248         getX : function(){
9249             return D.getX(this.dom);
9250         },
9251
9252         /**
9253           * 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).
9254           * @return {Number} The Y position of the element
9255           */
9256         getY : function(){
9257             return D.getY(this.dom);
9258         },
9259
9260         /**
9261           * 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).
9262           * @return {Array} The XY position of the element
9263           */
9264         getXY : function(){
9265             return D.getXY(this.dom);
9266         },
9267
9268         /**
9269          * 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).
9270          * @param {Number} The X position of the element
9271          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9272          * @return {Roo.Element} this
9273          */
9274         setX : function(x, animate){
9275             if(!animate || !A){
9276                 D.setX(this.dom, x);
9277             }else{
9278                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9279             }
9280             return this;
9281         },
9282
9283         /**
9284          * 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).
9285          * @param {Number} The Y position of the element
9286          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9287          * @return {Roo.Element} this
9288          */
9289         setY : function(y, animate){
9290             if(!animate || !A){
9291                 D.setY(this.dom, y);
9292             }else{
9293                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9294             }
9295             return this;
9296         },
9297
9298         /**
9299          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9300          * @param {String} left The left CSS property value
9301          * @return {Roo.Element} this
9302          */
9303         setLeft : function(left){
9304             this.setStyle("left", this.addUnits(left));
9305             return this;
9306         },
9307
9308         /**
9309          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9310          * @param {String} top The top CSS property value
9311          * @return {Roo.Element} this
9312          */
9313         setTop : function(top){
9314             this.setStyle("top", this.addUnits(top));
9315             return this;
9316         },
9317
9318         /**
9319          * Sets the element's CSS right style.
9320          * @param {String} right The right CSS property value
9321          * @return {Roo.Element} this
9322          */
9323         setRight : function(right){
9324             this.setStyle("right", this.addUnits(right));
9325             return this;
9326         },
9327
9328         /**
9329          * Sets the element's CSS bottom style.
9330          * @param {String} bottom The bottom CSS property value
9331          * @return {Roo.Element} this
9332          */
9333         setBottom : function(bottom){
9334             this.setStyle("bottom", this.addUnits(bottom));
9335             return this;
9336         },
9337
9338         /**
9339          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9340          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9341          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9342          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9343          * @return {Roo.Element} this
9344          */
9345         setXY : function(pos, animate){
9346             if(!animate || !A){
9347                 D.setXY(this.dom, pos);
9348             }else{
9349                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9350             }
9351             return this;
9352         },
9353
9354         /**
9355          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9356          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9357          * @param {Number} x X value for new position (coordinates are page-based)
9358          * @param {Number} y Y value for new position (coordinates are page-based)
9359          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9360          * @return {Roo.Element} this
9361          */
9362         setLocation : function(x, y, animate){
9363             this.setXY([x, y], this.preanim(arguments, 2));
9364             return this;
9365         },
9366
9367         /**
9368          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9369          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9370          * @param {Number} x X value for new position (coordinates are page-based)
9371          * @param {Number} y Y value for new position (coordinates are page-based)
9372          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9373          * @return {Roo.Element} this
9374          */
9375         moveTo : function(x, y, animate){
9376             this.setXY([x, y], this.preanim(arguments, 2));
9377             return this;
9378         },
9379
9380         /**
9381          * Returns the region of the given element.
9382          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9383          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9384          */
9385         getRegion : function(){
9386             return D.getRegion(this.dom);
9387         },
9388
9389         /**
9390          * Returns the offset height of the element
9391          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9392          * @return {Number} The element's height
9393          */
9394         getHeight : function(contentHeight){
9395             var h = this.dom.offsetHeight || 0;
9396             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9397         },
9398
9399         /**
9400          * Returns the offset width of the element
9401          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9402          * @return {Number} The element's width
9403          */
9404         getWidth : function(contentWidth){
9405             var w = this.dom.offsetWidth || 0;
9406             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9407         },
9408
9409         /**
9410          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9411          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9412          * if a height has not been set using CSS.
9413          * @return {Number}
9414          */
9415         getComputedHeight : function(){
9416             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9417             if(!h){
9418                 h = parseInt(this.getStyle('height'), 10) || 0;
9419                 if(!this.isBorderBox()){
9420                     h += this.getFrameWidth('tb');
9421                 }
9422             }
9423             return h;
9424         },
9425
9426         /**
9427          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9428          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9429          * if a width has not been set using CSS.
9430          * @return {Number}
9431          */
9432         getComputedWidth : function(){
9433             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9434             if(!w){
9435                 w = parseInt(this.getStyle('width'), 10) || 0;
9436                 if(!this.isBorderBox()){
9437                     w += this.getFrameWidth('lr');
9438                 }
9439             }
9440             return w;
9441         },
9442
9443         /**
9444          * Returns the size of the element.
9445          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9446          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9447          */
9448         getSize : function(contentSize){
9449             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9450         },
9451
9452         /**
9453          * Returns the width and height of the viewport.
9454          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9455          */
9456         getViewSize : function(){
9457             var d = this.dom, doc = document, aw = 0, ah = 0;
9458             if(d == doc || d == doc.body){
9459                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9460             }else{
9461                 return {
9462                     width : d.clientWidth,
9463                     height: d.clientHeight
9464                 };
9465             }
9466         },
9467
9468         /**
9469          * Returns the value of the "value" attribute
9470          * @param {Boolean} asNumber true to parse the value as a number
9471          * @return {String/Number}
9472          */
9473         getValue : function(asNumber){
9474             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9475         },
9476
9477         // private
9478         adjustWidth : function(width){
9479             if(typeof width == "number"){
9480                 if(this.autoBoxAdjust && !this.isBorderBox()){
9481                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9482                 }
9483                 if(width < 0){
9484                     width = 0;
9485                 }
9486             }
9487             return width;
9488         },
9489
9490         // private
9491         adjustHeight : function(height){
9492             if(typeof height == "number"){
9493                if(this.autoBoxAdjust && !this.isBorderBox()){
9494                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9495                }
9496                if(height < 0){
9497                    height = 0;
9498                }
9499             }
9500             return height;
9501         },
9502
9503         /**
9504          * Set the width of the element
9505          * @param {Number} width The new width
9506          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9507          * @return {Roo.Element} this
9508          */
9509         setWidth : function(width, animate){
9510             width = this.adjustWidth(width);
9511             if(!animate || !A){
9512                 this.dom.style.width = this.addUnits(width);
9513             }else{
9514                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9515             }
9516             return this;
9517         },
9518
9519         /**
9520          * Set the height of the element
9521          * @param {Number} height The new height
9522          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9523          * @return {Roo.Element} this
9524          */
9525          setHeight : function(height, animate){
9526             height = this.adjustHeight(height);
9527             if(!animate || !A){
9528                 this.dom.style.height = this.addUnits(height);
9529             }else{
9530                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9531             }
9532             return this;
9533         },
9534
9535         /**
9536          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9537          * @param {Number} width The new width
9538          * @param {Number} height The new height
9539          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9540          * @return {Roo.Element} this
9541          */
9542          setSize : function(width, height, animate){
9543             if(typeof width == "object"){ // in case of object from getSize()
9544                 height = width.height; width = width.width;
9545             }
9546             width = this.adjustWidth(width); height = this.adjustHeight(height);
9547             if(!animate || !A){
9548                 this.dom.style.width = this.addUnits(width);
9549                 this.dom.style.height = this.addUnits(height);
9550             }else{
9551                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9552             }
9553             return this;
9554         },
9555
9556         /**
9557          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9558          * @param {Number} x X value for new position (coordinates are page-based)
9559          * @param {Number} y Y value for new position (coordinates are page-based)
9560          * @param {Number} width The new width
9561          * @param {Number} height The new height
9562          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9563          * @return {Roo.Element} this
9564          */
9565         setBounds : function(x, y, width, height, animate){
9566             if(!animate || !A){
9567                 this.setSize(width, height);
9568                 this.setLocation(x, y);
9569             }else{
9570                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9571                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9572                               this.preanim(arguments, 4), 'motion');
9573             }
9574             return this;
9575         },
9576
9577         /**
9578          * 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.
9579          * @param {Roo.lib.Region} region The region to fill
9580          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9581          * @return {Roo.Element} this
9582          */
9583         setRegion : function(region, animate){
9584             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9585             return this;
9586         },
9587
9588         /**
9589          * Appends an event handler
9590          *
9591          * @param {String}   eventName     The type of event to append
9592          * @param {Function} fn        The method the event invokes
9593          * @param {Object} scope       (optional) The scope (this object) of the fn
9594          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9595          */
9596         addListener : function(eventName, fn, scope, options)
9597         {
9598             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9599                 this.addListener('touchstart', this.onTapHandler, this);
9600             }
9601             
9602             // we need to handle a special case where dom element is a svg element.
9603             // in this case we do not actua
9604             if (!this.dom) {
9605                 return;
9606             }
9607             
9608             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9609                 if (typeof(this.listeners[eventName]) == 'undefined') {
9610                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9611                 }
9612                 this.listeners[eventName].addListener(fn, scope, options);
9613                 return;
9614             }
9615             
9616                 
9617             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9618             
9619             
9620         },
9621         tapedTwice : false,
9622         onTapHandler : function(event)
9623         {
9624             if(!this.tapedTwice) {
9625                 this.tapedTwice = true;
9626                 var s = this;
9627                 setTimeout( function() {
9628                     s.tapedTwice = false;
9629                 }, 300 );
9630                 return;
9631             }
9632             event.preventDefault();
9633             var revent = new MouseEvent('dblclick',  {
9634                 view: window,
9635                 bubbles: true,
9636                 cancelable: true
9637             });
9638              
9639             this.dom.dispatchEvent(revent);
9640             //action on double tap goes below
9641              
9642         }, 
9643  
9644         /**
9645          * Removes an event handler from this element
9646          * @param {String} eventName the type of event to remove
9647          * @param {Function} fn the method the event invokes
9648          * @param {Function} scope (needed for svg fake listeners)
9649          * @return {Roo.Element} this
9650          */
9651         removeListener : function(eventName, fn, scope){
9652             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9653             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9654                 return this;
9655             }
9656             this.listeners[eventName].removeListener(fn, scope);
9657             return this;
9658         },
9659
9660         /**
9661          * Removes all previous added listeners from this element
9662          * @return {Roo.Element} this
9663          */
9664         removeAllListeners : function(){
9665             E.purgeElement(this.dom);
9666             this.listeners = {};
9667             return this;
9668         },
9669
9670         relayEvent : function(eventName, observable){
9671             this.on(eventName, function(e){
9672                 observable.fireEvent(eventName, e);
9673             });
9674         },
9675
9676         
9677         /**
9678          * Set the opacity of the element
9679          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9680          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9681          * @return {Roo.Element} this
9682          */
9683          setOpacity : function(opacity, animate){
9684             if(!animate || !A){
9685                 var s = this.dom.style;
9686                 if(Roo.isIE){
9687                     s.zoom = 1;
9688                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9689                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9690                 }else{
9691                     s.opacity = opacity;
9692                 }
9693             }else{
9694                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9695             }
9696             return this;
9697         },
9698
9699         /**
9700          * Gets the left X coordinate
9701          * @param {Boolean} local True to get the local css position instead of page coordinate
9702          * @return {Number}
9703          */
9704         getLeft : function(local){
9705             if(!local){
9706                 return this.getX();
9707             }else{
9708                 return parseInt(this.getStyle("left"), 10) || 0;
9709             }
9710         },
9711
9712         /**
9713          * Gets the right X coordinate of the element (element X position + element width)
9714          * @param {Boolean} local True to get the local css position instead of page coordinate
9715          * @return {Number}
9716          */
9717         getRight : function(local){
9718             if(!local){
9719                 return this.getX() + this.getWidth();
9720             }else{
9721                 return (this.getLeft(true) + this.getWidth()) || 0;
9722             }
9723         },
9724
9725         /**
9726          * Gets the top Y coordinate
9727          * @param {Boolean} local True to get the local css position instead of page coordinate
9728          * @return {Number}
9729          */
9730         getTop : function(local) {
9731             if(!local){
9732                 return this.getY();
9733             }else{
9734                 return parseInt(this.getStyle("top"), 10) || 0;
9735             }
9736         },
9737
9738         /**
9739          * Gets the bottom Y coordinate of the element (element Y position + element height)
9740          * @param {Boolean} local True to get the local css position instead of page coordinate
9741          * @return {Number}
9742          */
9743         getBottom : function(local){
9744             if(!local){
9745                 return this.getY() + this.getHeight();
9746             }else{
9747                 return (this.getTop(true) + this.getHeight()) || 0;
9748             }
9749         },
9750
9751         /**
9752         * Initializes positioning on this element. If a desired position is not passed, it will make the
9753         * the element positioned relative IF it is not already positioned.
9754         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9755         * @param {Number} zIndex (optional) The zIndex to apply
9756         * @param {Number} x (optional) Set the page X position
9757         * @param {Number} y (optional) Set the page Y position
9758         */
9759         position : function(pos, zIndex, x, y){
9760             if(!pos){
9761                if(this.getStyle('position') == 'static'){
9762                    this.setStyle('position', 'relative');
9763                }
9764             }else{
9765                 this.setStyle("position", pos);
9766             }
9767             if(zIndex){
9768                 this.setStyle("z-index", zIndex);
9769             }
9770             if(x !== undefined && y !== undefined){
9771                 this.setXY([x, y]);
9772             }else if(x !== undefined){
9773                 this.setX(x);
9774             }else if(y !== undefined){
9775                 this.setY(y);
9776             }
9777         },
9778
9779         /**
9780         * Clear positioning back to the default when the document was loaded
9781         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9782         * @return {Roo.Element} this
9783          */
9784         clearPositioning : function(value){
9785             value = value ||'';
9786             this.setStyle({
9787                 "left": value,
9788                 "right": value,
9789                 "top": value,
9790                 "bottom": value,
9791                 "z-index": "",
9792                 "position" : "static"
9793             });
9794             return this;
9795         },
9796
9797         /**
9798         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9799         * snapshot before performing an update and then restoring the element.
9800         * @return {Object}
9801         */
9802         getPositioning : function(){
9803             var l = this.getStyle("left");
9804             var t = this.getStyle("top");
9805             return {
9806                 "position" : this.getStyle("position"),
9807                 "left" : l,
9808                 "right" : l ? "" : this.getStyle("right"),
9809                 "top" : t,
9810                 "bottom" : t ? "" : this.getStyle("bottom"),
9811                 "z-index" : this.getStyle("z-index")
9812             };
9813         },
9814
9815         /**
9816          * Gets the width of the border(s) for the specified side(s)
9817          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9818          * passing lr would get the border (l)eft width + the border (r)ight width.
9819          * @return {Number} The width of the sides passed added together
9820          */
9821         getBorderWidth : function(side){
9822             return this.addStyles(side, El.borders);
9823         },
9824
9825         /**
9826          * Gets the width of the padding(s) for the specified side(s)
9827          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9828          * passing lr would get the padding (l)eft + the padding (r)ight.
9829          * @return {Number} The padding of the sides passed added together
9830          */
9831         getPadding : function(side){
9832             return this.addStyles(side, El.paddings);
9833         },
9834
9835         /**
9836         * Set positioning with an object returned by getPositioning().
9837         * @param {Object} posCfg
9838         * @return {Roo.Element} this
9839          */
9840         setPositioning : function(pc){
9841             this.applyStyles(pc);
9842             if(pc.right == "auto"){
9843                 this.dom.style.right = "";
9844             }
9845             if(pc.bottom == "auto"){
9846                 this.dom.style.bottom = "";
9847             }
9848             return this;
9849         },
9850
9851         // private
9852         fixDisplay : function(){
9853             if(this.getStyle("display") == "none"){
9854                 this.setStyle("visibility", "hidden");
9855                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9856                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9857                     this.setStyle("display", "block");
9858                 }
9859             }
9860         },
9861
9862         /**
9863          * Quick set left and top adding default units
9864          * @param {String} left The left CSS property value
9865          * @param {String} top The top CSS property value
9866          * @return {Roo.Element} this
9867          */
9868          setLeftTop : function(left, top){
9869             this.dom.style.left = this.addUnits(left);
9870             this.dom.style.top = this.addUnits(top);
9871             return this;
9872         },
9873
9874         /**
9875          * Move this element relative to its current position.
9876          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9877          * @param {Number} distance How far to move the element in pixels
9878          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9879          * @return {Roo.Element} this
9880          */
9881          move : function(direction, distance, animate){
9882             var xy = this.getXY();
9883             direction = direction.toLowerCase();
9884             switch(direction){
9885                 case "l":
9886                 case "left":
9887                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9888                     break;
9889                case "r":
9890                case "right":
9891                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9892                     break;
9893                case "t":
9894                case "top":
9895                case "up":
9896                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9897                     break;
9898                case "b":
9899                case "bottom":
9900                case "down":
9901                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9902                     break;
9903             }
9904             return this;
9905         },
9906
9907         /**
9908          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9909          * @return {Roo.Element} this
9910          */
9911         clip : function(){
9912             if(!this.isClipped){
9913                this.isClipped = true;
9914                this.originalClip = {
9915                    "o": this.getStyle("overflow"),
9916                    "x": this.getStyle("overflow-x"),
9917                    "y": this.getStyle("overflow-y")
9918                };
9919                this.setStyle("overflow", "hidden");
9920                this.setStyle("overflow-x", "hidden");
9921                this.setStyle("overflow-y", "hidden");
9922             }
9923             return this;
9924         },
9925
9926         /**
9927          *  Return clipping (overflow) to original clipping before clip() was called
9928          * @return {Roo.Element} this
9929          */
9930         unclip : function(){
9931             if(this.isClipped){
9932                 this.isClipped = false;
9933                 var o = this.originalClip;
9934                 if(o.o){this.setStyle("overflow", o.o);}
9935                 if(o.x){this.setStyle("overflow-x", o.x);}
9936                 if(o.y){this.setStyle("overflow-y", o.y);}
9937             }
9938             return this;
9939         },
9940
9941
9942         /**
9943          * Gets the x,y coordinates specified by the anchor position on the element.
9944          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9945          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9946          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9947          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9948          * @return {Array} [x, y] An array containing the element's x and y coordinates
9949          */
9950         getAnchorXY : function(anchor, local, s){
9951             //Passing a different size is useful for pre-calculating anchors,
9952             //especially for anchored animations that change the el size.
9953
9954             var w, h, vp = false;
9955             if(!s){
9956                 var d = this.dom;
9957                 if(d == document.body || d == document){
9958                     vp = true;
9959                     w = D.getViewWidth(); h = D.getViewHeight();
9960                 }else{
9961                     w = this.getWidth(); h = this.getHeight();
9962                 }
9963             }else{
9964                 w = s.width;  h = s.height;
9965             }
9966             var x = 0, y = 0, r = Math.round;
9967             switch((anchor || "tl").toLowerCase()){
9968                 case "c":
9969                     x = r(w*.5);
9970                     y = r(h*.5);
9971                 break;
9972                 case "t":
9973                     x = r(w*.5);
9974                     y = 0;
9975                 break;
9976                 case "l":
9977                     x = 0;
9978                     y = r(h*.5);
9979                 break;
9980                 case "r":
9981                     x = w;
9982                     y = r(h*.5);
9983                 break;
9984                 case "b":
9985                     x = r(w*.5);
9986                     y = h;
9987                 break;
9988                 case "tl":
9989                     x = 0;
9990                     y = 0;
9991                 break;
9992                 case "bl":
9993                     x = 0;
9994                     y = h;
9995                 break;
9996                 case "br":
9997                     x = w;
9998                     y = h;
9999                 break;
10000                 case "tr":
10001                     x = w;
10002                     y = 0;
10003                 break;
10004             }
10005             if(local === true){
10006                 return [x, y];
10007             }
10008             if(vp){
10009                 var sc = this.getScroll();
10010                 return [x + sc.left, y + sc.top];
10011             }
10012             //Add the element's offset xy
10013             var o = this.getXY();
10014             return [x+o[0], y+o[1]];
10015         },
10016
10017         /**
10018          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
10019          * supported position values.
10020          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10021          * @param {String} position The position to align to.
10022          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10023          * @return {Array} [x, y]
10024          */
10025         getAlignToXY : function(el, p, o)
10026         {
10027             el = Roo.get(el);
10028             var d = this.dom;
10029             if(!el.dom){
10030                 throw "Element.alignTo with an element that doesn't exist";
10031             }
10032             var c = false; //constrain to viewport
10033             var p1 = "", p2 = "";
10034             o = o || [0,0];
10035
10036             if(!p){
10037                 p = "tl-bl";
10038             }else if(p == "?"){
10039                 p = "tl-bl?";
10040             }else if(p.indexOf("-") == -1){
10041                 p = "tl-" + p;
10042             }
10043             p = p.toLowerCase();
10044             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10045             if(!m){
10046                throw "Element.alignTo with an invalid alignment " + p;
10047             }
10048             p1 = m[1]; p2 = m[2]; c = !!m[3];
10049
10050             //Subtract the aligned el's internal xy from the target's offset xy
10051             //plus custom offset to get the aligned el's new offset xy
10052             var a1 = this.getAnchorXY(p1, true);
10053             var a2 = el.getAnchorXY(p2, false);
10054             var x = a2[0] - a1[0] + o[0];
10055             var y = a2[1] - a1[1] + o[1];
10056             if(c){
10057                 //constrain the aligned el to viewport if necessary
10058                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10059                 // 5px of margin for ie
10060                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10061
10062                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10063                 //perpendicular to the vp border, allow the aligned el to slide on that border,
10064                 //otherwise swap the aligned el to the opposite border of the target.
10065                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10066                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10067                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
10068                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10069
10070                var doc = document;
10071                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10072                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10073
10074                if((x+w) > dw + scrollX){
10075                     x = swapX ? r.left-w : dw+scrollX-w;
10076                 }
10077                if(x < scrollX){
10078                    x = swapX ? r.right : scrollX;
10079                }
10080                if((y+h) > dh + scrollY){
10081                     y = swapY ? r.top-h : dh+scrollY-h;
10082                 }
10083                if (y < scrollY){
10084                    y = swapY ? r.bottom : scrollY;
10085                }
10086             }
10087             return [x,y];
10088         },
10089
10090         // private
10091         getConstrainToXY : function(){
10092             var os = {top:0, left:0, bottom:0, right: 0};
10093
10094             return function(el, local, offsets, proposedXY){
10095                 el = Roo.get(el);
10096                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10097
10098                 var vw, vh, vx = 0, vy = 0;
10099                 if(el.dom == document.body || el.dom == document){
10100                     vw = Roo.lib.Dom.getViewWidth();
10101                     vh = Roo.lib.Dom.getViewHeight();
10102                 }else{
10103                     vw = el.dom.clientWidth;
10104                     vh = el.dom.clientHeight;
10105                     if(!local){
10106                         var vxy = el.getXY();
10107                         vx = vxy[0];
10108                         vy = vxy[1];
10109                     }
10110                 }
10111
10112                 var s = el.getScroll();
10113
10114                 vx += offsets.left + s.left;
10115                 vy += offsets.top + s.top;
10116
10117                 vw -= offsets.right;
10118                 vh -= offsets.bottom;
10119
10120                 var vr = vx+vw;
10121                 var vb = vy+vh;
10122
10123                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10124                 var x = xy[0], y = xy[1];
10125                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10126
10127                 // only move it if it needs it
10128                 var moved = false;
10129
10130                 // first validate right/bottom
10131                 if((x + w) > vr){
10132                     x = vr - w;
10133                     moved = true;
10134                 }
10135                 if((y + h) > vb){
10136                     y = vb - h;
10137                     moved = true;
10138                 }
10139                 // then make sure top/left isn't negative
10140                 if(x < vx){
10141                     x = vx;
10142                     moved = true;
10143                 }
10144                 if(y < vy){
10145                     y = vy;
10146                     moved = true;
10147                 }
10148                 return moved ? [x, y] : false;
10149             };
10150         }(),
10151
10152         // private
10153         adjustForConstraints : function(xy, parent, offsets){
10154             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
10155         },
10156
10157         /**
10158          * Aligns this element with another element relative to the specified anchor points. If the other element is the
10159          * document it aligns it to the viewport.
10160          * The position parameter is optional, and can be specified in any one of the following formats:
10161          * <ul>
10162          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10163          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10164          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
10165          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
10166          *   <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
10167          *       element's anchor point, and the second value is used as the target's anchor point.</li>
10168          * </ul>
10169          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
10170          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10171          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
10172          * that specified in order to enforce the viewport constraints.
10173          * Following are all of the supported anchor positions:
10174     <pre>
10175     Value  Description
10176     -----  -----------------------------
10177     tl     The top left corner (default)
10178     t      The center of the top edge
10179     tr     The top right corner
10180     l      The center of the left edge
10181     c      In the center of the element
10182     r      The center of the right edge
10183     bl     The bottom left corner
10184     b      The center of the bottom edge
10185     br     The bottom right corner
10186     </pre>
10187     Example Usage:
10188     <pre><code>
10189     // align el to other-el using the default positioning ("tl-bl", non-constrained)
10190     el.alignTo("other-el");
10191
10192     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10193     el.alignTo("other-el", "tr?");
10194
10195     // align the bottom right corner of el with the center left edge of other-el
10196     el.alignTo("other-el", "br-l?");
10197
10198     // align the center of el with the bottom left corner of other-el and
10199     // adjust the x position by -6 pixels (and the y position by 0)
10200     el.alignTo("other-el", "c-bl", [-6, 0]);
10201     </code></pre>
10202          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10203          * @param {String} position The position to align to.
10204          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10205          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10206          * @return {Roo.Element} this
10207          */
10208         alignTo : function(element, position, offsets, animate){
10209             var xy = this.getAlignToXY(element, position, offsets);
10210             this.setXY(xy, this.preanim(arguments, 3));
10211             return this;
10212         },
10213
10214         /**
10215          * Anchors an element to another element and realigns it when the window is resized.
10216          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10217          * @param {String} position The position to align to.
10218          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10219          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10220          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10221          * is a number, it is used as the buffer delay (defaults to 50ms).
10222          * @param {Function} callback The function to call after the animation finishes
10223          * @return {Roo.Element} this
10224          */
10225         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10226             var action = function(){
10227                 this.alignTo(el, alignment, offsets, animate);
10228                 Roo.callback(callback, this);
10229             };
10230             Roo.EventManager.onWindowResize(action, this);
10231             var tm = typeof monitorScroll;
10232             if(tm != 'undefined'){
10233                 Roo.EventManager.on(window, 'scroll', action, this,
10234                     {buffer: tm == 'number' ? monitorScroll : 50});
10235             }
10236             action.call(this); // align immediately
10237             return this;
10238         },
10239         /**
10240          * Clears any opacity settings from this element. Required in some cases for IE.
10241          * @return {Roo.Element} this
10242          */
10243         clearOpacity : function(){
10244             if (window.ActiveXObject) {
10245                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10246                     this.dom.style.filter = "";
10247                 }
10248             } else {
10249                 this.dom.style.opacity = "";
10250                 this.dom.style["-moz-opacity"] = "";
10251                 this.dom.style["-khtml-opacity"] = "";
10252             }
10253             return this;
10254         },
10255
10256         /**
10257          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10258          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10259          * @return {Roo.Element} this
10260          */
10261         hide : function(animate){
10262             this.setVisible(false, this.preanim(arguments, 0));
10263             return this;
10264         },
10265
10266         /**
10267         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10268         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10269          * @return {Roo.Element} this
10270          */
10271         show : function(animate){
10272             this.setVisible(true, this.preanim(arguments, 0));
10273             return this;
10274         },
10275
10276         /**
10277          * @private Test if size has a unit, otherwise appends the default
10278          */
10279         addUnits : function(size){
10280             return Roo.Element.addUnits(size, this.defaultUnit);
10281         },
10282
10283         /**
10284          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10285          * @return {Roo.Element} this
10286          */
10287         beginMeasure : function(){
10288             var el = this.dom;
10289             if(el.offsetWidth || el.offsetHeight){
10290                 return this; // offsets work already
10291             }
10292             var changed = [];
10293             var p = this.dom, b = document.body; // start with this element
10294             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10295                 var pe = Roo.get(p);
10296                 if(pe.getStyle('display') == 'none'){
10297                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10298                     p.style.visibility = "hidden";
10299                     p.style.display = "block";
10300                 }
10301                 p = p.parentNode;
10302             }
10303             this._measureChanged = changed;
10304             return this;
10305
10306         },
10307
10308         /**
10309          * Restores displays to before beginMeasure was called
10310          * @return {Roo.Element} this
10311          */
10312         endMeasure : function(){
10313             var changed = this._measureChanged;
10314             if(changed){
10315                 for(var i = 0, len = changed.length; i < len; i++) {
10316                     var r = changed[i];
10317                     r.el.style.visibility = r.visibility;
10318                     r.el.style.display = "none";
10319                 }
10320                 this._measureChanged = null;
10321             }
10322             return this;
10323         },
10324
10325         /**
10326         * Update the innerHTML of this element, optionally searching for and processing scripts
10327         * @param {String} html The new HTML
10328         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10329         * @param {Function} callback For async script loading you can be noticed when the update completes
10330         * @return {Roo.Element} this
10331          */
10332         update : function(html, loadScripts, callback){
10333             if(typeof html == "undefined"){
10334                 html = "";
10335             }
10336             if(loadScripts !== true){
10337                 this.dom.innerHTML = html;
10338                 if(typeof callback == "function"){
10339                     callback();
10340                 }
10341                 return this;
10342             }
10343             var id = Roo.id();
10344             var dom = this.dom;
10345
10346             html += '<span id="' + id + '"></span>';
10347
10348             E.onAvailable(id, function(){
10349                 var hd = document.getElementsByTagName("head")[0];
10350                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10351                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10352                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10353
10354                 var match;
10355                 while(match = re.exec(html)){
10356                     var attrs = match[1];
10357                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10358                     if(srcMatch && srcMatch[2]){
10359                        var s = document.createElement("script");
10360                        s.src = srcMatch[2];
10361                        var typeMatch = attrs.match(typeRe);
10362                        if(typeMatch && typeMatch[2]){
10363                            s.type = typeMatch[2];
10364                        }
10365                        hd.appendChild(s);
10366                     }else if(match[2] && match[2].length > 0){
10367                         if(window.execScript) {
10368                            window.execScript(match[2]);
10369                         } else {
10370                             /**
10371                              * eval:var:id
10372                              * eval:var:dom
10373                              * eval:var:html
10374                              * 
10375                              */
10376                            window.eval(match[2]);
10377                         }
10378                     }
10379                 }
10380                 var el = document.getElementById(id);
10381                 if(el){el.parentNode.removeChild(el);}
10382                 if(typeof callback == "function"){
10383                     callback();
10384                 }
10385             });
10386             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10387             return this;
10388         },
10389
10390         /**
10391          * Direct access to the UpdateManager update() method (takes the same parameters).
10392          * @param {String/Function} url The url for this request or a function to call to get the url
10393          * @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}
10394          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10395          * @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.
10396          * @return {Roo.Element} this
10397          */
10398         load : function(){
10399             var um = this.getUpdateManager();
10400             um.update.apply(um, arguments);
10401             return this;
10402         },
10403
10404         /**
10405         * Gets this element's UpdateManager
10406         * @return {Roo.UpdateManager} The UpdateManager
10407         */
10408         getUpdateManager : function(){
10409             if(!this.updateManager){
10410                 this.updateManager = new Roo.UpdateManager(this);
10411             }
10412             return this.updateManager;
10413         },
10414
10415         /**
10416          * Disables text selection for this element (normalized across browsers)
10417          * @return {Roo.Element} this
10418          */
10419         unselectable : function(){
10420             this.dom.unselectable = "on";
10421             this.swallowEvent("selectstart", true);
10422             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10423             this.addClass("x-unselectable");
10424             return this;
10425         },
10426
10427         /**
10428         * Calculates the x, y to center this element on the screen
10429         * @return {Array} The x, y values [x, y]
10430         */
10431         getCenterXY : function(){
10432             return this.getAlignToXY(document, 'c-c');
10433         },
10434
10435         /**
10436         * Centers the Element in either the viewport, or another Element.
10437         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10438         */
10439         center : function(centerIn){
10440             this.alignTo(centerIn || document, 'c-c');
10441             return this;
10442         },
10443
10444         /**
10445          * Tests various css rules/browsers to determine if this element uses a border box
10446          * @return {Boolean}
10447          */
10448         isBorderBox : function(){
10449             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10450         },
10451
10452         /**
10453          * Return a box {x, y, width, height} that can be used to set another elements
10454          * size/location to match this element.
10455          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10456          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10457          * @return {Object} box An object in the format {x, y, width, height}
10458          */
10459         getBox : function(contentBox, local){
10460             var xy;
10461             if(!local){
10462                 xy = this.getXY();
10463             }else{
10464                 var left = parseInt(this.getStyle("left"), 10) || 0;
10465                 var top = parseInt(this.getStyle("top"), 10) || 0;
10466                 xy = [left, top];
10467             }
10468             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10469             if(!contentBox){
10470                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10471             }else{
10472                 var l = this.getBorderWidth("l")+this.getPadding("l");
10473                 var r = this.getBorderWidth("r")+this.getPadding("r");
10474                 var t = this.getBorderWidth("t")+this.getPadding("t");
10475                 var b = this.getBorderWidth("b")+this.getPadding("b");
10476                 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)};
10477             }
10478             bx.right = bx.x + bx.width;
10479             bx.bottom = bx.y + bx.height;
10480             return bx;
10481         },
10482
10483         /**
10484          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10485          for more information about the sides.
10486          * @param {String} sides
10487          * @return {Number}
10488          */
10489         getFrameWidth : function(sides, onlyContentBox){
10490             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10491         },
10492
10493         /**
10494          * 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.
10495          * @param {Object} box The box to fill {x, y, width, height}
10496          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10497          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10498          * @return {Roo.Element} this
10499          */
10500         setBox : function(box, adjust, animate){
10501             var w = box.width, h = box.height;
10502             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10503                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10504                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10505             }
10506             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10507             return this;
10508         },
10509
10510         /**
10511          * Forces the browser to repaint this element
10512          * @return {Roo.Element} this
10513          */
10514          repaint : function(){
10515             var dom = this.dom;
10516             this.addClass("x-repaint");
10517             setTimeout(function(){
10518                 Roo.get(dom).removeClass("x-repaint");
10519             }, 1);
10520             return this;
10521         },
10522
10523         /**
10524          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10525          * then it returns the calculated width of the sides (see getPadding)
10526          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10527          * @return {Object/Number}
10528          */
10529         getMargins : function(side){
10530             if(!side){
10531                 return {
10532                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10533                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10534                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10535                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10536                 };
10537             }else{
10538                 return this.addStyles(side, El.margins);
10539              }
10540         },
10541
10542         // private
10543         addStyles : function(sides, styles){
10544             var val = 0, v, w;
10545             for(var i = 0, len = sides.length; i < len; i++){
10546                 v = this.getStyle(styles[sides.charAt(i)]);
10547                 if(v){
10548                      w = parseInt(v, 10);
10549                      if(w){ val += w; }
10550                 }
10551             }
10552             return val;
10553         },
10554
10555         /**
10556          * Creates a proxy element of this element
10557          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10558          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10559          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10560          * @return {Roo.Element} The new proxy element
10561          */
10562         createProxy : function(config, renderTo, matchBox){
10563             if(renderTo){
10564                 renderTo = Roo.getDom(renderTo);
10565             }else{
10566                 renderTo = document.body;
10567             }
10568             config = typeof config == "object" ?
10569                 config : {tag : "div", cls: config};
10570             var proxy = Roo.DomHelper.append(renderTo, config, true);
10571             if(matchBox){
10572                proxy.setBox(this.getBox());
10573             }
10574             return proxy;
10575         },
10576
10577         /**
10578          * Puts a mask over this element to disable user interaction. Requires core.css.
10579          * This method can only be applied to elements which accept child nodes.
10580          * @param {String} msg (optional) A message to display in the mask
10581          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10582          * @return {Element} The mask  element
10583          */
10584         mask : function(msg, msgCls)
10585         {
10586             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10587                 this.setStyle("position", "relative");
10588             }
10589             if(!this._mask){
10590                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10591             }
10592             
10593             this.addClass("x-masked");
10594             this._mask.setDisplayed(true);
10595             
10596             // we wander
10597             var z = 0;
10598             var dom = this.dom;
10599             while (dom && dom.style) {
10600                 if (!isNaN(parseInt(dom.style.zIndex))) {
10601                     z = Math.max(z, parseInt(dom.style.zIndex));
10602                 }
10603                 dom = dom.parentNode;
10604             }
10605             // if we are masking the body - then it hides everything..
10606             if (this.dom == document.body) {
10607                 z = 1000000;
10608                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10609                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10610             }
10611            
10612             if(typeof msg == 'string'){
10613                 if(!this._maskMsg){
10614                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10615                         cls: "roo-el-mask-msg", 
10616                         cn: [
10617                             {
10618                                 tag: 'i',
10619                                 cls: 'fa fa-spinner fa-spin'
10620                             },
10621                             {
10622                                 tag: 'div'
10623                             }   
10624                         ]
10625                     }, true);
10626                 }
10627                 var mm = this._maskMsg;
10628                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10629                 if (mm.dom.lastChild) { // weird IE issue?
10630                     mm.dom.lastChild.innerHTML = msg;
10631                 }
10632                 mm.setDisplayed(true);
10633                 mm.center(this);
10634                 mm.setStyle('z-index', z + 102);
10635             }
10636             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10637                 this._mask.setHeight(this.getHeight());
10638             }
10639             this._mask.setStyle('z-index', z + 100);
10640             
10641             return this._mask;
10642         },
10643
10644         /**
10645          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10646          * it is cached for reuse.
10647          */
10648         unmask : function(removeEl){
10649             if(this._mask){
10650                 if(removeEl === true){
10651                     this._mask.remove();
10652                     delete this._mask;
10653                     if(this._maskMsg){
10654                         this._maskMsg.remove();
10655                         delete this._maskMsg;
10656                     }
10657                 }else{
10658                     this._mask.setDisplayed(false);
10659                     if(this._maskMsg){
10660                         this._maskMsg.setDisplayed(false);
10661                     }
10662                 }
10663             }
10664             this.removeClass("x-masked");
10665         },
10666
10667         /**
10668          * Returns true if this element is masked
10669          * @return {Boolean}
10670          */
10671         isMasked : function(){
10672             return this._mask && this._mask.isVisible();
10673         },
10674
10675         /**
10676          * Creates an iframe shim for this element to keep selects and other windowed objects from
10677          * showing through.
10678          * @return {Roo.Element} The new shim element
10679          */
10680         createShim : function(){
10681             var el = document.createElement('iframe');
10682             el.frameBorder = 'no';
10683             el.className = 'roo-shim';
10684             if(Roo.isIE && Roo.isSecure){
10685                 el.src = Roo.SSL_SECURE_URL;
10686             }
10687             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10688             shim.autoBoxAdjust = false;
10689             return shim;
10690         },
10691
10692         /**
10693          * Removes this element from the DOM and deletes it from the cache
10694          */
10695         remove : function(){
10696             if(this.dom.parentNode){
10697                 this.dom.parentNode.removeChild(this.dom);
10698             }
10699             delete El.cache[this.dom.id];
10700         },
10701
10702         /**
10703          * Sets up event handlers to add and remove a css class when the mouse is over this element
10704          * @param {String} className
10705          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10706          * mouseout events for children elements
10707          * @return {Roo.Element} this
10708          */
10709         addClassOnOver : function(className, preventFlicker){
10710             this.on("mouseover", function(){
10711                 Roo.fly(this, '_internal').addClass(className);
10712             }, this.dom);
10713             var removeFn = function(e){
10714                 if(preventFlicker !== true || !e.within(this, true)){
10715                     Roo.fly(this, '_internal').removeClass(className);
10716                 }
10717             };
10718             this.on("mouseout", removeFn, this.dom);
10719             return this;
10720         },
10721
10722         /**
10723          * Sets up event handlers to add and remove a css class when this element has the focus
10724          * @param {String} className
10725          * @return {Roo.Element} this
10726          */
10727         addClassOnFocus : function(className){
10728             this.on("focus", function(){
10729                 Roo.fly(this, '_internal').addClass(className);
10730             }, this.dom);
10731             this.on("blur", function(){
10732                 Roo.fly(this, '_internal').removeClass(className);
10733             }, this.dom);
10734             return this;
10735         },
10736         /**
10737          * 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)
10738          * @param {String} className
10739          * @return {Roo.Element} this
10740          */
10741         addClassOnClick : function(className){
10742             var dom = this.dom;
10743             this.on("mousedown", function(){
10744                 Roo.fly(dom, '_internal').addClass(className);
10745                 var d = Roo.get(document);
10746                 var fn = function(){
10747                     Roo.fly(dom, '_internal').removeClass(className);
10748                     d.removeListener("mouseup", fn);
10749                 };
10750                 d.on("mouseup", fn);
10751             });
10752             return this;
10753         },
10754
10755         /**
10756          * Stops the specified event from bubbling and optionally prevents the default action
10757          * @param {String} eventName
10758          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10759          * @return {Roo.Element} this
10760          */
10761         swallowEvent : function(eventName, preventDefault){
10762             var fn = function(e){
10763                 e.stopPropagation();
10764                 if(preventDefault){
10765                     e.preventDefault();
10766                 }
10767             };
10768             if(eventName instanceof Array){
10769                 for(var i = 0, len = eventName.length; i < len; i++){
10770                      this.on(eventName[i], fn);
10771                 }
10772                 return this;
10773             }
10774             this.on(eventName, fn);
10775             return this;
10776         },
10777
10778         /**
10779          * @private
10780          */
10781         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10782
10783         /**
10784          * Sizes this element to its parent element's dimensions performing
10785          * neccessary box adjustments.
10786          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10787          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10788          * @return {Roo.Element} this
10789          */
10790         fitToParent : function(monitorResize, targetParent) {
10791           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10792           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10793           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10794             return this;
10795           }
10796           var p = Roo.get(targetParent || this.dom.parentNode);
10797           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10798           if (monitorResize === true) {
10799             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10800             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10801           }
10802           return this;
10803         },
10804
10805         /**
10806          * Gets the next sibling, skipping text nodes
10807          * @return {HTMLElement} The next sibling or null
10808          */
10809         getNextSibling : function(){
10810             var n = this.dom.nextSibling;
10811             while(n && n.nodeType != 1){
10812                 n = n.nextSibling;
10813             }
10814             return n;
10815         },
10816
10817         /**
10818          * Gets the previous sibling, skipping text nodes
10819          * @return {HTMLElement} The previous sibling or null
10820          */
10821         getPrevSibling : function(){
10822             var n = this.dom.previousSibling;
10823             while(n && n.nodeType != 1){
10824                 n = n.previousSibling;
10825             }
10826             return n;
10827         },
10828
10829
10830         /**
10831          * Appends the passed element(s) to this element
10832          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10833          * @return {Roo.Element} this
10834          */
10835         appendChild: function(el){
10836             el = Roo.get(el);
10837             el.appendTo(this);
10838             return this;
10839         },
10840
10841         /**
10842          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10843          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10844          * automatically generated with the specified attributes.
10845          * @param {HTMLElement} insertBefore (optional) a child element of this element
10846          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10847          * @return {Roo.Element} The new child element
10848          */
10849         createChild: function(config, insertBefore, returnDom){
10850             config = config || {tag:'div'};
10851             if(insertBefore){
10852                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10853             }
10854             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10855         },
10856
10857         /**
10858          * Appends this element to the passed element
10859          * @param {String/HTMLElement/Element} el The new parent element
10860          * @return {Roo.Element} this
10861          */
10862         appendTo: function(el){
10863             el = Roo.getDom(el);
10864             el.appendChild(this.dom);
10865             return this;
10866         },
10867
10868         /**
10869          * Inserts this element before the passed element in the DOM
10870          * @param {String/HTMLElement/Element} el The element to insert before
10871          * @return {Roo.Element} this
10872          */
10873         insertBefore: function(el){
10874             el = Roo.getDom(el);
10875             el.parentNode.insertBefore(this.dom, el);
10876             return this;
10877         },
10878
10879         /**
10880          * Inserts this element after the passed element in the DOM
10881          * @param {String/HTMLElement/Element} el The element to insert after
10882          * @return {Roo.Element} this
10883          */
10884         insertAfter: function(el){
10885             el = Roo.getDom(el);
10886             el.parentNode.insertBefore(this.dom, el.nextSibling);
10887             return this;
10888         },
10889
10890         /**
10891          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10892          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10893          * @return {Roo.Element} The new child
10894          */
10895         insertFirst: function(el, returnDom){
10896             el = el || {};
10897             if(typeof el == 'object' && !el.nodeType){ // dh config
10898                 return this.createChild(el, this.dom.firstChild, returnDom);
10899             }else{
10900                 el = Roo.getDom(el);
10901                 this.dom.insertBefore(el, this.dom.firstChild);
10902                 return !returnDom ? Roo.get(el) : el;
10903             }
10904         },
10905
10906         /**
10907          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10908          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10909          * @param {String} where (optional) 'before' or 'after' defaults to before
10910          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10911          * @return {Roo.Element} the inserted Element
10912          */
10913         insertSibling: function(el, where, returnDom){
10914             where = where ? where.toLowerCase() : 'before';
10915             el = el || {};
10916             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10917
10918             if(typeof el == 'object' && !el.nodeType){ // dh config
10919                 if(where == 'after' && !this.dom.nextSibling){
10920                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10921                 }else{
10922                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10923                 }
10924
10925             }else{
10926                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10927                             where == 'before' ? this.dom : this.dom.nextSibling);
10928                 if(!returnDom){
10929                     rt = Roo.get(rt);
10930                 }
10931             }
10932             return rt;
10933         },
10934
10935         /**
10936          * Creates and wraps this element with another element
10937          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10938          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10939          * @return {HTMLElement/Element} The newly created wrapper element
10940          */
10941         wrap: function(config, returnDom){
10942             if(!config){
10943                 config = {tag: "div"};
10944             }
10945             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10946             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10947             return newEl;
10948         },
10949
10950         /**
10951          * Replaces the passed element with this element
10952          * @param {String/HTMLElement/Element} el The element to replace
10953          * @return {Roo.Element} this
10954          */
10955         replace: function(el){
10956             el = Roo.get(el);
10957             this.insertBefore(el);
10958             el.remove();
10959             return this;
10960         },
10961
10962         /**
10963          * Inserts an html fragment into this element
10964          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10965          * @param {String} html The HTML fragment
10966          * @param {Boolean} returnEl True to return an Roo.Element
10967          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10968          */
10969         insertHtml : function(where, html, returnEl){
10970             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10971             return returnEl ? Roo.get(el) : el;
10972         },
10973
10974         /**
10975          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10976          * @param {Object} o The object with the attributes
10977          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10978          * @return {Roo.Element} this
10979          */
10980         set : function(o, useSet){
10981             var el = this.dom;
10982             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10983             for(var attr in o){
10984                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10985                 if(attr=="cls"){
10986                     el.className = o["cls"];
10987                 }else{
10988                     if(useSet) {
10989                         el.setAttribute(attr, o[attr]);
10990                     } else {
10991                         el[attr] = o[attr];
10992                     }
10993                 }
10994             }
10995             if(o.style){
10996                 Roo.DomHelper.applyStyles(el, o.style);
10997             }
10998             return this;
10999         },
11000
11001         /**
11002          * Convenience method for constructing a KeyMap
11003          * @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:
11004          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
11005          * @param {Function} fn The function to call
11006          * @param {Object} scope (optional) The scope of the function
11007          * @return {Roo.KeyMap} The KeyMap created
11008          */
11009         addKeyListener : function(key, fn, scope){
11010             var config;
11011             if(typeof key != "object" || key instanceof Array){
11012                 config = {
11013                     key: key,
11014                     fn: fn,
11015                     scope: scope
11016                 };
11017             }else{
11018                 config = {
11019                     key : key.key,
11020                     shift : key.shift,
11021                     ctrl : key.ctrl,
11022                     alt : key.alt,
11023                     fn: fn,
11024                     scope: scope
11025                 };
11026             }
11027             return new Roo.KeyMap(this, config);
11028         },
11029
11030         /**
11031          * Creates a KeyMap for this element
11032          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11033          * @return {Roo.KeyMap} The KeyMap created
11034          */
11035         addKeyMap : function(config){
11036             return new Roo.KeyMap(this, config);
11037         },
11038
11039         /**
11040          * Returns true if this element is scrollable.
11041          * @return {Boolean}
11042          */
11043          isScrollable : function(){
11044             var dom = this.dom;
11045             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11046         },
11047
11048         /**
11049          * 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().
11050          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11051          * @param {Number} value The new scroll value
11052          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11053          * @return {Element} this
11054          */
11055
11056         scrollTo : function(side, value, animate){
11057             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11058             if(!animate || !A){
11059                 this.dom[prop] = value;
11060             }else{
11061                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11062                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11063             }
11064             return this;
11065         },
11066
11067         /**
11068          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11069          * within this element's scrollable range.
11070          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11071          * @param {Number} distance How far to scroll the element in pixels
11072          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11073          * @return {Boolean} Returns true if a scroll was triggered or false if the element
11074          * was scrolled as far as it could go.
11075          */
11076          scroll : function(direction, distance, animate){
11077              if(!this.isScrollable()){
11078                  return;
11079              }
11080              var el = this.dom;
11081              var l = el.scrollLeft, t = el.scrollTop;
11082              var w = el.scrollWidth, h = el.scrollHeight;
11083              var cw = el.clientWidth, ch = el.clientHeight;
11084              direction = direction.toLowerCase();
11085              var scrolled = false;
11086              var a = this.preanim(arguments, 2);
11087              switch(direction){
11088                  case "l":
11089                  case "left":
11090                      if(w - l > cw){
11091                          var v = Math.min(l + distance, w-cw);
11092                          this.scrollTo("left", v, a);
11093                          scrolled = true;
11094                      }
11095                      break;
11096                 case "r":
11097                 case "right":
11098                      if(l > 0){
11099                          var v = Math.max(l - distance, 0);
11100                          this.scrollTo("left", v, a);
11101                          scrolled = true;
11102                      }
11103                      break;
11104                 case "t":
11105                 case "top":
11106                 case "up":
11107                      if(t > 0){
11108                          var v = Math.max(t - distance, 0);
11109                          this.scrollTo("top", v, a);
11110                          scrolled = true;
11111                      }
11112                      break;
11113                 case "b":
11114                 case "bottom":
11115                 case "down":
11116                      if(h - t > ch){
11117                          var v = Math.min(t + distance, h-ch);
11118                          this.scrollTo("top", v, a);
11119                          scrolled = true;
11120                      }
11121                      break;
11122              }
11123              return scrolled;
11124         },
11125
11126         /**
11127          * Translates the passed page coordinates into left/top css values for this element
11128          * @param {Number/Array} x The page x or an array containing [x, y]
11129          * @param {Number} y The page y
11130          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11131          */
11132         translatePoints : function(x, y){
11133             if(typeof x == 'object' || x instanceof Array){
11134                 y = x[1]; x = x[0];
11135             }
11136             var p = this.getStyle('position');
11137             var o = this.getXY();
11138
11139             var l = parseInt(this.getStyle('left'), 10);
11140             var t = parseInt(this.getStyle('top'), 10);
11141
11142             if(isNaN(l)){
11143                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11144             }
11145             if(isNaN(t)){
11146                 t = (p == "relative") ? 0 : this.dom.offsetTop;
11147             }
11148
11149             return {left: (x - o[0] + l), top: (y - o[1] + t)};
11150         },
11151
11152         /**
11153          * Returns the current scroll position of the element.
11154          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11155          */
11156         getScroll : function(){
11157             var d = this.dom, doc = document;
11158             if(d == doc || d == doc.body){
11159                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11160                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11161                 return {left: l, top: t};
11162             }else{
11163                 return {left: d.scrollLeft, top: d.scrollTop};
11164             }
11165         },
11166
11167         /**
11168          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11169          * are convert to standard 6 digit hex color.
11170          * @param {String} attr The css attribute
11171          * @param {String} defaultValue The default value to use when a valid color isn't found
11172          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11173          * YUI color anims.
11174          */
11175         getColor : function(attr, defaultValue, prefix){
11176             var v = this.getStyle(attr);
11177             if(!v || v == "transparent" || v == "inherit") {
11178                 return defaultValue;
11179             }
11180             var color = typeof prefix == "undefined" ? "#" : prefix;
11181             if(v.substr(0, 4) == "rgb("){
11182                 var rvs = v.slice(4, v.length -1).split(",");
11183                 for(var i = 0; i < 3; i++){
11184                     var h = parseInt(rvs[i]).toString(16);
11185                     if(h < 16){
11186                         h = "0" + h;
11187                     }
11188                     color += h;
11189                 }
11190             } else {
11191                 if(v.substr(0, 1) == "#"){
11192                     if(v.length == 4) {
11193                         for(var i = 1; i < 4; i++){
11194                             var c = v.charAt(i);
11195                             color +=  c + c;
11196                         }
11197                     }else if(v.length == 7){
11198                         color += v.substr(1);
11199                     }
11200                 }
11201             }
11202             return(color.length > 5 ? color.toLowerCase() : defaultValue);
11203         },
11204
11205         /**
11206          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11207          * gradient background, rounded corners and a 4-way shadow.
11208          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11209          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11210          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11211          * @return {Roo.Element} this
11212          */
11213         boxWrap : function(cls){
11214             cls = cls || 'x-box';
11215             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11216             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11217             return el;
11218         },
11219
11220         /**
11221          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11222          * @param {String} namespace The namespace in which to look for the attribute
11223          * @param {String} name The attribute name
11224          * @return {String} The attribute value
11225          */
11226         getAttributeNS : Roo.isIE ? function(ns, name){
11227             var d = this.dom;
11228             var type = typeof d[ns+":"+name];
11229             if(type != 'undefined' && type != 'unknown'){
11230                 return d[ns+":"+name];
11231             }
11232             return d[name];
11233         } : function(ns, name){
11234             var d = this.dom;
11235             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11236         },
11237         
11238         
11239         /**
11240          * Sets or Returns the value the dom attribute value
11241          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11242          * @param {String} value (optional) The value to set the attribute to
11243          * @return {String} The attribute value
11244          */
11245         attr : function(name){
11246             if (arguments.length > 1) {
11247                 this.dom.setAttribute(name, arguments[1]);
11248                 return arguments[1];
11249             }
11250             if (typeof(name) == 'object') {
11251                 for(var i in name) {
11252                     this.attr(i, name[i]);
11253                 }
11254                 return name;
11255             }
11256             
11257             
11258             if (!this.dom.hasAttribute(name)) {
11259                 return undefined;
11260             }
11261             return this.dom.getAttribute(name);
11262         }
11263         
11264         
11265         
11266     };
11267
11268     var ep = El.prototype;
11269
11270     /**
11271      * Appends an event handler (Shorthand for addListener)
11272      * @param {String}   eventName     The type of event to append
11273      * @param {Function} fn        The method the event invokes
11274      * @param {Object} scope       (optional) The scope (this object) of the fn
11275      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11276      * @method
11277      */
11278     ep.on = ep.addListener;
11279         // backwards compat
11280     ep.mon = ep.addListener;
11281
11282     /**
11283      * Removes an event handler from this element (shorthand for removeListener)
11284      * @param {String} eventName the type of event to remove
11285      * @param {Function} fn the method the event invokes
11286      * @return {Roo.Element} this
11287      * @method
11288      */
11289     ep.un = ep.removeListener;
11290
11291     /**
11292      * true to automatically adjust width and height settings for box-model issues (default to true)
11293      */
11294     ep.autoBoxAdjust = true;
11295
11296     // private
11297     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11298
11299     // private
11300     El.addUnits = function(v, defaultUnit){
11301         if(v === "" || v == "auto"){
11302             return v;
11303         }
11304         if(v === undefined){
11305             return '';
11306         }
11307         if(typeof v == "number" || !El.unitPattern.test(v)){
11308             return v + (defaultUnit || 'px');
11309         }
11310         return v;
11311     };
11312
11313     // special markup used throughout Roo when box wrapping elements
11314     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>';
11315     /**
11316      * Visibility mode constant - Use visibility to hide element
11317      * @static
11318      * @type Number
11319      */
11320     El.VISIBILITY = 1;
11321     /**
11322      * Visibility mode constant - Use display to hide element
11323      * @static
11324      * @type Number
11325      */
11326     El.DISPLAY = 2;
11327
11328     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11329     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11330     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11331
11332
11333
11334     /**
11335      * @private
11336      */
11337     El.cache = {};
11338
11339     var docEl;
11340
11341     /**
11342      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11343      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11344      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11345      * @return {Element} The Element object
11346      * @static
11347      */
11348     El.get = function(el){
11349         var ex, elm, id;
11350         if(!el){ return null; }
11351         if(typeof el == "string"){ // element id
11352             if(!(elm = document.getElementById(el))){
11353                 return null;
11354             }
11355             if(ex = El.cache[el]){
11356                 ex.dom = elm;
11357             }else{
11358                 ex = El.cache[el] = new El(elm);
11359             }
11360             return ex;
11361         }else if(el.tagName){ // dom element
11362             if(!(id = el.id)){
11363                 id = Roo.id(el);
11364             }
11365             if(ex = El.cache[id]){
11366                 ex.dom = el;
11367             }else{
11368                 ex = El.cache[id] = new El(el);
11369             }
11370             return ex;
11371         }else if(el instanceof El){
11372             if(el != docEl){
11373                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11374                                                               // catch case where it hasn't been appended
11375                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11376             }
11377             return el;
11378         }else if(el.isComposite){
11379             return el;
11380         }else if(el instanceof Array){
11381             return El.select(el);
11382         }else if(el == document){
11383             // create a bogus element object representing the document object
11384             if(!docEl){
11385                 var f = function(){};
11386                 f.prototype = El.prototype;
11387                 docEl = new f();
11388                 docEl.dom = document;
11389             }
11390             return docEl;
11391         }
11392         return null;
11393     };
11394
11395     // private
11396     El.uncache = function(el){
11397         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11398             if(a[i]){
11399                 delete El.cache[a[i].id || a[i]];
11400             }
11401         }
11402     };
11403
11404     // private
11405     // Garbage collection - uncache elements/purge listeners on orphaned elements
11406     // so we don't hold a reference and cause the browser to retain them
11407     El.garbageCollect = function(){
11408         if(!Roo.enableGarbageCollector){
11409             clearInterval(El.collectorThread);
11410             return;
11411         }
11412         for(var eid in El.cache){
11413             var el = El.cache[eid], d = el.dom;
11414             // -------------------------------------------------------
11415             // Determining what is garbage:
11416             // -------------------------------------------------------
11417             // !d
11418             // dom node is null, definitely garbage
11419             // -------------------------------------------------------
11420             // !d.parentNode
11421             // no parentNode == direct orphan, definitely garbage
11422             // -------------------------------------------------------
11423             // !d.offsetParent && !document.getElementById(eid)
11424             // display none elements have no offsetParent so we will
11425             // also try to look it up by it's id. However, check
11426             // offsetParent first so we don't do unneeded lookups.
11427             // This enables collection of elements that are not orphans
11428             // directly, but somewhere up the line they have an orphan
11429             // parent.
11430             // -------------------------------------------------------
11431             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11432                 delete El.cache[eid];
11433                 if(d && Roo.enableListenerCollection){
11434                     E.purgeElement(d);
11435                 }
11436             }
11437         }
11438     }
11439     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11440
11441
11442     // dom is optional
11443     El.Flyweight = function(dom){
11444         this.dom = dom;
11445     };
11446     El.Flyweight.prototype = El.prototype;
11447
11448     El._flyweights = {};
11449     /**
11450      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11451      * the dom node can be overwritten by other code.
11452      * @param {String/HTMLElement} el The dom node or id
11453      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11454      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11455      * @static
11456      * @return {Element} The shared Element object
11457      */
11458     El.fly = function(el, named){
11459         named = named || '_global';
11460         el = Roo.getDom(el);
11461         if(!el){
11462             return null;
11463         }
11464         if(!El._flyweights[named]){
11465             El._flyweights[named] = new El.Flyweight();
11466         }
11467         El._flyweights[named].dom = el;
11468         return El._flyweights[named];
11469     };
11470
11471     /**
11472      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11473      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11474      * Shorthand of {@link Roo.Element#get}
11475      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11476      * @return {Element} The Element object
11477      * @member Roo
11478      * @method get
11479      */
11480     Roo.get = El.get;
11481     /**
11482      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11483      * the dom node can be overwritten by other code.
11484      * Shorthand of {@link Roo.Element#fly}
11485      * @param {String/HTMLElement} el The dom node or id
11486      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11487      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11488      * @static
11489      * @return {Element} The shared Element object
11490      * @member Roo
11491      * @method fly
11492      */
11493     Roo.fly = El.fly;
11494
11495     // speedy lookup for elements never to box adjust
11496     var noBoxAdjust = Roo.isStrict ? {
11497         select:1
11498     } : {
11499         input:1, select:1, textarea:1
11500     };
11501     if(Roo.isIE || Roo.isGecko){
11502         noBoxAdjust['button'] = 1;
11503     }
11504
11505
11506     Roo.EventManager.on(window, 'unload', function(){
11507         delete El.cache;
11508         delete El._flyweights;
11509     });
11510 })();
11511
11512
11513
11514
11515 if(Roo.DomQuery){
11516     Roo.Element.selectorFunction = Roo.DomQuery.select;
11517 }
11518
11519 Roo.Element.select = function(selector, unique, root){
11520     var els;
11521     if(typeof selector == "string"){
11522         els = Roo.Element.selectorFunction(selector, root);
11523     }else if(selector.length !== undefined){
11524         els = selector;
11525     }else{
11526         throw "Invalid selector";
11527     }
11528     if(unique === true){
11529         return new Roo.CompositeElement(els);
11530     }else{
11531         return new Roo.CompositeElementLite(els);
11532     }
11533 };
11534 /**
11535  * Selects elements based on the passed CSS selector to enable working on them as 1.
11536  * @param {String/Array} selector The CSS selector or an array of elements
11537  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11538  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11539  * @return {CompositeElementLite/CompositeElement}
11540  * @member Roo
11541  * @method select
11542  */
11543 Roo.select = Roo.Element.select;
11544
11545
11546
11547
11548
11549
11550
11551
11552
11553
11554
11555
11556
11557
11558 /*
11559  * Based on:
11560  * Ext JS Library 1.1.1
11561  * Copyright(c) 2006-2007, Ext JS, LLC.
11562  *
11563  * Originally Released Under LGPL - original licence link has changed is not relivant.
11564  *
11565  * Fork - LGPL
11566  * <script type="text/javascript">
11567  */
11568
11569
11570
11571 //Notifies Element that fx methods are available
11572 Roo.enableFx = true;
11573
11574 /**
11575  * @class Roo.Fx
11576  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11577  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11578  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11579  * Element effects to work.</p><br/>
11580  *
11581  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11582  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11583  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11584  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11585  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11586  * expected results and should be done with care.</p><br/>
11587  *
11588  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11589  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11590 <pre>
11591 Value  Description
11592 -----  -----------------------------
11593 tl     The top left corner
11594 t      The center of the top edge
11595 tr     The top right corner
11596 l      The center of the left edge
11597 r      The center of the right edge
11598 bl     The bottom left corner
11599 b      The center of the bottom edge
11600 br     The bottom right corner
11601 </pre>
11602  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11603  * below are common options that can be passed to any Fx method.</b>
11604  * @cfg {Function} callback A function called when the effect is finished
11605  * @cfg {Object} scope The scope of the effect function
11606  * @cfg {String} easing A valid Easing value for the effect
11607  * @cfg {String} afterCls A css class to apply after the effect
11608  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11609  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11610  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11611  * effects that end with the element being visually hidden, ignored otherwise)
11612  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11613  * a function which returns such a specification that will be applied to the Element after the effect finishes
11614  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11615  * @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
11616  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11617  */
11618 Roo.Fx = {
11619         /**
11620          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11621          * origin for the slide effect.  This function automatically handles wrapping the element with
11622          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11623          * Usage:
11624          *<pre><code>
11625 // default: slide the element in from the top
11626 el.slideIn();
11627
11628 // custom: slide the element in from the right with a 2-second duration
11629 el.slideIn('r', { duration: 2 });
11630
11631 // common config options shown with default values
11632 el.slideIn('t', {
11633     easing: 'easeOut',
11634     duration: .5
11635 });
11636 </code></pre>
11637          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11638          * @param {Object} options (optional) Object literal with any of the Fx config options
11639          * @return {Roo.Element} The Element
11640          */
11641     slideIn : function(anchor, o){
11642         var el = this.getFxEl();
11643         o = o || {};
11644
11645         el.queueFx(o, function(){
11646
11647             anchor = anchor || "t";
11648
11649             // fix display to visibility
11650             this.fixDisplay();
11651
11652             // restore values after effect
11653             var r = this.getFxRestore();
11654             var b = this.getBox();
11655             // fixed size for slide
11656             this.setSize(b);
11657
11658             // wrap if needed
11659             var wrap = this.fxWrap(r.pos, o, "hidden");
11660
11661             var st = this.dom.style;
11662             st.visibility = "visible";
11663             st.position = "absolute";
11664
11665             // clear out temp styles after slide and unwrap
11666             var after = function(){
11667                 el.fxUnwrap(wrap, r.pos, o);
11668                 st.width = r.width;
11669                 st.height = r.height;
11670                 el.afterFx(o);
11671             };
11672             // time to calc the positions
11673             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11674
11675             switch(anchor.toLowerCase()){
11676                 case "t":
11677                     wrap.setSize(b.width, 0);
11678                     st.left = st.bottom = "0";
11679                     a = {height: bh};
11680                 break;
11681                 case "l":
11682                     wrap.setSize(0, b.height);
11683                     st.right = st.top = "0";
11684                     a = {width: bw};
11685                 break;
11686                 case "r":
11687                     wrap.setSize(0, b.height);
11688                     wrap.setX(b.right);
11689                     st.left = st.top = "0";
11690                     a = {width: bw, points: pt};
11691                 break;
11692                 case "b":
11693                     wrap.setSize(b.width, 0);
11694                     wrap.setY(b.bottom);
11695                     st.left = st.top = "0";
11696                     a = {height: bh, points: pt};
11697                 break;
11698                 case "tl":
11699                     wrap.setSize(0, 0);
11700                     st.right = st.bottom = "0";
11701                     a = {width: bw, height: bh};
11702                 break;
11703                 case "bl":
11704                     wrap.setSize(0, 0);
11705                     wrap.setY(b.y+b.height);
11706                     st.right = st.top = "0";
11707                     a = {width: bw, height: bh, points: pt};
11708                 break;
11709                 case "br":
11710                     wrap.setSize(0, 0);
11711                     wrap.setXY([b.right, b.bottom]);
11712                     st.left = st.top = "0";
11713                     a = {width: bw, height: bh, points: pt};
11714                 break;
11715                 case "tr":
11716                     wrap.setSize(0, 0);
11717                     wrap.setX(b.x+b.width);
11718                     st.left = st.bottom = "0";
11719                     a = {width: bw, height: bh, points: pt};
11720                 break;
11721             }
11722             this.dom.style.visibility = "visible";
11723             wrap.show();
11724
11725             arguments.callee.anim = wrap.fxanim(a,
11726                 o,
11727                 'motion',
11728                 .5,
11729                 'easeOut', after);
11730         });
11731         return this;
11732     },
11733     
11734         /**
11735          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11736          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11737          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11738          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11739          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11740          * Usage:
11741          *<pre><code>
11742 // default: slide the element out to the top
11743 el.slideOut();
11744
11745 // custom: slide the element out to the right with a 2-second duration
11746 el.slideOut('r', { duration: 2 });
11747
11748 // common config options shown with default values
11749 el.slideOut('t', {
11750     easing: 'easeOut',
11751     duration: .5,
11752     remove: false,
11753     useDisplay: false
11754 });
11755 </code></pre>
11756          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11757          * @param {Object} options (optional) Object literal with any of the Fx config options
11758          * @return {Roo.Element} The Element
11759          */
11760     slideOut : function(anchor, o){
11761         var el = this.getFxEl();
11762         o = o || {};
11763
11764         el.queueFx(o, function(){
11765
11766             anchor = anchor || "t";
11767
11768             // restore values after effect
11769             var r = this.getFxRestore();
11770             
11771             var b = this.getBox();
11772             // fixed size for slide
11773             this.setSize(b);
11774
11775             // wrap if needed
11776             var wrap = this.fxWrap(r.pos, o, "visible");
11777
11778             var st = this.dom.style;
11779             st.visibility = "visible";
11780             st.position = "absolute";
11781
11782             wrap.setSize(b);
11783
11784             var after = function(){
11785                 if(o.useDisplay){
11786                     el.setDisplayed(false);
11787                 }else{
11788                     el.hide();
11789                 }
11790
11791                 el.fxUnwrap(wrap, r.pos, o);
11792
11793                 st.width = r.width;
11794                 st.height = r.height;
11795
11796                 el.afterFx(o);
11797             };
11798
11799             var a, zero = {to: 0};
11800             switch(anchor.toLowerCase()){
11801                 case "t":
11802                     st.left = st.bottom = "0";
11803                     a = {height: zero};
11804                 break;
11805                 case "l":
11806                     st.right = st.top = "0";
11807                     a = {width: zero};
11808                 break;
11809                 case "r":
11810                     st.left = st.top = "0";
11811                     a = {width: zero, points: {to:[b.right, b.y]}};
11812                 break;
11813                 case "b":
11814                     st.left = st.top = "0";
11815                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11816                 break;
11817                 case "tl":
11818                     st.right = st.bottom = "0";
11819                     a = {width: zero, height: zero};
11820                 break;
11821                 case "bl":
11822                     st.right = st.top = "0";
11823                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11824                 break;
11825                 case "br":
11826                     st.left = st.top = "0";
11827                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11828                 break;
11829                 case "tr":
11830                     st.left = st.bottom = "0";
11831                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11832                 break;
11833             }
11834
11835             arguments.callee.anim = wrap.fxanim(a,
11836                 o,
11837                 'motion',
11838                 .5,
11839                 "easeOut", after);
11840         });
11841         return this;
11842     },
11843
11844         /**
11845          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11846          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11847          * The element must be removed from the DOM using the 'remove' config option if desired.
11848          * Usage:
11849          *<pre><code>
11850 // default
11851 el.puff();
11852
11853 // common config options shown with default values
11854 el.puff({
11855     easing: 'easeOut',
11856     duration: .5,
11857     remove: false,
11858     useDisplay: false
11859 });
11860 </code></pre>
11861          * @param {Object} options (optional) Object literal with any of the Fx config options
11862          * @return {Roo.Element} The Element
11863          */
11864     puff : function(o){
11865         var el = this.getFxEl();
11866         o = o || {};
11867
11868         el.queueFx(o, function(){
11869             this.clearOpacity();
11870             this.show();
11871
11872             // restore values after effect
11873             var r = this.getFxRestore();
11874             var st = this.dom.style;
11875
11876             var after = function(){
11877                 if(o.useDisplay){
11878                     el.setDisplayed(false);
11879                 }else{
11880                     el.hide();
11881                 }
11882
11883                 el.clearOpacity();
11884
11885                 el.setPositioning(r.pos);
11886                 st.width = r.width;
11887                 st.height = r.height;
11888                 st.fontSize = '';
11889                 el.afterFx(o);
11890             };
11891
11892             var width = this.getWidth();
11893             var height = this.getHeight();
11894
11895             arguments.callee.anim = this.fxanim({
11896                     width : {to: this.adjustWidth(width * 2)},
11897                     height : {to: this.adjustHeight(height * 2)},
11898                     points : {by: [-(width * .5), -(height * .5)]},
11899                     opacity : {to: 0},
11900                     fontSize: {to:200, unit: "%"}
11901                 },
11902                 o,
11903                 'motion',
11904                 .5,
11905                 "easeOut", after);
11906         });
11907         return this;
11908     },
11909
11910         /**
11911          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11912          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11913          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11914          * Usage:
11915          *<pre><code>
11916 // default
11917 el.switchOff();
11918
11919 // all config options shown with default values
11920 el.switchOff({
11921     easing: 'easeIn',
11922     duration: .3,
11923     remove: false,
11924     useDisplay: false
11925 });
11926 </code></pre>
11927          * @param {Object} options (optional) Object literal with any of the Fx config options
11928          * @return {Roo.Element} The Element
11929          */
11930     switchOff : function(o){
11931         var el = this.getFxEl();
11932         o = o || {};
11933
11934         el.queueFx(o, function(){
11935             this.clearOpacity();
11936             this.clip();
11937
11938             // restore values after effect
11939             var r = this.getFxRestore();
11940             var st = this.dom.style;
11941
11942             var after = function(){
11943                 if(o.useDisplay){
11944                     el.setDisplayed(false);
11945                 }else{
11946                     el.hide();
11947                 }
11948
11949                 el.clearOpacity();
11950                 el.setPositioning(r.pos);
11951                 st.width = r.width;
11952                 st.height = r.height;
11953
11954                 el.afterFx(o);
11955             };
11956
11957             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11958                 this.clearOpacity();
11959                 (function(){
11960                     this.fxanim({
11961                         height:{to:1},
11962                         points:{by:[0, this.getHeight() * .5]}
11963                     }, o, 'motion', 0.3, 'easeIn', after);
11964                 }).defer(100, this);
11965             });
11966         });
11967         return this;
11968     },
11969
11970     /**
11971      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11972      * changed using the "attr" config option) and then fading back to the original color. If no original
11973      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11974      * Usage:
11975 <pre><code>
11976 // default: highlight background to yellow
11977 el.highlight();
11978
11979 // custom: highlight foreground text to blue for 2 seconds
11980 el.highlight("0000ff", { attr: 'color', duration: 2 });
11981
11982 // common config options shown with default values
11983 el.highlight("ffff9c", {
11984     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11985     endColor: (current color) or "ffffff",
11986     easing: 'easeIn',
11987     duration: 1
11988 });
11989 </code></pre>
11990      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11991      * @param {Object} options (optional) Object literal with any of the Fx config options
11992      * @return {Roo.Element} The Element
11993      */ 
11994     highlight : function(color, o){
11995         var el = this.getFxEl();
11996         o = o || {};
11997
11998         el.queueFx(o, function(){
11999             color = color || "ffff9c";
12000             attr = o.attr || "backgroundColor";
12001
12002             this.clearOpacity();
12003             this.show();
12004
12005             var origColor = this.getColor(attr);
12006             var restoreColor = this.dom.style[attr];
12007             endColor = (o.endColor || origColor) || "ffffff";
12008
12009             var after = function(){
12010                 el.dom.style[attr] = restoreColor;
12011                 el.afterFx(o);
12012             };
12013
12014             var a = {};
12015             a[attr] = {from: color, to: endColor};
12016             arguments.callee.anim = this.fxanim(a,
12017                 o,
12018                 'color',
12019                 1,
12020                 'easeIn', after);
12021         });
12022         return this;
12023     },
12024
12025    /**
12026     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
12027     * Usage:
12028 <pre><code>
12029 // default: a single light blue ripple
12030 el.frame();
12031
12032 // custom: 3 red ripples lasting 3 seconds total
12033 el.frame("ff0000", 3, { duration: 3 });
12034
12035 // common config options shown with default values
12036 el.frame("C3DAF9", 1, {
12037     duration: 1 //duration of entire animation (not each individual ripple)
12038     // Note: Easing is not configurable and will be ignored if included
12039 });
12040 </code></pre>
12041     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12042     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12043     * @param {Object} options (optional) Object literal with any of the Fx config options
12044     * @return {Roo.Element} The Element
12045     */
12046     frame : function(color, count, o){
12047         var el = this.getFxEl();
12048         o = o || {};
12049
12050         el.queueFx(o, function(){
12051             color = color || "#C3DAF9";
12052             if(color.length == 6){
12053                 color = "#" + color;
12054             }
12055             count = count || 1;
12056             duration = o.duration || 1;
12057             this.show();
12058
12059             var b = this.getBox();
12060             var animFn = function(){
12061                 var proxy = this.createProxy({
12062
12063                      style:{
12064                         visbility:"hidden",
12065                         position:"absolute",
12066                         "z-index":"35000", // yee haw
12067                         border:"0px solid " + color
12068                      }
12069                   });
12070                 var scale = Roo.isBorderBox ? 2 : 1;
12071                 proxy.animate({
12072                     top:{from:b.y, to:b.y - 20},
12073                     left:{from:b.x, to:b.x - 20},
12074                     borderWidth:{from:0, to:10},
12075                     opacity:{from:1, to:0},
12076                     height:{from:b.height, to:(b.height + (20*scale))},
12077                     width:{from:b.width, to:(b.width + (20*scale))}
12078                 }, duration, function(){
12079                     proxy.remove();
12080                 });
12081                 if(--count > 0){
12082                      animFn.defer((duration/2)*1000, this);
12083                 }else{
12084                     el.afterFx(o);
12085                 }
12086             };
12087             animFn.call(this);
12088         });
12089         return this;
12090     },
12091
12092    /**
12093     * Creates a pause before any subsequent queued effects begin.  If there are
12094     * no effects queued after the pause it will have no effect.
12095     * Usage:
12096 <pre><code>
12097 el.pause(1);
12098 </code></pre>
12099     * @param {Number} seconds The length of time to pause (in seconds)
12100     * @return {Roo.Element} The Element
12101     */
12102     pause : function(seconds){
12103         var el = this.getFxEl();
12104         var o = {};
12105
12106         el.queueFx(o, function(){
12107             setTimeout(function(){
12108                 el.afterFx(o);
12109             }, seconds * 1000);
12110         });
12111         return this;
12112     },
12113
12114    /**
12115     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
12116     * using the "endOpacity" config option.
12117     * Usage:
12118 <pre><code>
12119 // default: fade in from opacity 0 to 100%
12120 el.fadeIn();
12121
12122 // custom: fade in from opacity 0 to 75% over 2 seconds
12123 el.fadeIn({ endOpacity: .75, duration: 2});
12124
12125 // common config options shown with default values
12126 el.fadeIn({
12127     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12128     easing: 'easeOut',
12129     duration: .5
12130 });
12131 </code></pre>
12132     * @param {Object} options (optional) Object literal with any of the Fx config options
12133     * @return {Roo.Element} The Element
12134     */
12135     fadeIn : function(o){
12136         var el = this.getFxEl();
12137         o = o || {};
12138         el.queueFx(o, function(){
12139             this.setOpacity(0);
12140             this.fixDisplay();
12141             this.dom.style.visibility = 'visible';
12142             var to = o.endOpacity || 1;
12143             arguments.callee.anim = this.fxanim({opacity:{to:to}},
12144                 o, null, .5, "easeOut", function(){
12145                 if(to == 1){
12146                     this.clearOpacity();
12147                 }
12148                 el.afterFx(o);
12149             });
12150         });
12151         return this;
12152     },
12153
12154    /**
12155     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
12156     * using the "endOpacity" config option.
12157     * Usage:
12158 <pre><code>
12159 // default: fade out from the element's current opacity to 0
12160 el.fadeOut();
12161
12162 // custom: fade out from the element's current opacity to 25% over 2 seconds
12163 el.fadeOut({ endOpacity: .25, duration: 2});
12164
12165 // common config options shown with default values
12166 el.fadeOut({
12167     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12168     easing: 'easeOut',
12169     duration: .5
12170     remove: false,
12171     useDisplay: false
12172 });
12173 </code></pre>
12174     * @param {Object} options (optional) Object literal with any of the Fx config options
12175     * @return {Roo.Element} The Element
12176     */
12177     fadeOut : function(o){
12178         var el = this.getFxEl();
12179         o = o || {};
12180         el.queueFx(o, function(){
12181             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12182                 o, null, .5, "easeOut", function(){
12183                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12184                      this.dom.style.display = "none";
12185                 }else{
12186                      this.dom.style.visibility = "hidden";
12187                 }
12188                 this.clearOpacity();
12189                 el.afterFx(o);
12190             });
12191         });
12192         return this;
12193     },
12194
12195    /**
12196     * Animates the transition of an element's dimensions from a starting height/width
12197     * to an ending height/width.
12198     * Usage:
12199 <pre><code>
12200 // change height and width to 100x100 pixels
12201 el.scale(100, 100);
12202
12203 // common config options shown with default values.  The height and width will default to
12204 // the element's existing values if passed as null.
12205 el.scale(
12206     [element's width],
12207     [element's height], {
12208     easing: 'easeOut',
12209     duration: .35
12210 });
12211 </code></pre>
12212     * @param {Number} width  The new width (pass undefined to keep the original width)
12213     * @param {Number} height  The new height (pass undefined to keep the original height)
12214     * @param {Object} options (optional) Object literal with any of the Fx config options
12215     * @return {Roo.Element} The Element
12216     */
12217     scale : function(w, h, o){
12218         this.shift(Roo.apply({}, o, {
12219             width: w,
12220             height: h
12221         }));
12222         return this;
12223     },
12224
12225    /**
12226     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12227     * Any of these properties not specified in the config object will not be changed.  This effect 
12228     * requires that at least one new dimension, position or opacity setting must be passed in on
12229     * the config object in order for the function to have any effect.
12230     * Usage:
12231 <pre><code>
12232 // slide the element horizontally to x position 200 while changing the height and opacity
12233 el.shift({ x: 200, height: 50, opacity: .8 });
12234
12235 // common config options shown with default values.
12236 el.shift({
12237     width: [element's width],
12238     height: [element's height],
12239     x: [element's x position],
12240     y: [element's y position],
12241     opacity: [element's opacity],
12242     easing: 'easeOut',
12243     duration: .35
12244 });
12245 </code></pre>
12246     * @param {Object} options  Object literal with any of the Fx config options
12247     * @return {Roo.Element} The Element
12248     */
12249     shift : function(o){
12250         var el = this.getFxEl();
12251         o = o || {};
12252         el.queueFx(o, function(){
12253             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12254             if(w !== undefined){
12255                 a.width = {to: this.adjustWidth(w)};
12256             }
12257             if(h !== undefined){
12258                 a.height = {to: this.adjustHeight(h)};
12259             }
12260             if(x !== undefined || y !== undefined){
12261                 a.points = {to: [
12262                     x !== undefined ? x : this.getX(),
12263                     y !== undefined ? y : this.getY()
12264                 ]};
12265             }
12266             if(op !== undefined){
12267                 a.opacity = {to: op};
12268             }
12269             if(o.xy !== undefined){
12270                 a.points = {to: o.xy};
12271             }
12272             arguments.callee.anim = this.fxanim(a,
12273                 o, 'motion', .35, "easeOut", function(){
12274                 el.afterFx(o);
12275             });
12276         });
12277         return this;
12278     },
12279
12280         /**
12281          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12282          * ending point of the effect.
12283          * Usage:
12284          *<pre><code>
12285 // default: slide the element downward while fading out
12286 el.ghost();
12287
12288 // custom: slide the element out to the right with a 2-second duration
12289 el.ghost('r', { duration: 2 });
12290
12291 // common config options shown with default values
12292 el.ghost('b', {
12293     easing: 'easeOut',
12294     duration: .5
12295     remove: false,
12296     useDisplay: false
12297 });
12298 </code></pre>
12299          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12300          * @param {Object} options (optional) Object literal with any of the Fx config options
12301          * @return {Roo.Element} The Element
12302          */
12303     ghost : function(anchor, o){
12304         var el = this.getFxEl();
12305         o = o || {};
12306
12307         el.queueFx(o, function(){
12308             anchor = anchor || "b";
12309
12310             // restore values after effect
12311             var r = this.getFxRestore();
12312             var w = this.getWidth(),
12313                 h = this.getHeight();
12314
12315             var st = this.dom.style;
12316
12317             var after = function(){
12318                 if(o.useDisplay){
12319                     el.setDisplayed(false);
12320                 }else{
12321                     el.hide();
12322                 }
12323
12324                 el.clearOpacity();
12325                 el.setPositioning(r.pos);
12326                 st.width = r.width;
12327                 st.height = r.height;
12328
12329                 el.afterFx(o);
12330             };
12331
12332             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12333             switch(anchor.toLowerCase()){
12334                 case "t":
12335                     pt.by = [0, -h];
12336                 break;
12337                 case "l":
12338                     pt.by = [-w, 0];
12339                 break;
12340                 case "r":
12341                     pt.by = [w, 0];
12342                 break;
12343                 case "b":
12344                     pt.by = [0, h];
12345                 break;
12346                 case "tl":
12347                     pt.by = [-w, -h];
12348                 break;
12349                 case "bl":
12350                     pt.by = [-w, h];
12351                 break;
12352                 case "br":
12353                     pt.by = [w, h];
12354                 break;
12355                 case "tr":
12356                     pt.by = [w, -h];
12357                 break;
12358             }
12359
12360             arguments.callee.anim = this.fxanim(a,
12361                 o,
12362                 'motion',
12363                 .5,
12364                 "easeOut", after);
12365         });
12366         return this;
12367     },
12368
12369         /**
12370          * Ensures that all effects queued after syncFx is called on the element are
12371          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12372          * @return {Roo.Element} The Element
12373          */
12374     syncFx : function(){
12375         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12376             block : false,
12377             concurrent : true,
12378             stopFx : false
12379         });
12380         return this;
12381     },
12382
12383         /**
12384          * Ensures that all effects queued after sequenceFx is called on the element are
12385          * run in sequence.  This is the opposite of {@link #syncFx}.
12386          * @return {Roo.Element} The Element
12387          */
12388     sequenceFx : function(){
12389         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12390             block : false,
12391             concurrent : false,
12392             stopFx : false
12393         });
12394         return this;
12395     },
12396
12397         /* @private */
12398     nextFx : function(){
12399         var ef = this.fxQueue[0];
12400         if(ef){
12401             ef.call(this);
12402         }
12403     },
12404
12405         /**
12406          * Returns true if the element has any effects actively running or queued, else returns false.
12407          * @return {Boolean} True if element has active effects, else false
12408          */
12409     hasActiveFx : function(){
12410         return this.fxQueue && this.fxQueue[0];
12411     },
12412
12413         /**
12414          * Stops any running effects and clears the element's internal effects queue if it contains
12415          * any additional effects that haven't started yet.
12416          * @return {Roo.Element} The Element
12417          */
12418     stopFx : function(){
12419         if(this.hasActiveFx()){
12420             var cur = this.fxQueue[0];
12421             if(cur && cur.anim && cur.anim.isAnimated()){
12422                 this.fxQueue = [cur]; // clear out others
12423                 cur.anim.stop(true);
12424             }
12425         }
12426         return this;
12427     },
12428
12429         /* @private */
12430     beforeFx : function(o){
12431         if(this.hasActiveFx() && !o.concurrent){
12432            if(o.stopFx){
12433                this.stopFx();
12434                return true;
12435            }
12436            return false;
12437         }
12438         return true;
12439     },
12440
12441         /**
12442          * Returns true if the element is currently blocking so that no other effect can be queued
12443          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12444          * used to ensure that an effect initiated by a user action runs to completion prior to the
12445          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12446          * @return {Boolean} True if blocking, else false
12447          */
12448     hasFxBlock : function(){
12449         var q = this.fxQueue;
12450         return q && q[0] && q[0].block;
12451     },
12452
12453         /* @private */
12454     queueFx : function(o, fn){
12455         if(!this.fxQueue){
12456             this.fxQueue = [];
12457         }
12458         if(!this.hasFxBlock()){
12459             Roo.applyIf(o, this.fxDefaults);
12460             if(!o.concurrent){
12461                 var run = this.beforeFx(o);
12462                 fn.block = o.block;
12463                 this.fxQueue.push(fn);
12464                 if(run){
12465                     this.nextFx();
12466                 }
12467             }else{
12468                 fn.call(this);
12469             }
12470         }
12471         return this;
12472     },
12473
12474         /* @private */
12475     fxWrap : function(pos, o, vis){
12476         var wrap;
12477         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12478             var wrapXY;
12479             if(o.fixPosition){
12480                 wrapXY = this.getXY();
12481             }
12482             var div = document.createElement("div");
12483             div.style.visibility = vis;
12484             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12485             wrap.setPositioning(pos);
12486             if(wrap.getStyle("position") == "static"){
12487                 wrap.position("relative");
12488             }
12489             this.clearPositioning('auto');
12490             wrap.clip();
12491             wrap.dom.appendChild(this.dom);
12492             if(wrapXY){
12493                 wrap.setXY(wrapXY);
12494             }
12495         }
12496         return wrap;
12497     },
12498
12499         /* @private */
12500     fxUnwrap : function(wrap, pos, o){
12501         this.clearPositioning();
12502         this.setPositioning(pos);
12503         if(!o.wrap){
12504             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12505             wrap.remove();
12506         }
12507     },
12508
12509         /* @private */
12510     getFxRestore : function(){
12511         var st = this.dom.style;
12512         return {pos: this.getPositioning(), width: st.width, height : st.height};
12513     },
12514
12515         /* @private */
12516     afterFx : function(o){
12517         if(o.afterStyle){
12518             this.applyStyles(o.afterStyle);
12519         }
12520         if(o.afterCls){
12521             this.addClass(o.afterCls);
12522         }
12523         if(o.remove === true){
12524             this.remove();
12525         }
12526         Roo.callback(o.callback, o.scope, [this]);
12527         if(!o.concurrent){
12528             this.fxQueue.shift();
12529             this.nextFx();
12530         }
12531     },
12532
12533         /* @private */
12534     getFxEl : function(){ // support for composite element fx
12535         return Roo.get(this.dom);
12536     },
12537
12538         /* @private */
12539     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12540         animType = animType || 'run';
12541         opt = opt || {};
12542         var anim = Roo.lib.Anim[animType](
12543             this.dom, args,
12544             (opt.duration || defaultDur) || .35,
12545             (opt.easing || defaultEase) || 'easeOut',
12546             function(){
12547                 Roo.callback(cb, this);
12548             },
12549             this
12550         );
12551         opt.anim = anim;
12552         return anim;
12553     }
12554 };
12555
12556 // backwords compat
12557 Roo.Fx.resize = Roo.Fx.scale;
12558
12559 //When included, Roo.Fx is automatically applied to Element so that all basic
12560 //effects are available directly via the Element API
12561 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12562  * Based on:
12563  * Ext JS Library 1.1.1
12564  * Copyright(c) 2006-2007, Ext JS, LLC.
12565  *
12566  * Originally Released Under LGPL - original licence link has changed is not relivant.
12567  *
12568  * Fork - LGPL
12569  * <script type="text/javascript">
12570  */
12571
12572
12573 /**
12574  * @class Roo.CompositeElement
12575  * Standard composite class. Creates a Roo.Element for every element in the collection.
12576  * <br><br>
12577  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12578  * actions will be performed on all the elements in this collection.</b>
12579  * <br><br>
12580  * All methods return <i>this</i> and can be chained.
12581  <pre><code>
12582  var els = Roo.select("#some-el div.some-class", true);
12583  // or select directly from an existing element
12584  var el = Roo.get('some-el');
12585  el.select('div.some-class', true);
12586
12587  els.setWidth(100); // all elements become 100 width
12588  els.hide(true); // all elements fade out and hide
12589  // or
12590  els.setWidth(100).hide(true);
12591  </code></pre>
12592  */
12593 Roo.CompositeElement = function(els){
12594     this.elements = [];
12595     this.addElements(els);
12596 };
12597 Roo.CompositeElement.prototype = {
12598     isComposite: true,
12599     addElements : function(els){
12600         if(!els) {
12601             return this;
12602         }
12603         if(typeof els == "string"){
12604             els = Roo.Element.selectorFunction(els);
12605         }
12606         var yels = this.elements;
12607         var index = yels.length-1;
12608         for(var i = 0, len = els.length; i < len; i++) {
12609                 yels[++index] = Roo.get(els[i]);
12610         }
12611         return this;
12612     },
12613
12614     /**
12615     * Clears this composite and adds the elements returned by the passed selector.
12616     * @param {String/Array} els A string CSS selector, an array of elements or an element
12617     * @return {CompositeElement} this
12618     */
12619     fill : function(els){
12620         this.elements = [];
12621         this.add(els);
12622         return this;
12623     },
12624
12625     /**
12626     * Filters this composite to only elements that match the passed selector.
12627     * @param {String} selector A string CSS selector
12628     * @param {Boolean} inverse return inverse filter (not matches)
12629     * @return {CompositeElement} this
12630     */
12631     filter : function(selector, inverse){
12632         var els = [];
12633         inverse = inverse || false;
12634         this.each(function(el){
12635             var match = inverse ? !el.is(selector) : el.is(selector);
12636             if(match){
12637                 els[els.length] = el.dom;
12638             }
12639         });
12640         this.fill(els);
12641         return this;
12642     },
12643
12644     invoke : function(fn, args){
12645         var els = this.elements;
12646         for(var i = 0, len = els.length; i < len; i++) {
12647                 Roo.Element.prototype[fn].apply(els[i], args);
12648         }
12649         return this;
12650     },
12651     /**
12652     * Adds elements to this composite.
12653     * @param {String/Array} els A string CSS selector, an array of elements or an element
12654     * @return {CompositeElement} this
12655     */
12656     add : function(els){
12657         if(typeof els == "string"){
12658             this.addElements(Roo.Element.selectorFunction(els));
12659         }else if(els.length !== undefined){
12660             this.addElements(els);
12661         }else{
12662             this.addElements([els]);
12663         }
12664         return this;
12665     },
12666     /**
12667     * Calls the passed function passing (el, this, index) for each element in this composite.
12668     * @param {Function} fn The function to call
12669     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12670     * @return {CompositeElement} this
12671     */
12672     each : function(fn, scope){
12673         var els = this.elements;
12674         for(var i = 0, len = els.length; i < len; i++){
12675             if(fn.call(scope || els[i], els[i], this, i) === false) {
12676                 break;
12677             }
12678         }
12679         return this;
12680     },
12681
12682     /**
12683      * Returns the Element object at the specified index
12684      * @param {Number} index
12685      * @return {Roo.Element}
12686      */
12687     item : function(index){
12688         return this.elements[index] || null;
12689     },
12690
12691     /**
12692      * Returns the first Element
12693      * @return {Roo.Element}
12694      */
12695     first : function(){
12696         return this.item(0);
12697     },
12698
12699     /**
12700      * Returns the last Element
12701      * @return {Roo.Element}
12702      */
12703     last : function(){
12704         return this.item(this.elements.length-1);
12705     },
12706
12707     /**
12708      * Returns the number of elements in this composite
12709      * @return Number
12710      */
12711     getCount : function(){
12712         return this.elements.length;
12713     },
12714
12715     /**
12716      * Returns true if this composite contains the passed element
12717      * @return Boolean
12718      */
12719     contains : function(el){
12720         return this.indexOf(el) !== -1;
12721     },
12722
12723     /**
12724      * Returns true if this composite contains the passed element
12725      * @return Boolean
12726      */
12727     indexOf : function(el){
12728         return this.elements.indexOf(Roo.get(el));
12729     },
12730
12731
12732     /**
12733     * Removes the specified element(s).
12734     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12735     * or an array of any of those.
12736     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12737     * @return {CompositeElement} this
12738     */
12739     removeElement : function(el, removeDom){
12740         if(el instanceof Array){
12741             for(var i = 0, len = el.length; i < len; i++){
12742                 this.removeElement(el[i]);
12743             }
12744             return this;
12745         }
12746         var index = typeof el == 'number' ? el : this.indexOf(el);
12747         if(index !== -1){
12748             if(removeDom){
12749                 var d = this.elements[index];
12750                 if(d.dom){
12751                     d.remove();
12752                 }else{
12753                     d.parentNode.removeChild(d);
12754                 }
12755             }
12756             this.elements.splice(index, 1);
12757         }
12758         return this;
12759     },
12760
12761     /**
12762     * Replaces the specified element with the passed element.
12763     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12764     * to replace.
12765     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12766     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12767     * @return {CompositeElement} this
12768     */
12769     replaceElement : function(el, replacement, domReplace){
12770         var index = typeof el == 'number' ? el : this.indexOf(el);
12771         if(index !== -1){
12772             if(domReplace){
12773                 this.elements[index].replaceWith(replacement);
12774             }else{
12775                 this.elements.splice(index, 1, Roo.get(replacement))
12776             }
12777         }
12778         return this;
12779     },
12780
12781     /**
12782      * Removes all elements.
12783      */
12784     clear : function(){
12785         this.elements = [];
12786     }
12787 };
12788 (function(){
12789     Roo.CompositeElement.createCall = function(proto, fnName){
12790         if(!proto[fnName]){
12791             proto[fnName] = function(){
12792                 return this.invoke(fnName, arguments);
12793             };
12794         }
12795     };
12796     for(var fnName in Roo.Element.prototype){
12797         if(typeof Roo.Element.prototype[fnName] == "function"){
12798             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12799         }
12800     };
12801 })();
12802 /*
12803  * Based on:
12804  * Ext JS Library 1.1.1
12805  * Copyright(c) 2006-2007, Ext JS, LLC.
12806  *
12807  * Originally Released Under LGPL - original licence link has changed is not relivant.
12808  *
12809  * Fork - LGPL
12810  * <script type="text/javascript">
12811  */
12812
12813 /**
12814  * @class Roo.CompositeElementLite
12815  * @extends Roo.CompositeElement
12816  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12817  <pre><code>
12818  var els = Roo.select("#some-el div.some-class");
12819  // or select directly from an existing element
12820  var el = Roo.get('some-el');
12821  el.select('div.some-class');
12822
12823  els.setWidth(100); // all elements become 100 width
12824  els.hide(true); // all elements fade out and hide
12825  // or
12826  els.setWidth(100).hide(true);
12827  </code></pre><br><br>
12828  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12829  * actions will be performed on all the elements in this collection.</b>
12830  */
12831 Roo.CompositeElementLite = function(els){
12832     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12833     this.el = new Roo.Element.Flyweight();
12834 };
12835 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12836     addElements : function(els){
12837         if(els){
12838             if(els instanceof Array){
12839                 this.elements = this.elements.concat(els);
12840             }else{
12841                 var yels = this.elements;
12842                 var index = yels.length-1;
12843                 for(var i = 0, len = els.length; i < len; i++) {
12844                     yels[++index] = els[i];
12845                 }
12846             }
12847         }
12848         return this;
12849     },
12850     invoke : function(fn, args){
12851         var els = this.elements;
12852         var el = this.el;
12853         for(var i = 0, len = els.length; i < len; i++) {
12854             el.dom = els[i];
12855                 Roo.Element.prototype[fn].apply(el, args);
12856         }
12857         return this;
12858     },
12859     /**
12860      * Returns a flyweight Element of the dom element object at the specified index
12861      * @param {Number} index
12862      * @return {Roo.Element}
12863      */
12864     item : function(index){
12865         if(!this.elements[index]){
12866             return null;
12867         }
12868         this.el.dom = this.elements[index];
12869         return this.el;
12870     },
12871
12872     // fixes scope with flyweight
12873     addListener : function(eventName, handler, scope, opt){
12874         var els = this.elements;
12875         for(var i = 0, len = els.length; i < len; i++) {
12876             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12877         }
12878         return this;
12879     },
12880
12881     /**
12882     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12883     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12884     * a reference to the dom node, use el.dom.</b>
12885     * @param {Function} fn The function to call
12886     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12887     * @return {CompositeElement} this
12888     */
12889     each : function(fn, scope){
12890         var els = this.elements;
12891         var el = this.el;
12892         for(var i = 0, len = els.length; i < len; i++){
12893             el.dom = els[i];
12894                 if(fn.call(scope || el, el, this, i) === false){
12895                 break;
12896             }
12897         }
12898         return this;
12899     },
12900
12901     indexOf : function(el){
12902         return this.elements.indexOf(Roo.getDom(el));
12903     },
12904
12905     replaceElement : function(el, replacement, domReplace){
12906         var index = typeof el == 'number' ? el : this.indexOf(el);
12907         if(index !== -1){
12908             replacement = Roo.getDom(replacement);
12909             if(domReplace){
12910                 var d = this.elements[index];
12911                 d.parentNode.insertBefore(replacement, d);
12912                 d.parentNode.removeChild(d);
12913             }
12914             this.elements.splice(index, 1, replacement);
12915         }
12916         return this;
12917     }
12918 });
12919 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12920
12921 /*
12922  * Based on:
12923  * Ext JS Library 1.1.1
12924  * Copyright(c) 2006-2007, Ext JS, LLC.
12925  *
12926  * Originally Released Under LGPL - original licence link has changed is not relivant.
12927  *
12928  * Fork - LGPL
12929  * <script type="text/javascript">
12930  */
12931
12932  
12933
12934 /**
12935  * @class Roo.data.Connection
12936  * @extends Roo.util.Observable
12937  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12938  * either to a configured URL, or to a URL specified at request time. 
12939  * 
12940  * Requests made by this class are asynchronous, and will return immediately. No data from
12941  * the server will be available to the statement immediately following the {@link #request} call.
12942  * To process returned data, use a callback in the request options object, or an event listener.
12943  * 
12944  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12945  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12946  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12947  * property and, if present, the IFRAME's XML document as the responseXML property.
12948  * 
12949  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12950  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12951  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12952  * standard DOM methods.
12953  * @constructor
12954  * @param {Object} config a configuration object.
12955  */
12956 Roo.data.Connection = function(config){
12957     Roo.apply(this, config);
12958     this.addEvents({
12959         /**
12960          * @event beforerequest
12961          * Fires before a network request is made to retrieve a data object.
12962          * @param {Connection} conn This Connection object.
12963          * @param {Object} options The options config object passed to the {@link #request} method.
12964          */
12965         "beforerequest" : true,
12966         /**
12967          * @event requestcomplete
12968          * Fires if the request was successfully completed.
12969          * @param {Connection} conn This Connection object.
12970          * @param {Object} response The XHR object containing the response data.
12971          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12972          * @param {Object} options The options config object passed to the {@link #request} method.
12973          */
12974         "requestcomplete" : true,
12975         /**
12976          * @event requestexception
12977          * Fires if an error HTTP status was returned from the server.
12978          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12979          * @param {Connection} conn This Connection object.
12980          * @param {Object} response The XHR object containing the response data.
12981          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12982          * @param {Object} options The options config object passed to the {@link #request} method.
12983          */
12984         "requestexception" : true
12985     });
12986     Roo.data.Connection.superclass.constructor.call(this);
12987 };
12988
12989 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12990     /**
12991      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12992      */
12993     /**
12994      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12995      * extra parameters to each request made by this object. (defaults to undefined)
12996      */
12997     /**
12998      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12999      *  to each request made by this object. (defaults to undefined)
13000      */
13001     /**
13002      * @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)
13003      */
13004     /**
13005      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13006      */
13007     timeout : 30000,
13008     /**
13009      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13010      * @type Boolean
13011      */
13012     autoAbort:false,
13013
13014     /**
13015      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13016      * @type Boolean
13017      */
13018     disableCaching: true,
13019
13020     /**
13021      * Sends an HTTP request to a remote server.
13022      * @param {Object} options An object which may contain the following properties:<ul>
13023      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
13024      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
13025      * request, a url encoded string or a function to call to get either.</li>
13026      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
13027      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
13028      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13029      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13030      * <li>options {Object} The parameter to the request call.</li>
13031      * <li>success {Boolean} True if the request succeeded.</li>
13032      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13033      * </ul></li>
13034      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13035      * The callback is passed the following parameters:<ul>
13036      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13037      * <li>options {Object} The parameter to the request call.</li>
13038      * </ul></li>
13039      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13040      * The callback is passed the following parameters:<ul>
13041      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13042      * <li>options {Object} The parameter to the request call.</li>
13043      * </ul></li>
13044      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13045      * for the callback function. Defaults to the browser window.</li>
13046      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13047      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13048      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13049      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13050      * params for the post data. Any params will be appended to the URL.</li>
13051      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13052      * </ul>
13053      * @return {Number} transactionId
13054      */
13055     request : function(o){
13056         if(this.fireEvent("beforerequest", this, o) !== false){
13057             var p = o.params;
13058
13059             if(typeof p == "function"){
13060                 p = p.call(o.scope||window, o);
13061             }
13062             if(typeof p == "object"){
13063                 p = Roo.urlEncode(o.params);
13064             }
13065             if(this.extraParams){
13066                 var extras = Roo.urlEncode(this.extraParams);
13067                 p = p ? (p + '&' + extras) : extras;
13068             }
13069
13070             var url = o.url || this.url;
13071             if(typeof url == 'function'){
13072                 url = url.call(o.scope||window, o);
13073             }
13074
13075             if(o.form){
13076                 var form = Roo.getDom(o.form);
13077                 url = url || form.action;
13078
13079                 var enctype = form.getAttribute("enctype");
13080                 
13081                 if (o.formData) {
13082                     return this.doFormDataUpload(o, url);
13083                 }
13084                 
13085                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13086                     return this.doFormUpload(o, p, url);
13087                 }
13088                 var f = Roo.lib.Ajax.serializeForm(form);
13089                 p = p ? (p + '&' + f) : f;
13090             }
13091             
13092             if (!o.form && o.formData) {
13093                 o.formData = o.formData === true ? new FormData() : o.formData;
13094                 for (var k in o.params) {
13095                     o.formData.append(k,o.params[k]);
13096                 }
13097                     
13098                 return this.doFormDataUpload(o, url);
13099             }
13100             
13101
13102             var hs = o.headers;
13103             if(this.defaultHeaders){
13104                 hs = Roo.apply(hs || {}, this.defaultHeaders);
13105                 if(!o.headers){
13106                     o.headers = hs;
13107                 }
13108             }
13109
13110             var cb = {
13111                 success: this.handleResponse,
13112                 failure: this.handleFailure,
13113                 scope: this,
13114                 argument: {options: o},
13115                 timeout : o.timeout || this.timeout
13116             };
13117
13118             var method = o.method||this.method||(p ? "POST" : "GET");
13119
13120             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13121                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13122             }
13123
13124             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13125                 if(o.autoAbort){
13126                     this.abort();
13127                 }
13128             }else if(this.autoAbort !== false){
13129                 this.abort();
13130             }
13131
13132             if((method == 'GET' && p) || o.xmlData){
13133                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13134                 p = '';
13135             }
13136             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13137             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13138             Roo.lib.Ajax.useDefaultHeader == true;
13139             return this.transId;
13140         }else{
13141             Roo.callback(o.callback, o.scope, [o, null, null]);
13142             return null;
13143         }
13144     },
13145
13146     /**
13147      * Determine whether this object has a request outstanding.
13148      * @param {Number} transactionId (Optional) defaults to the last transaction
13149      * @return {Boolean} True if there is an outstanding request.
13150      */
13151     isLoading : function(transId){
13152         if(transId){
13153             return Roo.lib.Ajax.isCallInProgress(transId);
13154         }else{
13155             return this.transId ? true : false;
13156         }
13157     },
13158
13159     /**
13160      * Aborts any outstanding request.
13161      * @param {Number} transactionId (Optional) defaults to the last transaction
13162      */
13163     abort : function(transId){
13164         if(transId || this.isLoading()){
13165             Roo.lib.Ajax.abort(transId || this.transId);
13166         }
13167     },
13168
13169     // private
13170     handleResponse : function(response){
13171         this.transId = false;
13172         var options = response.argument.options;
13173         response.argument = options ? options.argument : null;
13174         this.fireEvent("requestcomplete", this, response, options);
13175         Roo.callback(options.success, options.scope, [response, options]);
13176         Roo.callback(options.callback, options.scope, [options, true, response]);
13177     },
13178
13179     // private
13180     handleFailure : function(response, e){
13181         this.transId = false;
13182         var options = response.argument.options;
13183         response.argument = options ? options.argument : null;
13184         this.fireEvent("requestexception", this, response, options, e);
13185         Roo.callback(options.failure, options.scope, [response, options]);
13186         Roo.callback(options.callback, options.scope, [options, false, response]);
13187     },
13188
13189     // private
13190     doFormUpload : function(o, ps, url){
13191         var id = Roo.id();
13192         var frame = document.createElement('iframe');
13193         frame.id = id;
13194         frame.name = id;
13195         frame.className = 'x-hidden';
13196         if(Roo.isIE){
13197             frame.src = Roo.SSL_SECURE_URL;
13198         }
13199         document.body.appendChild(frame);
13200
13201         if(Roo.isIE){
13202            document.frames[id].name = id;
13203         }
13204
13205         var form = Roo.getDom(o.form);
13206         form.target = id;
13207         form.method = 'POST';
13208         form.enctype = form.encoding = 'multipart/form-data';
13209         if(url){
13210             form.action = url;
13211         }
13212
13213         var hiddens, hd;
13214         if(ps){ // add dynamic params
13215             hiddens = [];
13216             ps = Roo.urlDecode(ps, false);
13217             for(var k in ps){
13218                 if(ps.hasOwnProperty(k)){
13219                     hd = document.createElement('input');
13220                     hd.type = 'hidden';
13221                     hd.name = k;
13222                     hd.value = ps[k];
13223                     form.appendChild(hd);
13224                     hiddens.push(hd);
13225                 }
13226             }
13227         }
13228
13229         function cb(){
13230             var r = {  // bogus response object
13231                 responseText : '',
13232                 responseXML : null
13233             };
13234
13235             r.argument = o ? o.argument : null;
13236
13237             try { //
13238                 var doc;
13239                 if(Roo.isIE){
13240                     doc = frame.contentWindow.document;
13241                 }else {
13242                     doc = (frame.contentDocument || window.frames[id].document);
13243                 }
13244                 if(doc && doc.body){
13245                     r.responseText = doc.body.innerHTML;
13246                 }
13247                 if(doc && doc.XMLDocument){
13248                     r.responseXML = doc.XMLDocument;
13249                 }else {
13250                     r.responseXML = doc;
13251                 }
13252             }
13253             catch(e) {
13254                 // ignore
13255             }
13256
13257             Roo.EventManager.removeListener(frame, 'load', cb, this);
13258
13259             this.fireEvent("requestcomplete", this, r, o);
13260             Roo.callback(o.success, o.scope, [r, o]);
13261             Roo.callback(o.callback, o.scope, [o, true, r]);
13262
13263             setTimeout(function(){document.body.removeChild(frame);}, 100);
13264         }
13265
13266         Roo.EventManager.on(frame, 'load', cb, this);
13267         form.submit();
13268
13269         if(hiddens){ // remove dynamic params
13270             for(var i = 0, len = hiddens.length; i < len; i++){
13271                 form.removeChild(hiddens[i]);
13272             }
13273         }
13274     },
13275     // this is a 'formdata version???'
13276     
13277     
13278     doFormDataUpload : function(o,  url)
13279     {
13280         var formData;
13281         if (o.form) {
13282             var form =  Roo.getDom(o.form);
13283             form.enctype = form.encoding = 'multipart/form-data';
13284             formData = o.formData === true ? new FormData(form) : o.formData;
13285         } else {
13286             formData = o.formData === true ? new FormData() : o.formData;
13287         }
13288         
13289       
13290         var cb = {
13291             success: this.handleResponse,
13292             failure: this.handleFailure,
13293             scope: this,
13294             argument: {options: o},
13295             timeout : o.timeout || this.timeout
13296         };
13297  
13298         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13299             if(o.autoAbort){
13300                 this.abort();
13301             }
13302         }else if(this.autoAbort !== false){
13303             this.abort();
13304         }
13305
13306         //Roo.lib.Ajax.defaultPostHeader = null;
13307         Roo.lib.Ajax.useDefaultHeader = false;
13308         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13309         Roo.lib.Ajax.useDefaultHeader = true;
13310  
13311          
13312     }
13313     
13314 });
13315 /*
13316  * Based on:
13317  * Ext JS Library 1.1.1
13318  * Copyright(c) 2006-2007, Ext JS, LLC.
13319  *
13320  * Originally Released Under LGPL - original licence link has changed is not relivant.
13321  *
13322  * Fork - LGPL
13323  * <script type="text/javascript">
13324  */
13325  
13326 /**
13327  * Global Ajax request class.
13328  * 
13329  * @class Roo.Ajax
13330  * @extends Roo.data.Connection
13331  * @static
13332  * 
13333  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13334  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13335  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13336  * @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)
13337  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13338  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13339  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13340  */
13341 Roo.Ajax = new Roo.data.Connection({
13342     // fix up the docs
13343     /**
13344      * @scope Roo.Ajax
13345      * @type {Boolear} 
13346      */
13347     autoAbort : false,
13348
13349     /**
13350      * Serialize the passed form into a url encoded string
13351      * @scope Roo.Ajax
13352      * @param {String/HTMLElement} form
13353      * @return {String}
13354      */
13355     serializeForm : function(form){
13356         return Roo.lib.Ajax.serializeForm(form);
13357     }
13358 });/*
13359  * Based on:
13360  * Ext JS Library 1.1.1
13361  * Copyright(c) 2006-2007, Ext JS, LLC.
13362  *
13363  * Originally Released Under LGPL - original licence link has changed is not relivant.
13364  *
13365  * Fork - LGPL
13366  * <script type="text/javascript">
13367  */
13368
13369  
13370 /**
13371  * @class Roo.UpdateManager
13372  * @extends Roo.util.Observable
13373  * Provides AJAX-style update for Element object.<br><br>
13374  * Usage:<br>
13375  * <pre><code>
13376  * // Get it from a Roo.Element object
13377  * var el = Roo.get("foo");
13378  * var mgr = el.getUpdateManager();
13379  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13380  * ...
13381  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13382  * <br>
13383  * // or directly (returns the same UpdateManager instance)
13384  * var mgr = new Roo.UpdateManager("myElementId");
13385  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13386  * mgr.on("update", myFcnNeedsToKnow);
13387  * <br>
13388    // short handed call directly from the element object
13389    Roo.get("foo").load({
13390         url: "bar.php",
13391         scripts:true,
13392         params: "for=bar",
13393         text: "Loading Foo..."
13394    });
13395  * </code></pre>
13396  * @constructor
13397  * Create new UpdateManager directly.
13398  * @param {String/HTMLElement/Roo.Element} el The element to update
13399  * @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).
13400  */
13401 Roo.UpdateManager = function(el, forceNew){
13402     el = Roo.get(el);
13403     if(!forceNew && el.updateManager){
13404         return el.updateManager;
13405     }
13406     /**
13407      * The Element object
13408      * @type Roo.Element
13409      */
13410     this.el = el;
13411     /**
13412      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13413      * @type String
13414      */
13415     this.defaultUrl = null;
13416
13417     this.addEvents({
13418         /**
13419          * @event beforeupdate
13420          * Fired before an update is made, return false from your handler and the update is cancelled.
13421          * @param {Roo.Element} el
13422          * @param {String/Object/Function} url
13423          * @param {String/Object} params
13424          */
13425         "beforeupdate": true,
13426         /**
13427          * @event update
13428          * Fired after successful update is made.
13429          * @param {Roo.Element} el
13430          * @param {Object} oResponseObject The response Object
13431          */
13432         "update": true,
13433         /**
13434          * @event failure
13435          * Fired on update failure.
13436          * @param {Roo.Element} el
13437          * @param {Object} oResponseObject The response Object
13438          */
13439         "failure": true
13440     });
13441     var d = Roo.UpdateManager.defaults;
13442     /**
13443      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13444      * @type String
13445      */
13446     this.sslBlankUrl = d.sslBlankUrl;
13447     /**
13448      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13449      * @type Boolean
13450      */
13451     this.disableCaching = d.disableCaching;
13452     /**
13453      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13454      * @type String
13455      */
13456     this.indicatorText = d.indicatorText;
13457     /**
13458      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13459      * @type String
13460      */
13461     this.showLoadIndicator = d.showLoadIndicator;
13462     /**
13463      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13464      * @type Number
13465      */
13466     this.timeout = d.timeout;
13467
13468     /**
13469      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13470      * @type Boolean
13471      */
13472     this.loadScripts = d.loadScripts;
13473
13474     /**
13475      * Transaction object of current executing transaction
13476      */
13477     this.transaction = null;
13478
13479     /**
13480      * @private
13481      */
13482     this.autoRefreshProcId = null;
13483     /**
13484      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13485      * @type Function
13486      */
13487     this.refreshDelegate = this.refresh.createDelegate(this);
13488     /**
13489      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13490      * @type Function
13491      */
13492     this.updateDelegate = this.update.createDelegate(this);
13493     /**
13494      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13495      * @type Function
13496      */
13497     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13498     /**
13499      * @private
13500      */
13501     this.successDelegate = this.processSuccess.createDelegate(this);
13502     /**
13503      * @private
13504      */
13505     this.failureDelegate = this.processFailure.createDelegate(this);
13506
13507     if(!this.renderer){
13508      /**
13509       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13510       */
13511     this.renderer = new Roo.UpdateManager.BasicRenderer();
13512     }
13513     
13514     Roo.UpdateManager.superclass.constructor.call(this);
13515 };
13516
13517 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13518     /**
13519      * Get the Element this UpdateManager is bound to
13520      * @return {Roo.Element} The element
13521      */
13522     getEl : function(){
13523         return this.el;
13524     },
13525     /**
13526      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13527      * @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:
13528 <pre><code>
13529 um.update({<br/>
13530     url: "your-url.php",<br/>
13531     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13532     callback: yourFunction,<br/>
13533     scope: yourObject, //(optional scope)  <br/>
13534     discardUrl: false, <br/>
13535     nocache: false,<br/>
13536     text: "Loading...",<br/>
13537     timeout: 30,<br/>
13538     scripts: false<br/>
13539 });
13540 </code></pre>
13541      * The only required property is url. The optional properties nocache, text and scripts
13542      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13543      * @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}
13544      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13545      * @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.
13546      */
13547     update : function(url, params, callback, discardUrl){
13548         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13549             var method = this.method,
13550                 cfg;
13551             if(typeof url == "object"){ // must be config object
13552                 cfg = url;
13553                 url = cfg.url;
13554                 params = params || cfg.params;
13555                 callback = callback || cfg.callback;
13556                 discardUrl = discardUrl || cfg.discardUrl;
13557                 if(callback && cfg.scope){
13558                     callback = callback.createDelegate(cfg.scope);
13559                 }
13560                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13561                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13562                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13563                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13564                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13565             }
13566             this.showLoading();
13567             if(!discardUrl){
13568                 this.defaultUrl = url;
13569             }
13570             if(typeof url == "function"){
13571                 url = url.call(this);
13572             }
13573
13574             method = method || (params ? "POST" : "GET");
13575             if(method == "GET"){
13576                 url = this.prepareUrl(url);
13577             }
13578
13579             var o = Roo.apply(cfg ||{}, {
13580                 url : url,
13581                 params: params,
13582                 success: this.successDelegate,
13583                 failure: this.failureDelegate,
13584                 callback: undefined,
13585                 timeout: (this.timeout*1000),
13586                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13587             });
13588             Roo.log("updated manager called with timeout of " + o.timeout);
13589             this.transaction = Roo.Ajax.request(o);
13590         }
13591     },
13592
13593     /**
13594      * 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.
13595      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13596      * @param {String/HTMLElement} form The form Id or form element
13597      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13598      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13599      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13600      */
13601     formUpdate : function(form, url, reset, callback){
13602         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13603             if(typeof url == "function"){
13604                 url = url.call(this);
13605             }
13606             form = Roo.getDom(form);
13607             this.transaction = Roo.Ajax.request({
13608                 form: form,
13609                 url:url,
13610                 success: this.successDelegate,
13611                 failure: this.failureDelegate,
13612                 timeout: (this.timeout*1000),
13613                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13614             });
13615             this.showLoading.defer(1, this);
13616         }
13617     },
13618
13619     /**
13620      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13621      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13622      */
13623     refresh : function(callback){
13624         if(this.defaultUrl == null){
13625             return;
13626         }
13627         this.update(this.defaultUrl, null, callback, true);
13628     },
13629
13630     /**
13631      * Set this element to auto refresh.
13632      * @param {Number} interval How often to update (in seconds).
13633      * @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)
13634      * @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}
13635      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13636      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13637      */
13638     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13639         if(refreshNow){
13640             this.update(url || this.defaultUrl, params, callback, true);
13641         }
13642         if(this.autoRefreshProcId){
13643             clearInterval(this.autoRefreshProcId);
13644         }
13645         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13646     },
13647
13648     /**
13649      * Stop auto refresh on this element.
13650      */
13651      stopAutoRefresh : function(){
13652         if(this.autoRefreshProcId){
13653             clearInterval(this.autoRefreshProcId);
13654             delete this.autoRefreshProcId;
13655         }
13656     },
13657
13658     isAutoRefreshing : function(){
13659        return this.autoRefreshProcId ? true : false;
13660     },
13661     /**
13662      * Called to update the element to "Loading" state. Override to perform custom action.
13663      */
13664     showLoading : function(){
13665         if(this.showLoadIndicator){
13666             this.el.update(this.indicatorText);
13667         }
13668     },
13669
13670     /**
13671      * Adds unique parameter to query string if disableCaching = true
13672      * @private
13673      */
13674     prepareUrl : function(url){
13675         if(this.disableCaching){
13676             var append = "_dc=" + (new Date().getTime());
13677             if(url.indexOf("?") !== -1){
13678                 url += "&" + append;
13679             }else{
13680                 url += "?" + append;
13681             }
13682         }
13683         return url;
13684     },
13685
13686     /**
13687      * @private
13688      */
13689     processSuccess : function(response){
13690         this.transaction = null;
13691         if(response.argument.form && response.argument.reset){
13692             try{ // put in try/catch since some older FF releases had problems with this
13693                 response.argument.form.reset();
13694             }catch(e){}
13695         }
13696         if(this.loadScripts){
13697             this.renderer.render(this.el, response, this,
13698                 this.updateComplete.createDelegate(this, [response]));
13699         }else{
13700             this.renderer.render(this.el, response, this);
13701             this.updateComplete(response);
13702         }
13703     },
13704
13705     updateComplete : function(response){
13706         this.fireEvent("update", this.el, response);
13707         if(typeof response.argument.callback == "function"){
13708             response.argument.callback(this.el, true, response);
13709         }
13710     },
13711
13712     /**
13713      * @private
13714      */
13715     processFailure : function(response){
13716         this.transaction = null;
13717         this.fireEvent("failure", this.el, response);
13718         if(typeof response.argument.callback == "function"){
13719             response.argument.callback(this.el, false, response);
13720         }
13721     },
13722
13723     /**
13724      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13725      * @param {Object} renderer The object implementing the render() method
13726      */
13727     setRenderer : function(renderer){
13728         this.renderer = renderer;
13729     },
13730
13731     getRenderer : function(){
13732        return this.renderer;
13733     },
13734
13735     /**
13736      * Set the defaultUrl used for updates
13737      * @param {String/Function} defaultUrl The url or a function to call to get the url
13738      */
13739     setDefaultUrl : function(defaultUrl){
13740         this.defaultUrl = defaultUrl;
13741     },
13742
13743     /**
13744      * Aborts the executing transaction
13745      */
13746     abort : function(){
13747         if(this.transaction){
13748             Roo.Ajax.abort(this.transaction);
13749         }
13750     },
13751
13752     /**
13753      * Returns true if an update is in progress
13754      * @return {Boolean}
13755      */
13756     isUpdating : function(){
13757         if(this.transaction){
13758             return Roo.Ajax.isLoading(this.transaction);
13759         }
13760         return false;
13761     }
13762 });
13763
13764 /**
13765  * @class Roo.UpdateManager.defaults
13766  * @static (not really - but it helps the doc tool)
13767  * The defaults collection enables customizing the default properties of UpdateManager
13768  */
13769    Roo.UpdateManager.defaults = {
13770        /**
13771          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13772          * @type Number
13773          */
13774          timeout : 30,
13775
13776          /**
13777          * True to process scripts by default (Defaults to false).
13778          * @type Boolean
13779          */
13780         loadScripts : false,
13781
13782         /**
13783         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13784         * @type String
13785         */
13786         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13787         /**
13788          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13789          * @type Boolean
13790          */
13791         disableCaching : false,
13792         /**
13793          * Whether to show indicatorText when loading (Defaults to true).
13794          * @type Boolean
13795          */
13796         showLoadIndicator : true,
13797         /**
13798          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13799          * @type String
13800          */
13801         indicatorText : '<div class="loading-indicator">Loading...</div>'
13802    };
13803
13804 /**
13805  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13806  *Usage:
13807  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13808  * @param {String/HTMLElement/Roo.Element} el The element to update
13809  * @param {String} url The url
13810  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13811  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13812  * @static
13813  * @deprecated
13814  * @member Roo.UpdateManager
13815  */
13816 Roo.UpdateManager.updateElement = function(el, url, params, options){
13817     var um = Roo.get(el, true).getUpdateManager();
13818     Roo.apply(um, options);
13819     um.update(url, params, options ? options.callback : null);
13820 };
13821 // alias for backwards compat
13822 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13823 /**
13824  * @class Roo.UpdateManager.BasicRenderer
13825  * Default Content renderer. Updates the elements innerHTML with the responseText.
13826  */
13827 Roo.UpdateManager.BasicRenderer = function(){};
13828
13829 Roo.UpdateManager.BasicRenderer.prototype = {
13830     /**
13831      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13832      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13833      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13834      * @param {Roo.Element} el The element being rendered
13835      * @param {Object} response The YUI Connect response object
13836      * @param {UpdateManager} updateManager The calling update manager
13837      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13838      */
13839      render : function(el, response, updateManager, callback){
13840         el.update(response.responseText, updateManager.loadScripts, callback);
13841     }
13842 };
13843 /*
13844  * Based on:
13845  * Roo JS
13846  * (c)) Alan Knowles
13847  * Licence : LGPL
13848  */
13849
13850
13851 /**
13852  * @class Roo.DomTemplate
13853  * @extends Roo.Template
13854  * An effort at a dom based template engine..
13855  *
13856  * Similar to XTemplate, except it uses dom parsing to create the template..
13857  *
13858  * Supported features:
13859  *
13860  *  Tags:
13861
13862 <pre><code>
13863       {a_variable} - output encoded.
13864       {a_variable.format:("Y-m-d")} - call a method on the variable
13865       {a_variable:raw} - unencoded output
13866       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13867       {a_variable:this.method_on_template(...)} - call a method on the template object.
13868  
13869 </code></pre>
13870  *  The tpl tag:
13871 <pre><code>
13872         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13873         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13874         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13875         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13876   
13877 </code></pre>
13878  *      
13879  */
13880 Roo.DomTemplate = function()
13881 {
13882      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13883      if (this.html) {
13884         this.compile();
13885      }
13886 };
13887
13888
13889 Roo.extend(Roo.DomTemplate, Roo.Template, {
13890     /**
13891      * id counter for sub templates.
13892      */
13893     id : 0,
13894     /**
13895      * flag to indicate if dom parser is inside a pre,
13896      * it will strip whitespace if not.
13897      */
13898     inPre : false,
13899     
13900     /**
13901      * The various sub templates
13902      */
13903     tpls : false,
13904     
13905     
13906     
13907     /**
13908      *
13909      * basic tag replacing syntax
13910      * WORD:WORD()
13911      *
13912      * // you can fake an object call by doing this
13913      *  x.t:(test,tesT) 
13914      * 
13915      */
13916     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13917     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13918     
13919     iterChild : function (node, method) {
13920         
13921         var oldPre = this.inPre;
13922         if (node.tagName == 'PRE') {
13923             this.inPre = true;
13924         }
13925         for( var i = 0; i < node.childNodes.length; i++) {
13926             method.call(this, node.childNodes[i]);
13927         }
13928         this.inPre = oldPre;
13929     },
13930     
13931     
13932     
13933     /**
13934      * compile the template
13935      *
13936      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13937      *
13938      */
13939     compile: function()
13940     {
13941         var s = this.html;
13942         
13943         // covert the html into DOM...
13944         var doc = false;
13945         var div =false;
13946         try {
13947             doc = document.implementation.createHTMLDocument("");
13948             doc.documentElement.innerHTML =   this.html  ;
13949             div = doc.documentElement;
13950         } catch (e) {
13951             // old IE... - nasty -- it causes all sorts of issues.. with
13952             // images getting pulled from server..
13953             div = document.createElement('div');
13954             div.innerHTML = this.html;
13955         }
13956         //doc.documentElement.innerHTML = htmlBody
13957          
13958         
13959         
13960         this.tpls = [];
13961         var _t = this;
13962         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13963         
13964         var tpls = this.tpls;
13965         
13966         // create a top level template from the snippet..
13967         
13968         //Roo.log(div.innerHTML);
13969         
13970         var tpl = {
13971             uid : 'master',
13972             id : this.id++,
13973             attr : false,
13974             value : false,
13975             body : div.innerHTML,
13976             
13977             forCall : false,
13978             execCall : false,
13979             dom : div,
13980             isTop : true
13981             
13982         };
13983         tpls.unshift(tpl);
13984         
13985         
13986         // compile them...
13987         this.tpls = [];
13988         Roo.each(tpls, function(tp){
13989             this.compileTpl(tp);
13990             this.tpls[tp.id] = tp;
13991         }, this);
13992         
13993         this.master = tpls[0];
13994         return this;
13995         
13996         
13997     },
13998     
13999     compileNode : function(node, istop) {
14000         // test for
14001         //Roo.log(node);
14002         
14003         
14004         // skip anything not a tag..
14005         if (node.nodeType != 1) {
14006             if (node.nodeType == 3 && !this.inPre) {
14007                 // reduce white space..
14008                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
14009                 
14010             }
14011             return;
14012         }
14013         
14014         var tpl = {
14015             uid : false,
14016             id : false,
14017             attr : false,
14018             value : false,
14019             body : '',
14020             
14021             forCall : false,
14022             execCall : false,
14023             dom : false,
14024             isTop : istop
14025             
14026             
14027         };
14028         
14029         
14030         switch(true) {
14031             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14032             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14033             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14034             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14035             // no default..
14036         }
14037         
14038         
14039         if (!tpl.attr) {
14040             // just itterate children..
14041             this.iterChild(node,this.compileNode);
14042             return;
14043         }
14044         tpl.uid = this.id++;
14045         tpl.value = node.getAttribute('roo-' +  tpl.attr);
14046         node.removeAttribute('roo-'+ tpl.attr);
14047         if (tpl.attr != 'name') {
14048             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14049             node.parentNode.replaceChild(placeholder,  node);
14050         } else {
14051             
14052             var placeholder =  document.createElement('span');
14053             placeholder.className = 'roo-tpl-' + tpl.value;
14054             node.parentNode.replaceChild(placeholder,  node);
14055         }
14056         
14057         // parent now sees '{domtplXXXX}
14058         this.iterChild(node,this.compileNode);
14059         
14060         // we should now have node body...
14061         var div = document.createElement('div');
14062         div.appendChild(node);
14063         tpl.dom = node;
14064         // this has the unfortunate side effect of converting tagged attributes
14065         // eg. href="{...}" into %7C...%7D
14066         // this has been fixed by searching for those combo's although it's a bit hacky..
14067         
14068         
14069         tpl.body = div.innerHTML;
14070         
14071         
14072          
14073         tpl.id = tpl.uid;
14074         switch(tpl.attr) {
14075             case 'for' :
14076                 switch (tpl.value) {
14077                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14078                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14079                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14080                 }
14081                 break;
14082             
14083             case 'exec':
14084                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14085                 break;
14086             
14087             case 'if':     
14088                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14089                 break;
14090             
14091             case 'name':
14092                 tpl.id  = tpl.value; // replace non characters???
14093                 break;
14094             
14095         }
14096         
14097         
14098         this.tpls.push(tpl);
14099         
14100         
14101         
14102     },
14103     
14104     
14105     
14106     
14107     /**
14108      * Compile a segment of the template into a 'sub-template'
14109      *
14110      * 
14111      * 
14112      *
14113      */
14114     compileTpl : function(tpl)
14115     {
14116         var fm = Roo.util.Format;
14117         var useF = this.disableFormats !== true;
14118         
14119         var sep = Roo.isGecko ? "+\n" : ",\n";
14120         
14121         var undef = function(str) {
14122             Roo.debug && Roo.log("Property not found :"  + str);
14123             return '';
14124         };
14125           
14126         //Roo.log(tpl.body);
14127         
14128         
14129         
14130         var fn = function(m, lbrace, name, format, args)
14131         {
14132             //Roo.log("ARGS");
14133             //Roo.log(arguments);
14134             args = args ? args.replace(/\\'/g,"'") : args;
14135             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14136             if (typeof(format) == 'undefined') {
14137                 format =  'htmlEncode'; 
14138             }
14139             if (format == 'raw' ) {
14140                 format = false;
14141             }
14142             
14143             if(name.substr(0, 6) == 'domtpl'){
14144                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14145             }
14146             
14147             // build an array of options to determine if value is undefined..
14148             
14149             // basically get 'xxxx.yyyy' then do
14150             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14151             //    (function () { Roo.log("Property not found"); return ''; })() :
14152             //    ......
14153             
14154             var udef_ar = [];
14155             var lookfor = '';
14156             Roo.each(name.split('.'), function(st) {
14157                 lookfor += (lookfor.length ? '.': '') + st;
14158                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
14159             });
14160             
14161             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14162             
14163             
14164             if(format && useF){
14165                 
14166                 args = args ? ',' + args : "";
14167                  
14168                 if(format.substr(0, 5) != "this."){
14169                     format = "fm." + format + '(';
14170                 }else{
14171                     format = 'this.call("'+ format.substr(5) + '", ';
14172                     args = ", values";
14173                 }
14174                 
14175                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
14176             }
14177              
14178             if (args && args.length) {
14179                 // called with xxyx.yuu:(test,test)
14180                 // change to ()
14181                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
14182             }
14183             // raw.. - :raw modifier..
14184             return "'"+ sep + udef_st  + name + ")"+sep+"'";
14185             
14186         };
14187         var body;
14188         // branched to use + in gecko and [].join() in others
14189         if(Roo.isGecko){
14190             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
14191                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14192                     "';};};";
14193         }else{
14194             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
14195             body.push(tpl.body.replace(/(\r\n|\n)/g,
14196                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14197             body.push("'].join('');};};");
14198             body = body.join('');
14199         }
14200         
14201         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14202        
14203         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
14204         eval(body);
14205         
14206         return this;
14207     },
14208      
14209     /**
14210      * same as applyTemplate, except it's done to one of the subTemplates
14211      * when using named templates, you can do:
14212      *
14213      * var str = pl.applySubTemplate('your-name', values);
14214      *
14215      * 
14216      * @param {Number} id of the template
14217      * @param {Object} values to apply to template
14218      * @param {Object} parent (normaly the instance of this object)
14219      */
14220     applySubTemplate : function(id, values, parent)
14221     {
14222         
14223         
14224         var t = this.tpls[id];
14225         
14226         
14227         try { 
14228             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14229                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14230                 return '';
14231             }
14232         } catch(e) {
14233             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14234             Roo.log(values);
14235           
14236             return '';
14237         }
14238         try { 
14239             
14240             if(t.execCall && t.execCall.call(this, values, parent)){
14241                 return '';
14242             }
14243         } catch(e) {
14244             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14245             Roo.log(values);
14246             return '';
14247         }
14248         
14249         try {
14250             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14251             parent = t.target ? values : parent;
14252             if(t.forCall && vs instanceof Array){
14253                 var buf = [];
14254                 for(var i = 0, len = vs.length; i < len; i++){
14255                     try {
14256                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14257                     } catch (e) {
14258                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14259                         Roo.log(e.body);
14260                         //Roo.log(t.compiled);
14261                         Roo.log(vs[i]);
14262                     }   
14263                 }
14264                 return buf.join('');
14265             }
14266         } catch (e) {
14267             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14268             Roo.log(values);
14269             return '';
14270         }
14271         try {
14272             return t.compiled.call(this, vs, parent);
14273         } catch (e) {
14274             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14275             Roo.log(e.body);
14276             //Roo.log(t.compiled);
14277             Roo.log(values);
14278             return '';
14279         }
14280     },
14281
14282    
14283
14284     applyTemplate : function(values){
14285         return this.master.compiled.call(this, values, {});
14286         //var s = this.subs;
14287     },
14288
14289     apply : function(){
14290         return this.applyTemplate.apply(this, arguments);
14291     }
14292
14293  });
14294
14295 Roo.DomTemplate.from = function(el){
14296     el = Roo.getDom(el);
14297     return new Roo.Domtemplate(el.value || el.innerHTML);
14298 };/*
14299  * Based on:
14300  * Ext JS Library 1.1.1
14301  * Copyright(c) 2006-2007, Ext JS, LLC.
14302  *
14303  * Originally Released Under LGPL - original licence link has changed is not relivant.
14304  *
14305  * Fork - LGPL
14306  * <script type="text/javascript">
14307  */
14308
14309 /**
14310  * @class Roo.util.DelayedTask
14311  * Provides a convenient method of performing setTimeout where a new
14312  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14313  * You can use this class to buffer
14314  * the keypress events for a certain number of milliseconds, and perform only if they stop
14315  * for that amount of time.
14316  * @constructor The parameters to this constructor serve as defaults and are not required.
14317  * @param {Function} fn (optional) The default function to timeout
14318  * @param {Object} scope (optional) The default scope of that timeout
14319  * @param {Array} args (optional) The default Array of arguments
14320  */
14321 Roo.util.DelayedTask = function(fn, scope, args){
14322     var id = null, d, t;
14323
14324     var call = function(){
14325         var now = new Date().getTime();
14326         if(now - t >= d){
14327             clearInterval(id);
14328             id = null;
14329             fn.apply(scope, args || []);
14330         }
14331     };
14332     /**
14333      * Cancels any pending timeout and queues a new one
14334      * @param {Number} delay The milliseconds to delay
14335      * @param {Function} newFn (optional) Overrides function passed to constructor
14336      * @param {Object} newScope (optional) Overrides scope passed to constructor
14337      * @param {Array} newArgs (optional) Overrides args passed to constructor
14338      */
14339     this.delay = function(delay, newFn, newScope, newArgs){
14340         if(id && delay != d){
14341             this.cancel();
14342         }
14343         d = delay;
14344         t = new Date().getTime();
14345         fn = newFn || fn;
14346         scope = newScope || scope;
14347         args = newArgs || args;
14348         if(!id){
14349             id = setInterval(call, d);
14350         }
14351     };
14352
14353     /**
14354      * Cancel the last queued timeout
14355      */
14356     this.cancel = function(){
14357         if(id){
14358             clearInterval(id);
14359             id = null;
14360         }
14361     };
14362 };/*
14363  * Based on:
14364  * Ext JS Library 1.1.1
14365  * Copyright(c) 2006-2007, Ext JS, LLC.
14366  *
14367  * Originally Released Under LGPL - original licence link has changed is not relivant.
14368  *
14369  * Fork - LGPL
14370  * <script type="text/javascript">
14371  */
14372 /**
14373  * @class Roo.util.TaskRunner
14374  * Manage background tasks - not sure why this is better that setInterval?
14375  * @static
14376  *
14377  */
14378  
14379 Roo.util.TaskRunner = function(interval){
14380     interval = interval || 10;
14381     var tasks = [], removeQueue = [];
14382     var id = 0;
14383     var running = false;
14384
14385     var stopThread = function(){
14386         running = false;
14387         clearInterval(id);
14388         id = 0;
14389     };
14390
14391     var startThread = function(){
14392         if(!running){
14393             running = true;
14394             id = setInterval(runTasks, interval);
14395         }
14396     };
14397
14398     var removeTask = function(task){
14399         removeQueue.push(task);
14400         if(task.onStop){
14401             task.onStop();
14402         }
14403     };
14404
14405     var runTasks = function(){
14406         if(removeQueue.length > 0){
14407             for(var i = 0, len = removeQueue.length; i < len; i++){
14408                 tasks.remove(removeQueue[i]);
14409             }
14410             removeQueue = [];
14411             if(tasks.length < 1){
14412                 stopThread();
14413                 return;
14414             }
14415         }
14416         var now = new Date().getTime();
14417         for(var i = 0, len = tasks.length; i < len; ++i){
14418             var t = tasks[i];
14419             var itime = now - t.taskRunTime;
14420             if(t.interval <= itime){
14421                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14422                 t.taskRunTime = now;
14423                 if(rt === false || t.taskRunCount === t.repeat){
14424                     removeTask(t);
14425                     return;
14426                 }
14427             }
14428             if(t.duration && t.duration <= (now - t.taskStartTime)){
14429                 removeTask(t);
14430             }
14431         }
14432     };
14433
14434     /**
14435      * Queues a new task.
14436      * @param {Object} task
14437      *
14438      * Task property : interval = how frequent to run.
14439      * Task object should implement
14440      * function run()
14441      * Task object may implement
14442      * function onStop()
14443      */
14444     this.start = function(task){
14445         tasks.push(task);
14446         task.taskStartTime = new Date().getTime();
14447         task.taskRunTime = 0;
14448         task.taskRunCount = 0;
14449         startThread();
14450         return task;
14451     };
14452     /**
14453      * Stop  new task.
14454      * @param {Object} task
14455      */
14456     this.stop = function(task){
14457         removeTask(task);
14458         return task;
14459     };
14460     /**
14461      * Stop all Tasks
14462      */
14463     this.stopAll = function(){
14464         stopThread();
14465         for(var i = 0, len = tasks.length; i < len; i++){
14466             if(tasks[i].onStop){
14467                 tasks[i].onStop();
14468             }
14469         }
14470         tasks = [];
14471         removeQueue = [];
14472     };
14473 };
14474
14475 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14476  * Based on:
14477  * Ext JS Library 1.1.1
14478  * Copyright(c) 2006-2007, Ext JS, LLC.
14479  *
14480  * Originally Released Under LGPL - original licence link has changed is not relivant.
14481  *
14482  * Fork - LGPL
14483  * <script type="text/javascript">
14484  */
14485
14486  
14487 /**
14488  * @class Roo.util.MixedCollection
14489  * @extends Roo.util.Observable
14490  * A Collection class that maintains both numeric indexes and keys and exposes events.
14491  * @constructor
14492  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14493  * collection (defaults to false)
14494  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14495  * and return the key value for that item.  This is used when available to look up the key on items that
14496  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14497  * equivalent to providing an implementation for the {@link #getKey} method.
14498  */
14499 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14500     this.items = [];
14501     this.map = {};
14502     this.keys = [];
14503     this.length = 0;
14504     this.addEvents({
14505         /**
14506          * @event clear
14507          * Fires when the collection is cleared.
14508          */
14509         "clear" : true,
14510         /**
14511          * @event add
14512          * Fires when an item is added to the collection.
14513          * @param {Number} index The index at which the item was added.
14514          * @param {Object} o The item added.
14515          * @param {String} key The key associated with the added item.
14516          */
14517         "add" : true,
14518         /**
14519          * @event replace
14520          * Fires when an item is replaced in the collection.
14521          * @param {String} key he key associated with the new added.
14522          * @param {Object} old The item being replaced.
14523          * @param {Object} new The new item.
14524          */
14525         "replace" : true,
14526         /**
14527          * @event remove
14528          * Fires when an item is removed from the collection.
14529          * @param {Object} o The item being removed.
14530          * @param {String} key (optional) The key associated with the removed item.
14531          */
14532         "remove" : true,
14533         "sort" : true
14534     });
14535     this.allowFunctions = allowFunctions === true;
14536     if(keyFn){
14537         this.getKey = keyFn;
14538     }
14539     Roo.util.MixedCollection.superclass.constructor.call(this);
14540 };
14541
14542 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14543     allowFunctions : false,
14544     
14545 /**
14546  * Adds an item to the collection.
14547  * @param {String} key The key to associate with the item
14548  * @param {Object} o The item to add.
14549  * @return {Object} The item added.
14550  */
14551     add : function(key, o){
14552         if(arguments.length == 1){
14553             o = arguments[0];
14554             key = this.getKey(o);
14555         }
14556         if(typeof key == "undefined" || key === null){
14557             this.length++;
14558             this.items.push(o);
14559             this.keys.push(null);
14560         }else{
14561             var old = this.map[key];
14562             if(old){
14563                 return this.replace(key, o);
14564             }
14565             this.length++;
14566             this.items.push(o);
14567             this.map[key] = o;
14568             this.keys.push(key);
14569         }
14570         this.fireEvent("add", this.length-1, o, key);
14571         return o;
14572     },
14573        
14574 /**
14575   * MixedCollection has a generic way to fetch keys if you implement getKey.
14576 <pre><code>
14577 // normal way
14578 var mc = new Roo.util.MixedCollection();
14579 mc.add(someEl.dom.id, someEl);
14580 mc.add(otherEl.dom.id, otherEl);
14581 //and so on
14582
14583 // using getKey
14584 var mc = new Roo.util.MixedCollection();
14585 mc.getKey = function(el){
14586    return el.dom.id;
14587 };
14588 mc.add(someEl);
14589 mc.add(otherEl);
14590
14591 // or via the constructor
14592 var mc = new Roo.util.MixedCollection(false, function(el){
14593    return el.dom.id;
14594 });
14595 mc.add(someEl);
14596 mc.add(otherEl);
14597 </code></pre>
14598  * @param o {Object} The item for which to find the key.
14599  * @return {Object} The key for the passed item.
14600  */
14601     getKey : function(o){
14602          return o.id; 
14603     },
14604    
14605 /**
14606  * Replaces an item in the collection.
14607  * @param {String} key The key associated with the item to replace, or the item to replace.
14608  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14609  * @return {Object}  The new item.
14610  */
14611     replace : function(key, o){
14612         if(arguments.length == 1){
14613             o = arguments[0];
14614             key = this.getKey(o);
14615         }
14616         var old = this.item(key);
14617         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14618              return this.add(key, o);
14619         }
14620         var index = this.indexOfKey(key);
14621         this.items[index] = o;
14622         this.map[key] = o;
14623         this.fireEvent("replace", key, old, o);
14624         return o;
14625     },
14626    
14627 /**
14628  * Adds all elements of an Array or an Object to the collection.
14629  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14630  * an Array of values, each of which are added to the collection.
14631  */
14632     addAll : function(objs){
14633         if(arguments.length > 1 || objs instanceof Array){
14634             var args = arguments.length > 1 ? arguments : objs;
14635             for(var i = 0, len = args.length; i < len; i++){
14636                 this.add(args[i]);
14637             }
14638         }else{
14639             for(var key in objs){
14640                 if(this.allowFunctions || typeof objs[key] != "function"){
14641                     this.add(key, objs[key]);
14642                 }
14643             }
14644         }
14645     },
14646    
14647 /**
14648  * Executes the specified function once for every item in the collection, passing each
14649  * item as the first and only parameter. returning false from the function will stop the iteration.
14650  * @param {Function} fn The function to execute for each item.
14651  * @param {Object} scope (optional) The scope in which to execute the function.
14652  */
14653     each : function(fn, scope){
14654         var items = [].concat(this.items); // each safe for removal
14655         for(var i = 0, len = items.length; i < len; i++){
14656             if(fn.call(scope || items[i], items[i], i, len) === false){
14657                 break;
14658             }
14659         }
14660     },
14661    
14662 /**
14663  * Executes the specified function once for every key in the collection, passing each
14664  * key, and its associated item as the first two parameters.
14665  * @param {Function} fn The function to execute for each item.
14666  * @param {Object} scope (optional) The scope in which to execute the function.
14667  */
14668     eachKey : function(fn, scope){
14669         for(var i = 0, len = this.keys.length; i < len; i++){
14670             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14671         }
14672     },
14673    
14674 /**
14675  * Returns the first item in the collection which elicits a true return value from the
14676  * passed selection function.
14677  * @param {Function} fn The selection function to execute for each item.
14678  * @param {Object} scope (optional) The scope in which to execute the function.
14679  * @return {Object} The first item in the collection which returned true from the selection function.
14680  */
14681     find : function(fn, scope){
14682         for(var i = 0, len = this.items.length; i < len; i++){
14683             if(fn.call(scope || window, this.items[i], this.keys[i])){
14684                 return this.items[i];
14685             }
14686         }
14687         return null;
14688     },
14689    
14690 /**
14691  * Inserts an item at the specified index in the collection.
14692  * @param {Number} index The index to insert the item at.
14693  * @param {String} key The key to associate with the new item, or the item itself.
14694  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14695  * @return {Object} The item inserted.
14696  */
14697     insert : function(index, key, o){
14698         if(arguments.length == 2){
14699             o = arguments[1];
14700             key = this.getKey(o);
14701         }
14702         if(index >= this.length){
14703             return this.add(key, o);
14704         }
14705         this.length++;
14706         this.items.splice(index, 0, o);
14707         if(typeof key != "undefined" && key != null){
14708             this.map[key] = o;
14709         }
14710         this.keys.splice(index, 0, key);
14711         this.fireEvent("add", index, o, key);
14712         return o;
14713     },
14714    
14715 /**
14716  * Removed an item from the collection.
14717  * @param {Object} o The item to remove.
14718  * @return {Object} The item removed.
14719  */
14720     remove : function(o){
14721         return this.removeAt(this.indexOf(o));
14722     },
14723    
14724 /**
14725  * Remove an item from a specified index in the collection.
14726  * @param {Number} index The index within the collection of the item to remove.
14727  */
14728     removeAt : function(index){
14729         if(index < this.length && index >= 0){
14730             this.length--;
14731             var o = this.items[index];
14732             this.items.splice(index, 1);
14733             var key = this.keys[index];
14734             if(typeof key != "undefined"){
14735                 delete this.map[key];
14736             }
14737             this.keys.splice(index, 1);
14738             this.fireEvent("remove", o, key);
14739         }
14740     },
14741    
14742 /**
14743  * Removed an item associated with the passed key fom the collection.
14744  * @param {String} key The key of the item to remove.
14745  */
14746     removeKey : function(key){
14747         return this.removeAt(this.indexOfKey(key));
14748     },
14749    
14750 /**
14751  * Returns the number of items in the collection.
14752  * @return {Number} the number of items in the collection.
14753  */
14754     getCount : function(){
14755         return this.length; 
14756     },
14757    
14758 /**
14759  * Returns index within the collection of the passed Object.
14760  * @param {Object} o The item to find the index of.
14761  * @return {Number} index of the item.
14762  */
14763     indexOf : function(o){
14764         if(!this.items.indexOf){
14765             for(var i = 0, len = this.items.length; i < len; i++){
14766                 if(this.items[i] == o) {
14767                     return i;
14768                 }
14769             }
14770             return -1;
14771         }else{
14772             return this.items.indexOf(o);
14773         }
14774     },
14775    
14776 /**
14777  * Returns index within the collection of the passed key.
14778  * @param {String} key The key to find the index of.
14779  * @return {Number} index of the key.
14780  */
14781     indexOfKey : function(key){
14782         if(!this.keys.indexOf){
14783             for(var i = 0, len = this.keys.length; i < len; i++){
14784                 if(this.keys[i] == key) {
14785                     return i;
14786                 }
14787             }
14788             return -1;
14789         }else{
14790             return this.keys.indexOf(key);
14791         }
14792     },
14793    
14794 /**
14795  * Returns the item associated with the passed key OR index. Key has priority over index.
14796  * @param {String/Number} key The key or index of the item.
14797  * @return {Object} The item associated with the passed key.
14798  */
14799     item : function(key){
14800         if (key === 'length') {
14801             return null;
14802         }
14803         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14804         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14805     },
14806     
14807 /**
14808  * Returns the item at the specified index.
14809  * @param {Number} index The index of the item.
14810  * @return {Object}
14811  */
14812     itemAt : function(index){
14813         return this.items[index];
14814     },
14815     
14816 /**
14817  * Returns the item associated with the passed key.
14818  * @param {String/Number} key The key of the item.
14819  * @return {Object} The item associated with the passed key.
14820  */
14821     key : function(key){
14822         return this.map[key];
14823     },
14824    
14825 /**
14826  * Returns true if the collection contains the passed Object as an item.
14827  * @param {Object} o  The Object to look for in the collection.
14828  * @return {Boolean} True if the collection contains the Object as an item.
14829  */
14830     contains : function(o){
14831         return this.indexOf(o) != -1;
14832     },
14833    
14834 /**
14835  * Returns true if the collection contains the passed Object as a key.
14836  * @param {String} key The key to look for in the collection.
14837  * @return {Boolean} True if the collection contains the Object as a key.
14838  */
14839     containsKey : function(key){
14840         return typeof this.map[key] != "undefined";
14841     },
14842    
14843 /**
14844  * Removes all items from the collection.
14845  */
14846     clear : function(){
14847         this.length = 0;
14848         this.items = [];
14849         this.keys = [];
14850         this.map = {};
14851         this.fireEvent("clear");
14852     },
14853    
14854 /**
14855  * Returns the first item in the collection.
14856  * @return {Object} the first item in the collection..
14857  */
14858     first : function(){
14859         return this.items[0]; 
14860     },
14861    
14862 /**
14863  * Returns the last item in the collection.
14864  * @return {Object} the last item in the collection..
14865  */
14866     last : function(){
14867         return this.items[this.length-1];   
14868     },
14869     
14870     _sort : function(property, dir, fn){
14871         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14872         fn = fn || function(a, b){
14873             return a-b;
14874         };
14875         var c = [], k = this.keys, items = this.items;
14876         for(var i = 0, len = items.length; i < len; i++){
14877             c[c.length] = {key: k[i], value: items[i], index: i};
14878         }
14879         c.sort(function(a, b){
14880             var v = fn(a[property], b[property]) * dsc;
14881             if(v == 0){
14882                 v = (a.index < b.index ? -1 : 1);
14883             }
14884             return v;
14885         });
14886         for(var i = 0, len = c.length; i < len; i++){
14887             items[i] = c[i].value;
14888             k[i] = c[i].key;
14889         }
14890         this.fireEvent("sort", this);
14891     },
14892     
14893     /**
14894      * Sorts this collection with the passed comparison function
14895      * @param {String} direction (optional) "ASC" or "DESC"
14896      * @param {Function} fn (optional) comparison function
14897      */
14898     sort : function(dir, fn){
14899         this._sort("value", dir, fn);
14900     },
14901     
14902     /**
14903      * Sorts this collection by keys
14904      * @param {String} direction (optional) "ASC" or "DESC"
14905      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14906      */
14907     keySort : function(dir, fn){
14908         this._sort("key", dir, fn || function(a, b){
14909             return String(a).toUpperCase()-String(b).toUpperCase();
14910         });
14911     },
14912     
14913     /**
14914      * Returns a range of items in this collection
14915      * @param {Number} startIndex (optional) defaults to 0
14916      * @param {Number} endIndex (optional) default to the last item
14917      * @return {Array} An array of items
14918      */
14919     getRange : function(start, end){
14920         var items = this.items;
14921         if(items.length < 1){
14922             return [];
14923         }
14924         start = start || 0;
14925         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14926         var r = [];
14927         if(start <= end){
14928             for(var i = start; i <= end; i++) {
14929                     r[r.length] = items[i];
14930             }
14931         }else{
14932             for(var i = start; i >= end; i--) {
14933                     r[r.length] = items[i];
14934             }
14935         }
14936         return r;
14937     },
14938         
14939     /**
14940      * Filter the <i>objects</i> in this collection by a specific property. 
14941      * Returns a new collection that has been filtered.
14942      * @param {String} property A property on your objects
14943      * @param {String/RegExp} value Either string that the property values 
14944      * should start with or a RegExp to test against the property
14945      * @return {MixedCollection} The new filtered collection
14946      */
14947     filter : function(property, value){
14948         if(!value.exec){ // not a regex
14949             value = String(value);
14950             if(value.length == 0){
14951                 return this.clone();
14952             }
14953             value = new RegExp("^" + Roo.escapeRe(value), "i");
14954         }
14955         return this.filterBy(function(o){
14956             return o && value.test(o[property]);
14957         });
14958         },
14959     
14960     /**
14961      * Filter by a function. * Returns a new collection that has been filtered.
14962      * The passed function will be called with each 
14963      * object in the collection. If the function returns true, the value is included 
14964      * otherwise it is filtered.
14965      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14966      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14967      * @return {MixedCollection} The new filtered collection
14968      */
14969     filterBy : function(fn, scope){
14970         var r = new Roo.util.MixedCollection();
14971         r.getKey = this.getKey;
14972         var k = this.keys, it = this.items;
14973         for(var i = 0, len = it.length; i < len; i++){
14974             if(fn.call(scope||this, it[i], k[i])){
14975                                 r.add(k[i], it[i]);
14976                         }
14977         }
14978         return r;
14979     },
14980     
14981     /**
14982      * Creates a duplicate of this collection
14983      * @return {MixedCollection}
14984      */
14985     clone : function(){
14986         var r = new Roo.util.MixedCollection();
14987         var k = this.keys, it = this.items;
14988         for(var i = 0, len = it.length; i < len; i++){
14989             r.add(k[i], it[i]);
14990         }
14991         r.getKey = this.getKey;
14992         return r;
14993     }
14994 });
14995 /**
14996  * Returns the item associated with the passed key or index.
14997  * @method
14998  * @param {String/Number} key The key or index of the item.
14999  * @return {Object} The item associated with the passed key.
15000  */
15001 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
15002  * Based on:
15003  * Ext JS Library 1.1.1
15004  * Copyright(c) 2006-2007, Ext JS, LLC.
15005  *
15006  * Originally Released Under LGPL - original licence link has changed is not relivant.
15007  *
15008  * Fork - LGPL
15009  * <script type="text/javascript">
15010  */
15011 /**
15012  * @class Roo.util.JSON
15013  * Modified version of Douglas Crockford"s json.js that doesn"t
15014  * mess with the Object prototype 
15015  * http://www.json.org/js.html
15016  * @static
15017  */
15018 Roo.util.JSON = new (function(){
15019     var useHasOwn = {}.hasOwnProperty ? true : false;
15020     
15021     // crashes Safari in some instances
15022     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
15023     
15024     var pad = function(n) {
15025         return n < 10 ? "0" + n : n;
15026     };
15027     
15028     var m = {
15029         "\b": '\\b',
15030         "\t": '\\t',
15031         "\n": '\\n',
15032         "\f": '\\f',
15033         "\r": '\\r',
15034         '"' : '\\"',
15035         "\\": '\\\\'
15036     };
15037
15038     var encodeString = function(s){
15039         if (/["\\\x00-\x1f]/.test(s)) {
15040             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15041                 var c = m[b];
15042                 if(c){
15043                     return c;
15044                 }
15045                 c = b.charCodeAt();
15046                 return "\\u00" +
15047                     Math.floor(c / 16).toString(16) +
15048                     (c % 16).toString(16);
15049             }) + '"';
15050         }
15051         return '"' + s + '"';
15052     };
15053     
15054     var encodeArray = function(o){
15055         var a = ["["], b, i, l = o.length, v;
15056             for (i = 0; i < l; i += 1) {
15057                 v = o[i];
15058                 switch (typeof v) {
15059                     case "undefined":
15060                     case "function":
15061                     case "unknown":
15062                         break;
15063                     default:
15064                         if (b) {
15065                             a.push(',');
15066                         }
15067                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15068                         b = true;
15069                 }
15070             }
15071             a.push("]");
15072             return a.join("");
15073     };
15074     
15075     var encodeDate = function(o){
15076         return '"' + o.getFullYear() + "-" +
15077                 pad(o.getMonth() + 1) + "-" +
15078                 pad(o.getDate()) + "T" +
15079                 pad(o.getHours()) + ":" +
15080                 pad(o.getMinutes()) + ":" +
15081                 pad(o.getSeconds()) + '"';
15082     };
15083     
15084     /**
15085      * Encodes an Object, Array or other value
15086      * @param {Mixed} o The variable to encode
15087      * @return {String} The JSON string
15088      */
15089     this.encode = function(o)
15090     {
15091         // should this be extended to fully wrap stringify..
15092         
15093         if(typeof o == "undefined" || o === null){
15094             return "null";
15095         }else if(o instanceof Array){
15096             return encodeArray(o);
15097         }else if(o instanceof Date){
15098             return encodeDate(o);
15099         }else if(typeof o == "string"){
15100             return encodeString(o);
15101         }else if(typeof o == "number"){
15102             return isFinite(o) ? String(o) : "null";
15103         }else if(typeof o == "boolean"){
15104             return String(o);
15105         }else {
15106             var a = ["{"], b, i, v;
15107             for (i in o) {
15108                 if(!useHasOwn || o.hasOwnProperty(i)) {
15109                     v = o[i];
15110                     switch (typeof v) {
15111                     case "undefined":
15112                     case "function":
15113                     case "unknown":
15114                         break;
15115                     default:
15116                         if(b){
15117                             a.push(',');
15118                         }
15119                         a.push(this.encode(i), ":",
15120                                 v === null ? "null" : this.encode(v));
15121                         b = true;
15122                     }
15123                 }
15124             }
15125             a.push("}");
15126             return a.join("");
15127         }
15128     };
15129     
15130     /**
15131      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15132      * @param {String} json The JSON string
15133      * @return {Object} The resulting object
15134      */
15135     this.decode = function(json){
15136         
15137         return  /** eval:var:json */ eval("(" + json + ')');
15138     };
15139 })();
15140 /** 
15141  * Shorthand for {@link Roo.util.JSON#encode}
15142  * @member Roo encode 
15143  * @method */
15144 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15145 /** 
15146  * Shorthand for {@link Roo.util.JSON#decode}
15147  * @member Roo decode 
15148  * @method */
15149 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15150 /*
15151  * Based on:
15152  * Ext JS Library 1.1.1
15153  * Copyright(c) 2006-2007, Ext JS, LLC.
15154  *
15155  * Originally Released Under LGPL - original licence link has changed is not relivant.
15156  *
15157  * Fork - LGPL
15158  * <script type="text/javascript">
15159  */
15160  
15161 /**
15162  * @class Roo.util.Format
15163  * Reusable data formatting functions
15164  * @static
15165  */
15166 Roo.util.Format = function(){
15167     var trimRe = /^\s+|\s+$/g;
15168     return {
15169         /**
15170          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15171          * @param {String} value The string to truncate
15172          * @param {Number} length The maximum length to allow before truncating
15173          * @return {String} The converted text
15174          */
15175         ellipsis : function(value, len){
15176             if(value && value.length > len){
15177                 return value.substr(0, len-3)+"...";
15178             }
15179             return value;
15180         },
15181
15182         /**
15183          * Checks a reference and converts it to empty string if it is undefined
15184          * @param {Mixed} value Reference to check
15185          * @return {Mixed} Empty string if converted, otherwise the original value
15186          */
15187         undef : function(value){
15188             return typeof value != "undefined" ? value : "";
15189         },
15190
15191         /**
15192          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15193          * @param {String} value The string to encode
15194          * @return {String} The encoded text
15195          */
15196         htmlEncode : function(value){
15197             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
15198         },
15199
15200         /**
15201          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15202          * @param {String} value The string to decode
15203          * @return {String} The decoded text
15204          */
15205         htmlDecode : function(value){
15206             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15207         },
15208
15209         /**
15210          * Trims any whitespace from either side of a string
15211          * @param {String} value The text to trim
15212          * @return {String} The trimmed text
15213          */
15214         trim : function(value){
15215             return String(value).replace(trimRe, "");
15216         },
15217
15218         /**
15219          * Returns a substring from within an original string
15220          * @param {String} value The original text
15221          * @param {Number} start The start index of the substring
15222          * @param {Number} length The length of the substring
15223          * @return {String} The substring
15224          */
15225         substr : function(value, start, length){
15226             return String(value).substr(start, length);
15227         },
15228
15229         /**
15230          * Converts a string to all lower case letters
15231          * @param {String} value The text to convert
15232          * @return {String} The converted text
15233          */
15234         lowercase : function(value){
15235             return String(value).toLowerCase();
15236         },
15237
15238         /**
15239          * Converts a string to all upper case letters
15240          * @param {String} value The text to convert
15241          * @return {String} The converted text
15242          */
15243         uppercase : function(value){
15244             return String(value).toUpperCase();
15245         },
15246
15247         /**
15248          * Converts the first character only of a string to upper case
15249          * @param {String} value The text to convert
15250          * @return {String} The converted text
15251          */
15252         capitalize : function(value){
15253             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15254         },
15255
15256         // private
15257         call : function(value, fn){
15258             if(arguments.length > 2){
15259                 var args = Array.prototype.slice.call(arguments, 2);
15260                 args.unshift(value);
15261                  
15262                 return /** eval:var:value */  eval(fn).apply(window, args);
15263             }else{
15264                 /** eval:var:value */
15265                 return /** eval:var:value */ eval(fn).call(window, value);
15266             }
15267         },
15268
15269        
15270         /**
15271          * safer version of Math.toFixed..??/
15272          * @param {Number/String} value The numeric value to format
15273          * @param {Number/String} value Decimal places 
15274          * @return {String} The formatted currency string
15275          */
15276         toFixed : function(v, n)
15277         {
15278             // why not use to fixed - precision is buggered???
15279             if (!n) {
15280                 return Math.round(v-0);
15281             }
15282             var fact = Math.pow(10,n+1);
15283             v = (Math.round((v-0)*fact))/fact;
15284             var z = (''+fact).substring(2);
15285             if (v == Math.floor(v)) {
15286                 return Math.floor(v) + '.' + z;
15287             }
15288             
15289             // now just padd decimals..
15290             var ps = String(v).split('.');
15291             var fd = (ps[1] + z);
15292             var r = fd.substring(0,n); 
15293             var rm = fd.substring(n); 
15294             if (rm < 5) {
15295                 return ps[0] + '.' + r;
15296             }
15297             r*=1; // turn it into a number;
15298             r++;
15299             if (String(r).length != n) {
15300                 ps[0]*=1;
15301                 ps[0]++;
15302                 r = String(r).substring(1); // chop the end off.
15303             }
15304             
15305             return ps[0] + '.' + r;
15306              
15307         },
15308         
15309         /**
15310          * Format a number as US currency
15311          * @param {Number/String} value The numeric value to format
15312          * @return {String} The formatted currency string
15313          */
15314         usMoney : function(v){
15315             return '$' + Roo.util.Format.number(v);
15316         },
15317         
15318         /**
15319          * Format a number
15320          * eventually this should probably emulate php's number_format
15321          * @param {Number/String} value The numeric value to format
15322          * @param {Number} decimals number of decimal places
15323          * @param {String} delimiter for thousands (default comma)
15324          * @return {String} The formatted currency string
15325          */
15326         number : function(v, decimals, thousandsDelimiter)
15327         {
15328             // multiply and round.
15329             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15330             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15331             
15332             var mul = Math.pow(10, decimals);
15333             var zero = String(mul).substring(1);
15334             v = (Math.round((v-0)*mul))/mul;
15335             
15336             // if it's '0' number.. then
15337             
15338             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15339             v = String(v);
15340             var ps = v.split('.');
15341             var whole = ps[0];
15342             
15343             var r = /(\d+)(\d{3})/;
15344             // add comma's
15345             
15346             if(thousandsDelimiter.length != 0) {
15347                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15348             } 
15349             
15350             var sub = ps[1] ?
15351                     // has decimals..
15352                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15353                     // does not have decimals
15354                     (decimals ? ('.' + zero) : '');
15355             
15356             
15357             return whole + sub ;
15358         },
15359         
15360         /**
15361          * Parse a value into a formatted date using the specified format pattern.
15362          * @param {Mixed} value The value to format
15363          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15364          * @return {String} The formatted date string
15365          */
15366         date : function(v, format){
15367             if(!v){
15368                 return "";
15369             }
15370             if(!(v instanceof Date)){
15371                 v = new Date(Date.parse(v));
15372             }
15373             return v.dateFormat(format || Roo.util.Format.defaults.date);
15374         },
15375
15376         /**
15377          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15378          * @param {String} format Any valid date format string
15379          * @return {Function} The date formatting function
15380          */
15381         dateRenderer : function(format){
15382             return function(v){
15383                 return Roo.util.Format.date(v, format);  
15384             };
15385         },
15386
15387         // private
15388         stripTagsRE : /<\/?[^>]+>/gi,
15389         
15390         /**
15391          * Strips all HTML tags
15392          * @param {Mixed} value The text from which to strip tags
15393          * @return {String} The stripped text
15394          */
15395         stripTags : function(v){
15396             return !v ? v : String(v).replace(this.stripTagsRE, "");
15397         },
15398         
15399         /**
15400          * Size in Mb,Gb etc.
15401          * @param {Number} value The number to be formated
15402          * @param {number} decimals how many decimal places
15403          * @return {String} the formated string
15404          */
15405         size : function(value, decimals)
15406         {
15407             var sizes = ['b', 'k', 'M', 'G', 'T'];
15408             if (value == 0) {
15409                 return 0;
15410             }
15411             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15412             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15413         }
15414         
15415         
15416         
15417     };
15418 }();
15419 Roo.util.Format.defaults = {
15420     date : 'd/M/Y'
15421 };/*
15422  * Based on:
15423  * Ext JS Library 1.1.1
15424  * Copyright(c) 2006-2007, Ext JS, LLC.
15425  *
15426  * Originally Released Under LGPL - original licence link has changed is not relivant.
15427  *
15428  * Fork - LGPL
15429  * <script type="text/javascript">
15430  */
15431
15432
15433  
15434
15435 /**
15436  * @class Roo.MasterTemplate
15437  * @extends Roo.Template
15438  * Provides a template that can have child templates. The syntax is:
15439 <pre><code>
15440 var t = new Roo.MasterTemplate(
15441         '&lt;select name="{name}"&gt;',
15442                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15443         '&lt;/select&gt;'
15444 );
15445 t.add('options', {value: 'foo', text: 'bar'});
15446 // or you can add multiple child elements in one shot
15447 t.addAll('options', [
15448     {value: 'foo', text: 'bar'},
15449     {value: 'foo2', text: 'bar2'},
15450     {value: 'foo3', text: 'bar3'}
15451 ]);
15452 // then append, applying the master template values
15453 t.append('my-form', {name: 'my-select'});
15454 </code></pre>
15455 * A name attribute for the child template is not required if you have only one child
15456 * template or you want to refer to them by index.
15457  */
15458 Roo.MasterTemplate = function(){
15459     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15460     this.originalHtml = this.html;
15461     var st = {};
15462     var m, re = this.subTemplateRe;
15463     re.lastIndex = 0;
15464     var subIndex = 0;
15465     while(m = re.exec(this.html)){
15466         var name = m[1], content = m[2];
15467         st[subIndex] = {
15468             name: name,
15469             index: subIndex,
15470             buffer: [],
15471             tpl : new Roo.Template(content)
15472         };
15473         if(name){
15474             st[name] = st[subIndex];
15475         }
15476         st[subIndex].tpl.compile();
15477         st[subIndex].tpl.call = this.call.createDelegate(this);
15478         subIndex++;
15479     }
15480     this.subCount = subIndex;
15481     this.subs = st;
15482 };
15483 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15484     /**
15485     * The regular expression used to match sub templates
15486     * @type RegExp
15487     * @property
15488     */
15489     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15490
15491     /**
15492      * Applies the passed values to a child template.
15493      * @param {String/Number} name (optional) The name or index of the child template
15494      * @param {Array/Object} values The values to be applied to the template
15495      * @return {MasterTemplate} this
15496      */
15497      add : function(name, values){
15498         if(arguments.length == 1){
15499             values = arguments[0];
15500             name = 0;
15501         }
15502         var s = this.subs[name];
15503         s.buffer[s.buffer.length] = s.tpl.apply(values);
15504         return this;
15505     },
15506
15507     /**
15508      * Applies all the passed values to a child template.
15509      * @param {String/Number} name (optional) The name or index of the child template
15510      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15511      * @param {Boolean} reset (optional) True to reset the template first
15512      * @return {MasterTemplate} this
15513      */
15514     fill : function(name, values, reset){
15515         var a = arguments;
15516         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15517             values = a[0];
15518             name = 0;
15519             reset = a[1];
15520         }
15521         if(reset){
15522             this.reset();
15523         }
15524         for(var i = 0, len = values.length; i < len; i++){
15525             this.add(name, values[i]);
15526         }
15527         return this;
15528     },
15529
15530     /**
15531      * Resets the template for reuse
15532      * @return {MasterTemplate} this
15533      */
15534      reset : function(){
15535         var s = this.subs;
15536         for(var i = 0; i < this.subCount; i++){
15537             s[i].buffer = [];
15538         }
15539         return this;
15540     },
15541
15542     applyTemplate : function(values){
15543         var s = this.subs;
15544         var replaceIndex = -1;
15545         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15546             return s[++replaceIndex].buffer.join("");
15547         });
15548         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15549     },
15550
15551     apply : function(){
15552         return this.applyTemplate.apply(this, arguments);
15553     },
15554
15555     compile : function(){return this;}
15556 });
15557
15558 /**
15559  * Alias for fill().
15560  * @method
15561  */
15562 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15563  /**
15564  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15565  * var tpl = Roo.MasterTemplate.from('element-id');
15566  * @param {String/HTMLElement} el
15567  * @param {Object} config
15568  * @static
15569  */
15570 Roo.MasterTemplate.from = function(el, config){
15571     el = Roo.getDom(el);
15572     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15573 };/*
15574  * Based on:
15575  * Ext JS Library 1.1.1
15576  * Copyright(c) 2006-2007, Ext JS, LLC.
15577  *
15578  * Originally Released Under LGPL - original licence link has changed is not relivant.
15579  *
15580  * Fork - LGPL
15581  * <script type="text/javascript">
15582  */
15583
15584  
15585 /**
15586  * @class Roo.util.CSS
15587  * Utility class for manipulating CSS rules
15588  * @static
15589
15590  */
15591 Roo.util.CSS = function(){
15592         var rules = null;
15593         var doc = document;
15594
15595     var camelRe = /(-[a-z])/gi;
15596     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15597
15598    return {
15599    /**
15600     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15601     * tag and appended to the HEAD of the document.
15602     * @param {String|Object} cssText The text containing the css rules
15603     * @param {String} id An id to add to the stylesheet for later removal
15604     * @return {StyleSheet}
15605     */
15606     createStyleSheet : function(cssText, id){
15607         var ss;
15608         var head = doc.getElementsByTagName("head")[0];
15609         var nrules = doc.createElement("style");
15610         nrules.setAttribute("type", "text/css");
15611         if(id){
15612             nrules.setAttribute("id", id);
15613         }
15614         if (typeof(cssText) != 'string') {
15615             // support object maps..
15616             // not sure if this a good idea.. 
15617             // perhaps it should be merged with the general css handling
15618             // and handle js style props.
15619             var cssTextNew = [];
15620             for(var n in cssText) {
15621                 var citems = [];
15622                 for(var k in cssText[n]) {
15623                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15624                 }
15625                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15626                 
15627             }
15628             cssText = cssTextNew.join("\n");
15629             
15630         }
15631        
15632        
15633        if(Roo.isIE){
15634            head.appendChild(nrules);
15635            ss = nrules.styleSheet;
15636            ss.cssText = cssText;
15637        }else{
15638            try{
15639                 nrules.appendChild(doc.createTextNode(cssText));
15640            }catch(e){
15641                nrules.cssText = cssText; 
15642            }
15643            head.appendChild(nrules);
15644            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15645        }
15646        this.cacheStyleSheet(ss);
15647        return ss;
15648    },
15649
15650    /**
15651     * Removes a style or link tag by id
15652     * @param {String} id The id of the tag
15653     */
15654    removeStyleSheet : function(id){
15655        var existing = doc.getElementById(id);
15656        if(existing){
15657            existing.parentNode.removeChild(existing);
15658        }
15659    },
15660
15661    /**
15662     * Dynamically swaps an existing stylesheet reference for a new one
15663     * @param {String} id The id of an existing link tag to remove
15664     * @param {String} url The href of the new stylesheet to include
15665     */
15666    swapStyleSheet : function(id, url){
15667        this.removeStyleSheet(id);
15668        var ss = doc.createElement("link");
15669        ss.setAttribute("rel", "stylesheet");
15670        ss.setAttribute("type", "text/css");
15671        ss.setAttribute("id", id);
15672        ss.setAttribute("href", url);
15673        doc.getElementsByTagName("head")[0].appendChild(ss);
15674    },
15675    
15676    /**
15677     * Refresh the rule cache if you have dynamically added stylesheets
15678     * @return {Object} An object (hash) of rules indexed by selector
15679     */
15680    refreshCache : function(){
15681        return this.getRules(true);
15682    },
15683
15684    // private
15685    cacheStyleSheet : function(stylesheet){
15686        if(!rules){
15687            rules = {};
15688        }
15689        try{// try catch for cross domain access issue
15690            var ssRules = stylesheet.cssRules || stylesheet.rules;
15691            for(var j = ssRules.length-1; j >= 0; --j){
15692                rules[ssRules[j].selectorText] = ssRules[j];
15693            }
15694        }catch(e){}
15695    },
15696    
15697    /**
15698     * Gets all css rules for the document
15699     * @param {Boolean} refreshCache true to refresh the internal cache
15700     * @return {Object} An object (hash) of rules indexed by selector
15701     */
15702    getRules : function(refreshCache){
15703                 if(rules == null || refreshCache){
15704                         rules = {};
15705                         var ds = doc.styleSheets;
15706                         for(var i =0, len = ds.length; i < len; i++){
15707                             try{
15708                         this.cacheStyleSheet(ds[i]);
15709                     }catch(e){} 
15710                 }
15711                 }
15712                 return rules;
15713         },
15714         
15715         /**
15716     * Gets an an individual CSS rule by selector(s)
15717     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15718     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15719     * @return {CSSRule} The CSS rule or null if one is not found
15720     */
15721    getRule : function(selector, refreshCache){
15722                 var rs = this.getRules(refreshCache);
15723                 if(!(selector instanceof Array)){
15724                     return rs[selector];
15725                 }
15726                 for(var i = 0; i < selector.length; i++){
15727                         if(rs[selector[i]]){
15728                                 return rs[selector[i]];
15729                         }
15730                 }
15731                 return null;
15732         },
15733         
15734         
15735         /**
15736     * Updates a rule property
15737     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15738     * @param {String} property The css property
15739     * @param {String} value The new value for the property
15740     * @return {Boolean} true If a rule was found and updated
15741     */
15742    updateRule : function(selector, property, value){
15743                 if(!(selector instanceof Array)){
15744                         var rule = this.getRule(selector);
15745                         if(rule){
15746                                 rule.style[property.replace(camelRe, camelFn)] = value;
15747                                 return true;
15748                         }
15749                 }else{
15750                         for(var i = 0; i < selector.length; i++){
15751                                 if(this.updateRule(selector[i], property, value)){
15752                                         return true;
15753                                 }
15754                         }
15755                 }
15756                 return false;
15757         }
15758    };   
15759 }();/*
15760  * Based on:
15761  * Ext JS Library 1.1.1
15762  * Copyright(c) 2006-2007, Ext JS, LLC.
15763  *
15764  * Originally Released Under LGPL - original licence link has changed is not relivant.
15765  *
15766  * Fork - LGPL
15767  * <script type="text/javascript">
15768  */
15769
15770  
15771
15772 /**
15773  * @class Roo.util.ClickRepeater
15774  * @extends Roo.util.Observable
15775  * 
15776  * A wrapper class which can be applied to any element. Fires a "click" event while the
15777  * mouse is pressed. The interval between firings may be specified in the config but
15778  * defaults to 10 milliseconds.
15779  * 
15780  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15781  * 
15782  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15783  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15784  * Similar to an autorepeat key delay.
15785  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15786  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15787  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15788  *           "interval" and "delay" are ignored. "immediate" is honored.
15789  * @cfg {Boolean} preventDefault True to prevent the default click event
15790  * @cfg {Boolean} stopDefault True to stop the default click event
15791  * 
15792  * @history
15793  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15794  *     2007-02-02 jvs Renamed to ClickRepeater
15795  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15796  *
15797  *  @constructor
15798  * @param {String/HTMLElement/Element} el The element to listen on
15799  * @param {Object} config
15800  **/
15801 Roo.util.ClickRepeater = function(el, config)
15802 {
15803     this.el = Roo.get(el);
15804     this.el.unselectable();
15805
15806     Roo.apply(this, config);
15807
15808     this.addEvents({
15809     /**
15810      * @event mousedown
15811      * Fires when the mouse button is depressed.
15812      * @param {Roo.util.ClickRepeater} this
15813      */
15814         "mousedown" : true,
15815     /**
15816      * @event click
15817      * Fires on a specified interval during the time the element is pressed.
15818      * @param {Roo.util.ClickRepeater} this
15819      */
15820         "click" : true,
15821     /**
15822      * @event mouseup
15823      * Fires when the mouse key is released.
15824      * @param {Roo.util.ClickRepeater} this
15825      */
15826         "mouseup" : true
15827     });
15828
15829     this.el.on("mousedown", this.handleMouseDown, this);
15830     if(this.preventDefault || this.stopDefault){
15831         this.el.on("click", function(e){
15832             if(this.preventDefault){
15833                 e.preventDefault();
15834             }
15835             if(this.stopDefault){
15836                 e.stopEvent();
15837             }
15838         }, this);
15839     }
15840
15841     // allow inline handler
15842     if(this.handler){
15843         this.on("click", this.handler,  this.scope || this);
15844     }
15845
15846     Roo.util.ClickRepeater.superclass.constructor.call(this);
15847 };
15848
15849 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15850     interval : 20,
15851     delay: 250,
15852     preventDefault : true,
15853     stopDefault : false,
15854     timer : 0,
15855
15856     // private
15857     handleMouseDown : function(){
15858         clearTimeout(this.timer);
15859         this.el.blur();
15860         if(this.pressClass){
15861             this.el.addClass(this.pressClass);
15862         }
15863         this.mousedownTime = new Date();
15864
15865         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15866         this.el.on("mouseout", this.handleMouseOut, this);
15867
15868         this.fireEvent("mousedown", this);
15869         this.fireEvent("click", this);
15870         
15871         this.timer = this.click.defer(this.delay || this.interval, this);
15872     },
15873
15874     // private
15875     click : function(){
15876         this.fireEvent("click", this);
15877         this.timer = this.click.defer(this.getInterval(), this);
15878     },
15879
15880     // private
15881     getInterval: function(){
15882         if(!this.accelerate){
15883             return this.interval;
15884         }
15885         var pressTime = this.mousedownTime.getElapsed();
15886         if(pressTime < 500){
15887             return 400;
15888         }else if(pressTime < 1700){
15889             return 320;
15890         }else if(pressTime < 2600){
15891             return 250;
15892         }else if(pressTime < 3500){
15893             return 180;
15894         }else if(pressTime < 4400){
15895             return 140;
15896         }else if(pressTime < 5300){
15897             return 80;
15898         }else if(pressTime < 6200){
15899             return 50;
15900         }else{
15901             return 10;
15902         }
15903     },
15904
15905     // private
15906     handleMouseOut : function(){
15907         clearTimeout(this.timer);
15908         if(this.pressClass){
15909             this.el.removeClass(this.pressClass);
15910         }
15911         this.el.on("mouseover", this.handleMouseReturn, this);
15912     },
15913
15914     // private
15915     handleMouseReturn : function(){
15916         this.el.un("mouseover", this.handleMouseReturn);
15917         if(this.pressClass){
15918             this.el.addClass(this.pressClass);
15919         }
15920         this.click();
15921     },
15922
15923     // private
15924     handleMouseUp : function(){
15925         clearTimeout(this.timer);
15926         this.el.un("mouseover", this.handleMouseReturn);
15927         this.el.un("mouseout", this.handleMouseOut);
15928         Roo.get(document).un("mouseup", this.handleMouseUp);
15929         this.el.removeClass(this.pressClass);
15930         this.fireEvent("mouseup", this);
15931     }
15932 });/**
15933  * @class Roo.util.Clipboard
15934  * @static
15935  * 
15936  * Clipboard UTILS
15937  * 
15938  **/
15939 Roo.util.Clipboard = {
15940     /**
15941      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15942      * @param {String} text to copy to clipboard
15943      */
15944     write : function(text) {
15945         // navigator clipboard api needs a secure context (https)
15946         if (navigator.clipboard && window.isSecureContext) {
15947             // navigator clipboard api method'
15948             navigator.clipboard.writeText(text);
15949             return ;
15950         } 
15951         // text area method
15952         var ta = document.createElement("textarea");
15953         ta.value = text;
15954         // make the textarea out of viewport
15955         ta.style.position = "fixed";
15956         ta.style.left = "-999999px";
15957         ta.style.top = "-999999px";
15958         document.body.appendChild(ta);
15959         ta.focus();
15960         ta.select();
15961         document.execCommand('copy');
15962         (function() {
15963             ta.remove();
15964         }).defer(100);
15965         
15966     }
15967         
15968 }
15969     /*
15970  * Based on:
15971  * Ext JS Library 1.1.1
15972  * Copyright(c) 2006-2007, Ext JS, LLC.
15973  *
15974  * Originally Released Under LGPL - original licence link has changed is not relivant.
15975  *
15976  * Fork - LGPL
15977  * <script type="text/javascript">
15978  */
15979
15980  
15981 /**
15982  * @class Roo.KeyNav
15983  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15984  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15985  * way to implement custom navigation schemes for any UI component.</p>
15986  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15987  * pageUp, pageDown, del, home, end.  Usage:</p>
15988  <pre><code>
15989 var nav = new Roo.KeyNav("my-element", {
15990     "left" : function(e){
15991         this.moveLeft(e.ctrlKey);
15992     },
15993     "right" : function(e){
15994         this.moveRight(e.ctrlKey);
15995     },
15996     "enter" : function(e){
15997         this.save();
15998     },
15999     scope : this
16000 });
16001 </code></pre>
16002  * @constructor
16003  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16004  * @param {Object} config The config
16005  */
16006 Roo.KeyNav = function(el, config){
16007     this.el = Roo.get(el);
16008     Roo.apply(this, config);
16009     if(!this.disabled){
16010         this.disabled = true;
16011         this.enable();
16012     }
16013 };
16014
16015 Roo.KeyNav.prototype = {
16016     /**
16017      * @cfg {Boolean} disabled
16018      * True to disable this KeyNav instance (defaults to false)
16019      */
16020     disabled : false,
16021     /**
16022      * @cfg {String} defaultEventAction
16023      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
16024      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
16025      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
16026      */
16027     defaultEventAction: "stopEvent",
16028     /**
16029      * @cfg {Boolean} forceKeyDown
16030      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
16031      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16032      * handle keydown instead of keypress.
16033      */
16034     forceKeyDown : false,
16035
16036     // private
16037     prepareEvent : function(e){
16038         var k = e.getKey();
16039         var h = this.keyToHandler[k];
16040         //if(h && this[h]){
16041         //    e.stopPropagation();
16042         //}
16043         if(Roo.isSafari && h && k >= 37 && k <= 40){
16044             e.stopEvent();
16045         }
16046     },
16047
16048     // private
16049     relay : function(e){
16050         var k = e.getKey();
16051         var h = this.keyToHandler[k];
16052         if(h && this[h]){
16053             if(this.doRelay(e, this[h], h) !== true){
16054                 e[this.defaultEventAction]();
16055             }
16056         }
16057     },
16058
16059     // private
16060     doRelay : function(e, h, hname){
16061         return h.call(this.scope || this, e);
16062     },
16063
16064     // possible handlers
16065     enter : false,
16066     left : false,
16067     right : false,
16068     up : false,
16069     down : false,
16070     tab : false,
16071     esc : false,
16072     pageUp : false,
16073     pageDown : false,
16074     del : false,
16075     home : false,
16076     end : false,
16077
16078     // quick lookup hash
16079     keyToHandler : {
16080         37 : "left",
16081         39 : "right",
16082         38 : "up",
16083         40 : "down",
16084         33 : "pageUp",
16085         34 : "pageDown",
16086         46 : "del",
16087         36 : "home",
16088         35 : "end",
16089         13 : "enter",
16090         27 : "esc",
16091         9  : "tab"
16092     },
16093
16094         /**
16095          * Enable this KeyNav
16096          */
16097         enable: function(){
16098                 if(this.disabled){
16099             // ie won't do special keys on keypress, no one else will repeat keys with keydown
16100             // the EventObject will normalize Safari automatically
16101             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16102                 this.el.on("keydown", this.relay,  this);
16103             }else{
16104                 this.el.on("keydown", this.prepareEvent,  this);
16105                 this.el.on("keypress", this.relay,  this);
16106             }
16107                     this.disabled = false;
16108                 }
16109         },
16110
16111         /**
16112          * Disable this KeyNav
16113          */
16114         disable: function(){
16115                 if(!this.disabled){
16116                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16117                 this.el.un("keydown", this.relay);
16118             }else{
16119                 this.el.un("keydown", this.prepareEvent);
16120                 this.el.un("keypress", this.relay);
16121             }
16122                     this.disabled = true;
16123                 }
16124         }
16125 };/*
16126  * Based on:
16127  * Ext JS Library 1.1.1
16128  * Copyright(c) 2006-2007, Ext JS, LLC.
16129  *
16130  * Originally Released Under LGPL - original licence link has changed is not relivant.
16131  *
16132  * Fork - LGPL
16133  * <script type="text/javascript">
16134  */
16135
16136  
16137 /**
16138  * @class Roo.KeyMap
16139  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16140  * The constructor accepts the same config object as defined by {@link #addBinding}.
16141  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16142  * combination it will call the function with this signature (if the match is a multi-key
16143  * combination the callback will still be called only once): (String key, Roo.EventObject e)
16144  * A KeyMap can also handle a string representation of keys.<br />
16145  * Usage:
16146  <pre><code>
16147 // map one key by key code
16148 var map = new Roo.KeyMap("my-element", {
16149     key: 13, // or Roo.EventObject.ENTER
16150     fn: myHandler,
16151     scope: myObject
16152 });
16153
16154 // map multiple keys to one action by string
16155 var map = new Roo.KeyMap("my-element", {
16156     key: "a\r\n\t",
16157     fn: myHandler,
16158     scope: myObject
16159 });
16160
16161 // map multiple keys to multiple actions by strings and array of codes
16162 var map = new Roo.KeyMap("my-element", [
16163     {
16164         key: [10,13],
16165         fn: function(){ alert("Return was pressed"); }
16166     }, {
16167         key: "abc",
16168         fn: function(){ alert('a, b or c was pressed'); }
16169     }, {
16170         key: "\t",
16171         ctrl:true,
16172         shift:true,
16173         fn: function(){ alert('Control + shift + tab was pressed.'); }
16174     }
16175 ]);
16176 </code></pre>
16177  * <b>Note: A KeyMap starts enabled</b>
16178  * @constructor
16179  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16180  * @param {Object} config The config (see {@link #addBinding})
16181  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16182  */
16183 Roo.KeyMap = function(el, config, eventName){
16184     this.el  = Roo.get(el);
16185     this.eventName = eventName || "keydown";
16186     this.bindings = [];
16187     if(config){
16188         this.addBinding(config);
16189     }
16190     this.enable();
16191 };
16192
16193 Roo.KeyMap.prototype = {
16194     /**
16195      * True to stop the event from bubbling and prevent the default browser action if the
16196      * key was handled by the KeyMap (defaults to false)
16197      * @type Boolean
16198      */
16199     stopEvent : false,
16200
16201     /**
16202      * Add a new binding to this KeyMap. The following config object properties are supported:
16203      * <pre>
16204 Property    Type             Description
16205 ----------  ---------------  ----------------------------------------------------------------------
16206 key         String/Array     A single keycode or an array of keycodes to handle
16207 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16208 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16209 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16210 fn          Function         The function to call when KeyMap finds the expected key combination
16211 scope       Object           The scope of the callback function
16212 </pre>
16213      *
16214      * Usage:
16215      * <pre><code>
16216 // Create a KeyMap
16217 var map = new Roo.KeyMap(document, {
16218     key: Roo.EventObject.ENTER,
16219     fn: handleKey,
16220     scope: this
16221 });
16222
16223 //Add a new binding to the existing KeyMap later
16224 map.addBinding({
16225     key: 'abc',
16226     shift: true,
16227     fn: handleKey,
16228     scope: this
16229 });
16230 </code></pre>
16231      * @param {Object/Array} config A single KeyMap config or an array of configs
16232      */
16233         addBinding : function(config){
16234         if(config instanceof Array){
16235             for(var i = 0, len = config.length; i < len; i++){
16236                 this.addBinding(config[i]);
16237             }
16238             return;
16239         }
16240         var keyCode = config.key,
16241             shift = config.shift, 
16242             ctrl = config.ctrl, 
16243             alt = config.alt,
16244             fn = config.fn,
16245             scope = config.scope;
16246         if(typeof keyCode == "string"){
16247             var ks = [];
16248             var keyString = keyCode.toUpperCase();
16249             for(var j = 0, len = keyString.length; j < len; j++){
16250                 ks.push(keyString.charCodeAt(j));
16251             }
16252             keyCode = ks;
16253         }
16254         var keyArray = keyCode instanceof Array;
16255         var handler = function(e){
16256             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16257                 var k = e.getKey();
16258                 if(keyArray){
16259                     for(var i = 0, len = keyCode.length; i < len; i++){
16260                         if(keyCode[i] == k){
16261                           if(this.stopEvent){
16262                               e.stopEvent();
16263                           }
16264                           fn.call(scope || window, k, e);
16265                           return;
16266                         }
16267                     }
16268                 }else{
16269                     if(k == keyCode){
16270                         if(this.stopEvent){
16271                            e.stopEvent();
16272                         }
16273                         fn.call(scope || window, k, e);
16274                     }
16275                 }
16276             }
16277         };
16278         this.bindings.push(handler);  
16279         },
16280
16281     /**
16282      * Shorthand for adding a single key listener
16283      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16284      * following options:
16285      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16286      * @param {Function} fn The function to call
16287      * @param {Object} scope (optional) The scope of the function
16288      */
16289     on : function(key, fn, scope){
16290         var keyCode, shift, ctrl, alt;
16291         if(typeof key == "object" && !(key instanceof Array)){
16292             keyCode = key.key;
16293             shift = key.shift;
16294             ctrl = key.ctrl;
16295             alt = key.alt;
16296         }else{
16297             keyCode = key;
16298         }
16299         this.addBinding({
16300             key: keyCode,
16301             shift: shift,
16302             ctrl: ctrl,
16303             alt: alt,
16304             fn: fn,
16305             scope: scope
16306         })
16307     },
16308
16309     // private
16310     handleKeyDown : function(e){
16311             if(this.enabled){ //just in case
16312             var b = this.bindings;
16313             for(var i = 0, len = b.length; i < len; i++){
16314                 b[i].call(this, e);
16315             }
16316             }
16317         },
16318         
16319         /**
16320          * Returns true if this KeyMap is enabled
16321          * @return {Boolean} 
16322          */
16323         isEnabled : function(){
16324             return this.enabled;  
16325         },
16326         
16327         /**
16328          * Enables this KeyMap
16329          */
16330         enable: function(){
16331                 if(!this.enabled){
16332                     this.el.on(this.eventName, this.handleKeyDown, this);
16333                     this.enabled = true;
16334                 }
16335         },
16336
16337         /**
16338          * Disable this KeyMap
16339          */
16340         disable: function(){
16341                 if(this.enabled){
16342                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16343                     this.enabled = false;
16344                 }
16345         }
16346 };/*
16347  * Based on:
16348  * Ext JS Library 1.1.1
16349  * Copyright(c) 2006-2007, Ext JS, LLC.
16350  *
16351  * Originally Released Under LGPL - original licence link has changed is not relivant.
16352  *
16353  * Fork - LGPL
16354  * <script type="text/javascript">
16355  */
16356
16357  
16358 /**
16359  * @class Roo.util.TextMetrics
16360  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16361  * wide, in pixels, a given block of text will be.
16362  * @static
16363  */
16364 Roo.util.TextMetrics = function(){
16365     var shared;
16366     return {
16367         /**
16368          * Measures the size of the specified text
16369          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16370          * that can affect the size of the rendered text
16371          * @param {String} text The text to measure
16372          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16373          * in order to accurately measure the text height
16374          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16375          */
16376         measure : function(el, text, fixedWidth){
16377             if(!shared){
16378                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16379             }
16380             shared.bind(el);
16381             shared.setFixedWidth(fixedWidth || 'auto');
16382             return shared.getSize(text);
16383         },
16384
16385         /**
16386          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16387          * the overhead of multiple calls to initialize the style properties on each measurement.
16388          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16389          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16390          * in order to accurately measure the text height
16391          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16392          */
16393         createInstance : function(el, fixedWidth){
16394             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16395         }
16396     };
16397 }();
16398
16399 /**
16400  * @class Roo.util.TextMetrics.Instance
16401  * Instance of  TextMetrics Calcuation
16402  * @constructor
16403  * Create a new TextMetrics Instance
16404  * @param {Object} bindto
16405  * @param {Boolean} fixedWidth
16406  */
16407
16408 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16409 {
16410     var ml = new Roo.Element(document.createElement('div'));
16411     document.body.appendChild(ml.dom);
16412     ml.position('absolute');
16413     ml.setLeftTop(-1000, -1000);
16414     ml.hide();
16415
16416     if(fixedWidth){
16417         ml.setWidth(fixedWidth);
16418     }
16419      
16420     var instance = {
16421         /**
16422          * Returns the size of the specified text based on the internal element's style and width properties
16423          * @param {String} text The text to measure
16424          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16425          */
16426         getSize : function(text){
16427             ml.update(text);
16428             var s = ml.getSize();
16429             ml.update('');
16430             return s;
16431         },
16432
16433         /**
16434          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16435          * that can affect the size of the rendered text
16436          * @param {String/HTMLElement} el The element, dom node or id
16437          */
16438         bind : function(el){
16439             ml.setStyle(
16440                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16441             );
16442         },
16443
16444         /**
16445          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16446          * to set a fixed width in order to accurately measure the text height.
16447          * @param {Number} width The width to set on the element
16448          */
16449         setFixedWidth : function(width){
16450             ml.setWidth(width);
16451         },
16452
16453         /**
16454          * Returns the measured width of the specified text
16455          * @param {String} text The text to measure
16456          * @return {Number} width The width in pixels
16457          */
16458         getWidth : function(text){
16459             ml.dom.style.width = 'auto';
16460             return this.getSize(text).width;
16461         },
16462
16463         /**
16464          * Returns the measured height of the specified text.  For multiline text, be sure to call
16465          * {@link #setFixedWidth} if necessary.
16466          * @param {String} text The text to measure
16467          * @return {Number} height The height in pixels
16468          */
16469         getHeight : function(text){
16470             return this.getSize(text).height;
16471         }
16472     };
16473
16474     instance.bind(bindTo);
16475
16476     return instance;
16477 };
16478
16479 // backwards compat
16480 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16481  * Based on:
16482  * Ext JS Library 1.1.1
16483  * Copyright(c) 2006-2007, Ext JS, LLC.
16484  *
16485  * Originally Released Under LGPL - original licence link has changed is not relivant.
16486  *
16487  * Fork - LGPL
16488  * <script type="text/javascript">
16489  */
16490
16491 /**
16492  * @class Roo.state.Provider
16493  * Abstract base class for state provider implementations. This class provides methods
16494  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16495  * Provider interface.
16496  */
16497 Roo.state.Provider = function(){
16498     /**
16499      * @event statechange
16500      * Fires when a state change occurs.
16501      * @param {Provider} this This state provider
16502      * @param {String} key The state key which was changed
16503      * @param {String} value The encoded value for the state
16504      */
16505     this.addEvents({
16506         "statechange": true
16507     });
16508     this.state = {};
16509     Roo.state.Provider.superclass.constructor.call(this);
16510 };
16511 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16512     /**
16513      * Returns the current value for a key
16514      * @param {String} name The key name
16515      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16516      * @return {Mixed} The state data
16517      */
16518     get : function(name, defaultValue){
16519         return typeof this.state[name] == "undefined" ?
16520             defaultValue : this.state[name];
16521     },
16522     
16523     /**
16524      * Clears a value from the state
16525      * @param {String} name The key name
16526      */
16527     clear : function(name){
16528         delete this.state[name];
16529         this.fireEvent("statechange", this, name, null);
16530     },
16531     
16532     /**
16533      * Sets the value for a key
16534      * @param {String} name The key name
16535      * @param {Mixed} value The value to set
16536      */
16537     set : function(name, value){
16538         this.state[name] = value;
16539         this.fireEvent("statechange", this, name, value);
16540     },
16541     
16542     /**
16543      * Decodes a string previously encoded with {@link #encodeValue}.
16544      * @param {String} value The value to decode
16545      * @return {Mixed} The decoded value
16546      */
16547     decodeValue : function(cookie){
16548         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16549         var matches = re.exec(unescape(cookie));
16550         if(!matches || !matches[1]) {
16551             return; // non state cookie
16552         }
16553         var type = matches[1];
16554         var v = matches[2];
16555         switch(type){
16556             case "n":
16557                 return parseFloat(v);
16558             case "d":
16559                 return new Date(Date.parse(v));
16560             case "b":
16561                 return (v == "1");
16562             case "a":
16563                 var all = [];
16564                 var values = v.split("^");
16565                 for(var i = 0, len = values.length; i < len; i++){
16566                     all.push(this.decodeValue(values[i]));
16567                 }
16568                 return all;
16569            case "o":
16570                 var all = {};
16571                 var values = v.split("^");
16572                 for(var i = 0, len = values.length; i < len; i++){
16573                     var kv = values[i].split("=");
16574                     all[kv[0]] = this.decodeValue(kv[1]);
16575                 }
16576                 return all;
16577            default:
16578                 return v;
16579         }
16580     },
16581     
16582     /**
16583      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16584      * @param {Mixed} value The value to encode
16585      * @return {String} The encoded value
16586      */
16587     encodeValue : function(v){
16588         var enc;
16589         if(typeof v == "number"){
16590             enc = "n:" + v;
16591         }else if(typeof v == "boolean"){
16592             enc = "b:" + (v ? "1" : "0");
16593         }else if(v instanceof Date){
16594             enc = "d:" + v.toGMTString();
16595         }else if(v instanceof Array){
16596             var flat = "";
16597             for(var i = 0, len = v.length; i < len; i++){
16598                 flat += this.encodeValue(v[i]);
16599                 if(i != len-1) {
16600                     flat += "^";
16601                 }
16602             }
16603             enc = "a:" + flat;
16604         }else if(typeof v == "object"){
16605             var flat = "";
16606             for(var key in v){
16607                 if(typeof v[key] != "function"){
16608                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16609                 }
16610             }
16611             enc = "o:" + flat.substring(0, flat.length-1);
16612         }else{
16613             enc = "s:" + v;
16614         }
16615         return escape(enc);        
16616     }
16617 });
16618
16619 /*
16620  * Based on:
16621  * Ext JS Library 1.1.1
16622  * Copyright(c) 2006-2007, Ext JS, LLC.
16623  *
16624  * Originally Released Under LGPL - original licence link has changed is not relivant.
16625  *
16626  * Fork - LGPL
16627  * <script type="text/javascript">
16628  */
16629 /**
16630  * @class Roo.state.Manager
16631  * This is the global state manager. By default all components that are "state aware" check this class
16632  * for state information if you don't pass them a custom state provider. In order for this class
16633  * to be useful, it must be initialized with a provider when your application initializes.
16634  <pre><code>
16635 // in your initialization function
16636 init : function(){
16637    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16638    ...
16639    // supposed you have a {@link Roo.layout.Border}
16640    var layout = new Roo.layout.Border(...);
16641    layout.restoreState();
16642    // or a {Roo.BasicDialog}
16643    var dialog = new Roo.BasicDialog(...);
16644    dialog.restoreState();
16645  </code></pre>
16646  * @static
16647  */
16648 Roo.state.Manager = function(){
16649     var provider = new Roo.state.Provider();
16650     
16651     return {
16652         /**
16653          * Configures the default state provider for your application
16654          * @param {Provider} stateProvider The state provider to set
16655          */
16656         setProvider : function(stateProvider){
16657             provider = stateProvider;
16658         },
16659         
16660         /**
16661          * Returns the current value for a key
16662          * @param {String} name The key name
16663          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16664          * @return {Mixed} The state data
16665          */
16666         get : function(key, defaultValue){
16667             return provider.get(key, defaultValue);
16668         },
16669         
16670         /**
16671          * Sets the value for a key
16672          * @param {String} name The key name
16673          * @param {Mixed} value The state data
16674          */
16675          set : function(key, value){
16676             provider.set(key, value);
16677         },
16678         
16679         /**
16680          * Clears a value from the state
16681          * @param {String} name The key name
16682          */
16683         clear : function(key){
16684             provider.clear(key);
16685         },
16686         
16687         /**
16688          * Gets the currently configured state provider
16689          * @return {Provider} The state provider
16690          */
16691         getProvider : function(){
16692             return provider;
16693         }
16694     };
16695 }();
16696 /*
16697  * Based on:
16698  * Ext JS Library 1.1.1
16699  * Copyright(c) 2006-2007, Ext JS, LLC.
16700  *
16701  * Originally Released Under LGPL - original licence link has changed is not relivant.
16702  *
16703  * Fork - LGPL
16704  * <script type="text/javascript">
16705  */
16706 /**
16707  * @class Roo.state.CookieProvider
16708  * @extends Roo.state.Provider
16709  * The default Provider implementation which saves state via cookies.
16710  * <br />Usage:
16711  <pre><code>
16712    var cp = new Roo.state.CookieProvider({
16713        path: "/cgi-bin/",
16714        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16715        domain: "roojs.com"
16716    })
16717    Roo.state.Manager.setProvider(cp);
16718  </code></pre>
16719  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16720  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16721  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16722  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16723  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16724  * domain the page is running on including the 'www' like 'www.roojs.com')
16725  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16726  * @constructor
16727  * Create a new CookieProvider
16728  * @param {Object} config The configuration object
16729  */
16730 Roo.state.CookieProvider = function(config){
16731     Roo.state.CookieProvider.superclass.constructor.call(this);
16732     this.path = "/";
16733     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16734     this.domain = null;
16735     this.secure = false;
16736     Roo.apply(this, config);
16737     this.state = this.readCookies();
16738 };
16739
16740 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16741     // private
16742     set : function(name, value){
16743         if(typeof value == "undefined" || value === null){
16744             this.clear(name);
16745             return;
16746         }
16747         this.setCookie(name, value);
16748         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16749     },
16750
16751     // private
16752     clear : function(name){
16753         this.clearCookie(name);
16754         Roo.state.CookieProvider.superclass.clear.call(this, name);
16755     },
16756
16757     // private
16758     readCookies : function(){
16759         var cookies = {};
16760         var c = document.cookie + ";";
16761         var re = /\s?(.*?)=(.*?);/g;
16762         var matches;
16763         while((matches = re.exec(c)) != null){
16764             var name = matches[1];
16765             var value = matches[2];
16766             if(name && name.substring(0,3) == "ys-"){
16767                 cookies[name.substr(3)] = this.decodeValue(value);
16768             }
16769         }
16770         return cookies;
16771     },
16772
16773     // private
16774     setCookie : function(name, value){
16775         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16776            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16777            ((this.path == null) ? "" : ("; path=" + this.path)) +
16778            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16779            ((this.secure == true) ? "; secure" : "");
16780     },
16781
16782     // private
16783     clearCookie : function(name){
16784         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16785            ((this.path == null) ? "" : ("; path=" + this.path)) +
16786            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16787            ((this.secure == true) ? "; secure" : "");
16788     }
16789 });/*
16790  * Based on:
16791  * Ext JS Library 1.1.1
16792  * Copyright(c) 2006-2007, Ext JS, LLC.
16793  *
16794  * Originally Released Under LGPL - original licence link has changed is not relivant.
16795  *
16796  * Fork - LGPL
16797  * <script type="text/javascript">
16798  */
16799  
16800
16801 /**
16802  * @class Roo.ComponentMgr
16803  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16804  * @static
16805  */
16806 Roo.ComponentMgr = function(){
16807     var all = new Roo.util.MixedCollection();
16808
16809     return {
16810         /**
16811          * Registers a component.
16812          * @param {Roo.Component} c The component
16813          */
16814         register : function(c){
16815             all.add(c);
16816         },
16817
16818         /**
16819          * Unregisters a component.
16820          * @param {Roo.Component} c The component
16821          */
16822         unregister : function(c){
16823             all.remove(c);
16824         },
16825
16826         /**
16827          * Returns a component by id
16828          * @param {String} id The component id
16829          */
16830         get : function(id){
16831             return all.get(id);
16832         },
16833
16834         /**
16835          * Registers a function that will be called when a specified component is added to ComponentMgr
16836          * @param {String} id The component id
16837          * @param {Funtction} fn The callback function
16838          * @param {Object} scope The scope of the callback
16839          */
16840         onAvailable : function(id, fn, scope){
16841             all.on("add", function(index, o){
16842                 if(o.id == id){
16843                     fn.call(scope || o, o);
16844                     all.un("add", fn, scope);
16845                 }
16846             });
16847         }
16848     };
16849 }();/*
16850  * Based on:
16851  * Ext JS Library 1.1.1
16852  * Copyright(c) 2006-2007, Ext JS, LLC.
16853  *
16854  * Originally Released Under LGPL - original licence link has changed is not relivant.
16855  *
16856  * Fork - LGPL
16857  * <script type="text/javascript">
16858  */
16859  
16860 /**
16861  * @class Roo.Component
16862  * @extends Roo.util.Observable
16863  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16864  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16865  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16866  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16867  * All visual components (widgets) that require rendering into a layout should subclass Component.
16868  * @constructor
16869  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16870  * 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
16871  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16872  */
16873 Roo.Component = function(config){
16874     config = config || {};
16875     if(config.tagName || config.dom || typeof config == "string"){ // element object
16876         config = {el: config, id: config.id || config};
16877     }
16878     this.initialConfig = config;
16879
16880     Roo.apply(this, config);
16881     this.addEvents({
16882         /**
16883          * @event disable
16884          * Fires after the component is disabled.
16885              * @param {Roo.Component} this
16886              */
16887         disable : true,
16888         /**
16889          * @event enable
16890          * Fires after the component is enabled.
16891              * @param {Roo.Component} this
16892              */
16893         enable : true,
16894         /**
16895          * @event beforeshow
16896          * Fires before the component is shown.  Return false to stop the show.
16897              * @param {Roo.Component} this
16898              */
16899         beforeshow : true,
16900         /**
16901          * @event show
16902          * Fires after the component is shown.
16903              * @param {Roo.Component} this
16904              */
16905         show : true,
16906         /**
16907          * @event beforehide
16908          * Fires before the component is hidden. Return false to stop the hide.
16909              * @param {Roo.Component} this
16910              */
16911         beforehide : true,
16912         /**
16913          * @event hide
16914          * Fires after the component is hidden.
16915              * @param {Roo.Component} this
16916              */
16917         hide : true,
16918         /**
16919          * @event beforerender
16920          * Fires before the component is rendered. Return false to stop the render.
16921              * @param {Roo.Component} this
16922              */
16923         beforerender : true,
16924         /**
16925          * @event render
16926          * Fires after the component is rendered.
16927              * @param {Roo.Component} this
16928              */
16929         render : true,
16930         /**
16931          * @event beforedestroy
16932          * Fires before the component is destroyed. Return false to stop the destroy.
16933              * @param {Roo.Component} this
16934              */
16935         beforedestroy : true,
16936         /**
16937          * @event destroy
16938          * Fires after the component is destroyed.
16939              * @param {Roo.Component} this
16940              */
16941         destroy : true
16942     });
16943     if(!this.id){
16944         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16945     }
16946     Roo.ComponentMgr.register(this);
16947     Roo.Component.superclass.constructor.call(this);
16948     this.initComponent();
16949     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16950         this.render(this.renderTo);
16951         delete this.renderTo;
16952     }
16953 };
16954
16955 /** @private */
16956 Roo.Component.AUTO_ID = 1000;
16957
16958 Roo.extend(Roo.Component, Roo.util.Observable, {
16959     /**
16960      * @scope Roo.Component.prototype
16961      * @type {Boolean}
16962      * true if this component is hidden. Read-only.
16963      */
16964     hidden : false,
16965     /**
16966      * @type {Boolean}
16967      * true if this component is disabled. Read-only.
16968      */
16969     disabled : false,
16970     /**
16971      * @type {Boolean}
16972      * true if this component has been rendered. Read-only.
16973      */
16974     rendered : false,
16975     
16976     /** @cfg {String} disableClass
16977      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16978      */
16979     disabledClass : "x-item-disabled",
16980         /** @cfg {Boolean} allowDomMove
16981          * Whether the component can move the Dom node when rendering (defaults to true).
16982          */
16983     allowDomMove : true,
16984     /** @cfg {String} hideMode (display|visibility)
16985      * How this component should hidden. Supported values are
16986      * "visibility" (css visibility), "offsets" (negative offset position) and
16987      * "display" (css display) - defaults to "display".
16988      */
16989     hideMode: 'display',
16990
16991     /** @private */
16992     ctype : "Roo.Component",
16993
16994     /**
16995      * @cfg {String} actionMode 
16996      * which property holds the element that used for  hide() / show() / disable() / enable()
16997      * default is 'el' for forms you probably want to set this to fieldEl 
16998      */
16999     actionMode : "el",
17000
17001          /**
17002      * @cfg {String} style
17003      * css styles to add to component
17004      * eg. text-align:right;
17005      */
17006     style : false,
17007         
17008     /** @private */
17009     getActionEl : function(){
17010         return this[this.actionMode];
17011     },
17012
17013     initComponent : Roo.emptyFn,
17014     /**
17015      * If this is a lazy rendering component, render it to its container element.
17016      * @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.
17017      */
17018     render : function(container, position){
17019         
17020         if(this.rendered){
17021             return this;
17022         }
17023         
17024         if(this.fireEvent("beforerender", this) === false){
17025             return false;
17026         }
17027         
17028         if(!container && this.el){
17029             this.el = Roo.get(this.el);
17030             container = this.el.dom.parentNode;
17031             this.allowDomMove = false;
17032         }
17033         this.container = Roo.get(container);
17034         this.rendered = true;
17035         if(position !== undefined){
17036             if(typeof position == 'number'){
17037                 position = this.container.dom.childNodes[position];
17038             }else{
17039                 position = Roo.getDom(position);
17040             }
17041         }
17042         this.onRender(this.container, position || null);
17043         if(this.cls){
17044             this.el.addClass(this.cls);
17045             delete this.cls;
17046         }
17047         if(this.style){
17048             this.el.applyStyles(this.style);
17049             delete this.style;
17050         }
17051         this.fireEvent("render", this);
17052         this.afterRender(this.container);
17053         if(this.hidden){
17054             this.hide();
17055         }
17056         if(this.disabled){
17057             this.disable();
17058         }
17059
17060         return this;
17061         
17062     },
17063
17064     /** @private */
17065     // default function is not really useful
17066     onRender : function(ct, position){
17067         if(this.el){
17068             this.el = Roo.get(this.el);
17069             if(this.allowDomMove !== false){
17070                 ct.dom.insertBefore(this.el.dom, position);
17071             }
17072         }
17073     },
17074
17075     /** @private */
17076     getAutoCreate : function(){
17077         var cfg = typeof this.autoCreate == "object" ?
17078                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17079         if(this.id && !cfg.id){
17080             cfg.id = this.id;
17081         }
17082         return cfg;
17083     },
17084
17085     /** @private */
17086     afterRender : Roo.emptyFn,
17087
17088     /**
17089      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17090      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17091      */
17092     destroy : function(){
17093         if(this.fireEvent("beforedestroy", this) !== false){
17094             this.purgeListeners();
17095             this.beforeDestroy();
17096             if(this.rendered){
17097                 this.el.removeAllListeners();
17098                 this.el.remove();
17099                 if(this.actionMode == "container"){
17100                     this.container.remove();
17101                 }
17102             }
17103             this.onDestroy();
17104             Roo.ComponentMgr.unregister(this);
17105             this.fireEvent("destroy", this);
17106         }
17107     },
17108
17109         /** @private */
17110     beforeDestroy : function(){
17111
17112     },
17113
17114         /** @private */
17115         onDestroy : function(){
17116
17117     },
17118
17119     /**
17120      * Returns the underlying {@link Roo.Element}.
17121      * @return {Roo.Element} The element
17122      */
17123     getEl : function(){
17124         return this.el;
17125     },
17126
17127     /**
17128      * Returns the id of this component.
17129      * @return {String}
17130      */
17131     getId : function(){
17132         return this.id;
17133     },
17134
17135     /**
17136      * Try to focus this component.
17137      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17138      * @return {Roo.Component} this
17139      */
17140     focus : function(selectText){
17141         if(this.rendered){
17142             this.el.focus();
17143             if(selectText === true){
17144                 this.el.dom.select();
17145             }
17146         }
17147         return this;
17148     },
17149
17150     /** @private */
17151     blur : function(){
17152         if(this.rendered){
17153             this.el.blur();
17154         }
17155         return this;
17156     },
17157
17158     /**
17159      * Disable this component.
17160      * @return {Roo.Component} this
17161      */
17162     disable : function(){
17163         if(this.rendered){
17164             this.onDisable();
17165         }
17166         this.disabled = true;
17167         this.fireEvent("disable", this);
17168         return this;
17169     },
17170
17171         // private
17172     onDisable : function(){
17173         this.getActionEl().addClass(this.disabledClass);
17174         this.el.dom.disabled = true;
17175     },
17176
17177     /**
17178      * Enable this component.
17179      * @return {Roo.Component} this
17180      */
17181     enable : function(){
17182         if(this.rendered){
17183             this.onEnable();
17184         }
17185         this.disabled = false;
17186         this.fireEvent("enable", this);
17187         return this;
17188     },
17189
17190         // private
17191     onEnable : function(){
17192         this.getActionEl().removeClass(this.disabledClass);
17193         this.el.dom.disabled = false;
17194     },
17195
17196     /**
17197      * Convenience function for setting disabled/enabled by boolean.
17198      * @param {Boolean} disabled
17199      */
17200     setDisabled : function(disabled){
17201         this[disabled ? "disable" : "enable"]();
17202     },
17203
17204     /**
17205      * Show this component.
17206      * @return {Roo.Component} this
17207      */
17208     show: function(){
17209         if(this.fireEvent("beforeshow", this) !== false){
17210             this.hidden = false;
17211             if(this.rendered){
17212                 this.onShow();
17213             }
17214             this.fireEvent("show", this);
17215         }
17216         return this;
17217     },
17218
17219     // private
17220     onShow : function(){
17221         var ae = this.getActionEl();
17222         if(this.hideMode == 'visibility'){
17223             ae.dom.style.visibility = "visible";
17224         }else if(this.hideMode == 'offsets'){
17225             ae.removeClass('x-hidden');
17226         }else{
17227             ae.dom.style.display = "";
17228         }
17229     },
17230
17231     /**
17232      * Hide this component.
17233      * @return {Roo.Component} this
17234      */
17235     hide: function(){
17236         if(this.fireEvent("beforehide", this) !== false){
17237             this.hidden = true;
17238             if(this.rendered){
17239                 this.onHide();
17240             }
17241             this.fireEvent("hide", this);
17242         }
17243         return this;
17244     },
17245
17246     // private
17247     onHide : function(){
17248         var ae = this.getActionEl();
17249         if(this.hideMode == 'visibility'){
17250             ae.dom.style.visibility = "hidden";
17251         }else if(this.hideMode == 'offsets'){
17252             ae.addClass('x-hidden');
17253         }else{
17254             ae.dom.style.display = "none";
17255         }
17256     },
17257
17258     /**
17259      * Convenience function to hide or show this component by boolean.
17260      * @param {Boolean} visible True to show, false to hide
17261      * @return {Roo.Component} this
17262      */
17263     setVisible: function(visible){
17264         if(visible) {
17265             this.show();
17266         }else{
17267             this.hide();
17268         }
17269         return this;
17270     },
17271
17272     /**
17273      * Returns true if this component is visible.
17274      */
17275     isVisible : function(){
17276         return this.getActionEl().isVisible();
17277     },
17278
17279     cloneConfig : function(overrides){
17280         overrides = overrides || {};
17281         var id = overrides.id || Roo.id();
17282         var cfg = Roo.applyIf(overrides, this.initialConfig);
17283         cfg.id = id; // prevent dup id
17284         return new this.constructor(cfg);
17285     }
17286 });/*
17287  * Based on:
17288  * Ext JS Library 1.1.1
17289  * Copyright(c) 2006-2007, Ext JS, LLC.
17290  *
17291  * Originally Released Under LGPL - original licence link has changed is not relivant.
17292  *
17293  * Fork - LGPL
17294  * <script type="text/javascript">
17295  */
17296
17297 /**
17298  * @class Roo.BoxComponent
17299  * @extends Roo.Component
17300  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17301  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17302  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17303  * layout containers.
17304  * @constructor
17305  * @param {Roo.Element/String/Object} config The configuration options.
17306  */
17307 Roo.BoxComponent = function(config){
17308     Roo.Component.call(this, config);
17309     this.addEvents({
17310         /**
17311          * @event resize
17312          * Fires after the component is resized.
17313              * @param {Roo.Component} this
17314              * @param {Number} adjWidth The box-adjusted width that was set
17315              * @param {Number} adjHeight The box-adjusted height that was set
17316              * @param {Number} rawWidth The width that was originally specified
17317              * @param {Number} rawHeight The height that was originally specified
17318              */
17319         resize : true,
17320         /**
17321          * @event move
17322          * Fires after the component is moved.
17323              * @param {Roo.Component} this
17324              * @param {Number} x The new x position
17325              * @param {Number} y The new y position
17326              */
17327         move : true
17328     });
17329 };
17330
17331 Roo.extend(Roo.BoxComponent, Roo.Component, {
17332     // private, set in afterRender to signify that the component has been rendered
17333     boxReady : false,
17334     // private, used to defer height settings to subclasses
17335     deferHeight: false,
17336     /** @cfg {Number} width
17337      * width (optional) size of component
17338      */
17339      /** @cfg {Number} height
17340      * height (optional) size of component
17341      */
17342      
17343     /**
17344      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17345      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17346      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17347      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17348      * @return {Roo.BoxComponent} this
17349      */
17350     setSize : function(w, h){
17351         // support for standard size objects
17352         if(typeof w == 'object'){
17353             h = w.height;
17354             w = w.width;
17355         }
17356         // not rendered
17357         if(!this.boxReady){
17358             this.width = w;
17359             this.height = h;
17360             return this;
17361         }
17362
17363         // prevent recalcs when not needed
17364         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17365             return this;
17366         }
17367         this.lastSize = {width: w, height: h};
17368
17369         var adj = this.adjustSize(w, h);
17370         var aw = adj.width, ah = adj.height;
17371         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17372             var rz = this.getResizeEl();
17373             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17374                 rz.setSize(aw, ah);
17375             }else if(!this.deferHeight && ah !== undefined){
17376                 rz.setHeight(ah);
17377             }else if(aw !== undefined){
17378                 rz.setWidth(aw);
17379             }
17380             this.onResize(aw, ah, w, h);
17381             this.fireEvent('resize', this, aw, ah, w, h);
17382         }
17383         return this;
17384     },
17385
17386     /**
17387      * Gets the current size of the component's underlying element.
17388      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17389      */
17390     getSize : function(){
17391         return this.el.getSize();
17392     },
17393
17394     /**
17395      * Gets the current XY position of the component's underlying element.
17396      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17397      * @return {Array} The XY position of the element (e.g., [100, 200])
17398      */
17399     getPosition : function(local){
17400         if(local === true){
17401             return [this.el.getLeft(true), this.el.getTop(true)];
17402         }
17403         return this.xy || this.el.getXY();
17404     },
17405
17406     /**
17407      * Gets the current box measurements of the component's underlying element.
17408      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17409      * @returns {Object} box An object in the format {x, y, width, height}
17410      */
17411     getBox : function(local){
17412         var s = this.el.getSize();
17413         if(local){
17414             s.x = this.el.getLeft(true);
17415             s.y = this.el.getTop(true);
17416         }else{
17417             var xy = this.xy || this.el.getXY();
17418             s.x = xy[0];
17419             s.y = xy[1];
17420         }
17421         return s;
17422     },
17423
17424     /**
17425      * Sets the current box measurements of the component's underlying element.
17426      * @param {Object} box An object in the format {x, y, width, height}
17427      * @returns {Roo.BoxComponent} this
17428      */
17429     updateBox : function(box){
17430         this.setSize(box.width, box.height);
17431         this.setPagePosition(box.x, box.y);
17432         return this;
17433     },
17434
17435     // protected
17436     getResizeEl : function(){
17437         return this.resizeEl || this.el;
17438     },
17439
17440     // protected
17441     getPositionEl : function(){
17442         return this.positionEl || this.el;
17443     },
17444
17445     /**
17446      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17447      * This method fires the move event.
17448      * @param {Number} left The new left
17449      * @param {Number} top The new top
17450      * @returns {Roo.BoxComponent} this
17451      */
17452     setPosition : function(x, y){
17453         this.x = x;
17454         this.y = y;
17455         if(!this.boxReady){
17456             return this;
17457         }
17458         var adj = this.adjustPosition(x, y);
17459         var ax = adj.x, ay = adj.y;
17460
17461         var el = this.getPositionEl();
17462         if(ax !== undefined || ay !== undefined){
17463             if(ax !== undefined && ay !== undefined){
17464                 el.setLeftTop(ax, ay);
17465             }else if(ax !== undefined){
17466                 el.setLeft(ax);
17467             }else if(ay !== undefined){
17468                 el.setTop(ay);
17469             }
17470             this.onPosition(ax, ay);
17471             this.fireEvent('move', this, ax, ay);
17472         }
17473         return this;
17474     },
17475
17476     /**
17477      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17478      * This method fires the move event.
17479      * @param {Number} x The new x position
17480      * @param {Number} y The new y position
17481      * @returns {Roo.BoxComponent} this
17482      */
17483     setPagePosition : function(x, y){
17484         this.pageX = x;
17485         this.pageY = y;
17486         if(!this.boxReady){
17487             return;
17488         }
17489         if(x === undefined || y === undefined){ // cannot translate undefined points
17490             return;
17491         }
17492         var p = this.el.translatePoints(x, y);
17493         this.setPosition(p.left, p.top);
17494         return this;
17495     },
17496
17497     // private
17498     onRender : function(ct, position){
17499         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17500         if(this.resizeEl){
17501             this.resizeEl = Roo.get(this.resizeEl);
17502         }
17503         if(this.positionEl){
17504             this.positionEl = Roo.get(this.positionEl);
17505         }
17506     },
17507
17508     // private
17509     afterRender : function(){
17510         Roo.BoxComponent.superclass.afterRender.call(this);
17511         this.boxReady = true;
17512         this.setSize(this.width, this.height);
17513         if(this.x || this.y){
17514             this.setPosition(this.x, this.y);
17515         }
17516         if(this.pageX || this.pageY){
17517             this.setPagePosition(this.pageX, this.pageY);
17518         }
17519     },
17520
17521     /**
17522      * Force the component's size to recalculate based on the underlying element's current height and width.
17523      * @returns {Roo.BoxComponent} this
17524      */
17525     syncSize : function(){
17526         delete this.lastSize;
17527         this.setSize(this.el.getWidth(), this.el.getHeight());
17528         return this;
17529     },
17530
17531     /**
17532      * Called after the component is resized, this method is empty by default but can be implemented by any
17533      * subclass that needs to perform custom logic after a resize occurs.
17534      * @param {Number} adjWidth The box-adjusted width that was set
17535      * @param {Number} adjHeight The box-adjusted height that was set
17536      * @param {Number} rawWidth The width that was originally specified
17537      * @param {Number} rawHeight The height that was originally specified
17538      */
17539     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17540
17541     },
17542
17543     /**
17544      * Called after the component is moved, this method is empty by default but can be implemented by any
17545      * subclass that needs to perform custom logic after a move occurs.
17546      * @param {Number} x The new x position
17547      * @param {Number} y The new y position
17548      */
17549     onPosition : function(x, y){
17550
17551     },
17552
17553     // private
17554     adjustSize : function(w, h){
17555         if(this.autoWidth){
17556             w = 'auto';
17557         }
17558         if(this.autoHeight){
17559             h = 'auto';
17560         }
17561         return {width : w, height: h};
17562     },
17563
17564     // private
17565     adjustPosition : function(x, y){
17566         return {x : x, y: y};
17567     }
17568 });/*
17569  * Based on:
17570  * Ext JS Library 1.1.1
17571  * Copyright(c) 2006-2007, Ext JS, LLC.
17572  *
17573  * Originally Released Under LGPL - original licence link has changed is not relivant.
17574  *
17575  * Fork - LGPL
17576  * <script type="text/javascript">
17577  */
17578  (function(){ 
17579 /**
17580  * @class Roo.Layer
17581  * @extends Roo.Element
17582  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17583  * automatic maintaining of shadow/shim positions.
17584  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17585  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17586  * you can pass a string with a CSS class name. False turns off the shadow.
17587  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17588  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17589  * @cfg {String} cls CSS class to add to the element
17590  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17591  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17592  * @constructor
17593  * @param {Object} config An object with config options.
17594  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17595  */
17596
17597 Roo.Layer = function(config, existingEl){
17598     config = config || {};
17599     var dh = Roo.DomHelper;
17600     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17601     if(existingEl){
17602         this.dom = Roo.getDom(existingEl);
17603     }
17604     if(!this.dom){
17605         var o = config.dh || {tag: "div", cls: "x-layer"};
17606         this.dom = dh.append(pel, o);
17607     }
17608     if(config.cls){
17609         this.addClass(config.cls);
17610     }
17611     this.constrain = config.constrain !== false;
17612     this.visibilityMode = Roo.Element.VISIBILITY;
17613     if(config.id){
17614         this.id = this.dom.id = config.id;
17615     }else{
17616         this.id = Roo.id(this.dom);
17617     }
17618     this.zindex = config.zindex || this.getZIndex();
17619     this.position("absolute", this.zindex);
17620     if(config.shadow){
17621         this.shadowOffset = config.shadowOffset || 4;
17622         this.shadow = new Roo.Shadow({
17623             offset : this.shadowOffset,
17624             mode : config.shadow
17625         });
17626     }else{
17627         this.shadowOffset = 0;
17628     }
17629     this.useShim = config.shim !== false && Roo.useShims;
17630     this.useDisplay = config.useDisplay;
17631     this.hide();
17632 };
17633
17634 var supr = Roo.Element.prototype;
17635
17636 // shims are shared among layer to keep from having 100 iframes
17637 var shims = [];
17638
17639 Roo.extend(Roo.Layer, Roo.Element, {
17640
17641     getZIndex : function(){
17642         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17643     },
17644
17645     getShim : function(){
17646         if(!this.useShim){
17647             return null;
17648         }
17649         if(this.shim){
17650             return this.shim;
17651         }
17652         var shim = shims.shift();
17653         if(!shim){
17654             shim = this.createShim();
17655             shim.enableDisplayMode('block');
17656             shim.dom.style.display = 'none';
17657             shim.dom.style.visibility = 'visible';
17658         }
17659         var pn = this.dom.parentNode;
17660         if(shim.dom.parentNode != pn){
17661             pn.insertBefore(shim.dom, this.dom);
17662         }
17663         shim.setStyle('z-index', this.getZIndex()-2);
17664         this.shim = shim;
17665         return shim;
17666     },
17667
17668     hideShim : function(){
17669         if(this.shim){
17670             this.shim.setDisplayed(false);
17671             shims.push(this.shim);
17672             delete this.shim;
17673         }
17674     },
17675
17676     disableShadow : function(){
17677         if(this.shadow){
17678             this.shadowDisabled = true;
17679             this.shadow.hide();
17680             this.lastShadowOffset = this.shadowOffset;
17681             this.shadowOffset = 0;
17682         }
17683     },
17684
17685     enableShadow : function(show){
17686         if(this.shadow){
17687             this.shadowDisabled = false;
17688             this.shadowOffset = this.lastShadowOffset;
17689             delete this.lastShadowOffset;
17690             if(show){
17691                 this.sync(true);
17692             }
17693         }
17694     },
17695
17696     // private
17697     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17698     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17699     sync : function(doShow){
17700         var sw = this.shadow;
17701         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17702             var sh = this.getShim();
17703
17704             var w = this.getWidth(),
17705                 h = this.getHeight();
17706
17707             var l = this.getLeft(true),
17708                 t = this.getTop(true);
17709
17710             if(sw && !this.shadowDisabled){
17711                 if(doShow && !sw.isVisible()){
17712                     sw.show(this);
17713                 }else{
17714                     sw.realign(l, t, w, h);
17715                 }
17716                 if(sh){
17717                     if(doShow){
17718                        sh.show();
17719                     }
17720                     // fit the shim behind the shadow, so it is shimmed too
17721                     var a = sw.adjusts, s = sh.dom.style;
17722                     s.left = (Math.min(l, l+a.l))+"px";
17723                     s.top = (Math.min(t, t+a.t))+"px";
17724                     s.width = (w+a.w)+"px";
17725                     s.height = (h+a.h)+"px";
17726                 }
17727             }else if(sh){
17728                 if(doShow){
17729                    sh.show();
17730                 }
17731                 sh.setSize(w, h);
17732                 sh.setLeftTop(l, t);
17733             }
17734             
17735         }
17736     },
17737
17738     // private
17739     destroy : function(){
17740         this.hideShim();
17741         if(this.shadow){
17742             this.shadow.hide();
17743         }
17744         this.removeAllListeners();
17745         var pn = this.dom.parentNode;
17746         if(pn){
17747             pn.removeChild(this.dom);
17748         }
17749         Roo.Element.uncache(this.id);
17750     },
17751
17752     remove : function(){
17753         this.destroy();
17754     },
17755
17756     // private
17757     beginUpdate : function(){
17758         this.updating = true;
17759     },
17760
17761     // private
17762     endUpdate : function(){
17763         this.updating = false;
17764         this.sync(true);
17765     },
17766
17767     // private
17768     hideUnders : function(negOffset){
17769         if(this.shadow){
17770             this.shadow.hide();
17771         }
17772         this.hideShim();
17773     },
17774
17775     // private
17776     constrainXY : function(){
17777         if(this.constrain){
17778             var vw = Roo.lib.Dom.getViewWidth(),
17779                 vh = Roo.lib.Dom.getViewHeight();
17780             var s = Roo.get(document).getScroll();
17781
17782             var xy = this.getXY();
17783             var x = xy[0], y = xy[1];   
17784             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17785             // only move it if it needs it
17786             var moved = false;
17787             // first validate right/bottom
17788             if((x + w) > vw+s.left){
17789                 x = vw - w - this.shadowOffset;
17790                 moved = true;
17791             }
17792             if((y + h) > vh+s.top){
17793                 y = vh - h - this.shadowOffset;
17794                 moved = true;
17795             }
17796             // then make sure top/left isn't negative
17797             if(x < s.left){
17798                 x = s.left;
17799                 moved = true;
17800             }
17801             if(y < s.top){
17802                 y = s.top;
17803                 moved = true;
17804             }
17805             if(moved){
17806                 if(this.avoidY){
17807                     var ay = this.avoidY;
17808                     if(y <= ay && (y+h) >= ay){
17809                         y = ay-h-5;   
17810                     }
17811                 }
17812                 xy = [x, y];
17813                 this.storeXY(xy);
17814                 supr.setXY.call(this, xy);
17815                 this.sync();
17816             }
17817         }
17818     },
17819
17820     isVisible : function(){
17821         return this.visible;    
17822     },
17823
17824     // private
17825     showAction : function(){
17826         this.visible = true; // track visibility to prevent getStyle calls
17827         if(this.useDisplay === true){
17828             this.setDisplayed("");
17829         }else if(this.lastXY){
17830             supr.setXY.call(this, this.lastXY);
17831         }else if(this.lastLT){
17832             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17833         }
17834     },
17835
17836     // private
17837     hideAction : function(){
17838         this.visible = false;
17839         if(this.useDisplay === true){
17840             this.setDisplayed(false);
17841         }else{
17842             this.setLeftTop(-10000,-10000);
17843         }
17844     },
17845
17846     // overridden Element method
17847     setVisible : function(v, a, d, c, e){
17848         if(v){
17849             this.showAction();
17850         }
17851         if(a && v){
17852             var cb = function(){
17853                 this.sync(true);
17854                 if(c){
17855                     c();
17856                 }
17857             }.createDelegate(this);
17858             supr.setVisible.call(this, true, true, d, cb, e);
17859         }else{
17860             if(!v){
17861                 this.hideUnders(true);
17862             }
17863             var cb = c;
17864             if(a){
17865                 cb = function(){
17866                     this.hideAction();
17867                     if(c){
17868                         c();
17869                     }
17870                 }.createDelegate(this);
17871             }
17872             supr.setVisible.call(this, v, a, d, cb, e);
17873             if(v){
17874                 this.sync(true);
17875             }else if(!a){
17876                 this.hideAction();
17877             }
17878         }
17879     },
17880
17881     storeXY : function(xy){
17882         delete this.lastLT;
17883         this.lastXY = xy;
17884     },
17885
17886     storeLeftTop : function(left, top){
17887         delete this.lastXY;
17888         this.lastLT = [left, top];
17889     },
17890
17891     // private
17892     beforeFx : function(){
17893         this.beforeAction();
17894         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17895     },
17896
17897     // private
17898     afterFx : function(){
17899         Roo.Layer.superclass.afterFx.apply(this, arguments);
17900         this.sync(this.isVisible());
17901     },
17902
17903     // private
17904     beforeAction : function(){
17905         if(!this.updating && this.shadow){
17906             this.shadow.hide();
17907         }
17908     },
17909
17910     // overridden Element method
17911     setLeft : function(left){
17912         this.storeLeftTop(left, this.getTop(true));
17913         supr.setLeft.apply(this, arguments);
17914         this.sync();
17915     },
17916
17917     setTop : function(top){
17918         this.storeLeftTop(this.getLeft(true), top);
17919         supr.setTop.apply(this, arguments);
17920         this.sync();
17921     },
17922
17923     setLeftTop : function(left, top){
17924         this.storeLeftTop(left, top);
17925         supr.setLeftTop.apply(this, arguments);
17926         this.sync();
17927     },
17928
17929     setXY : function(xy, a, d, c, e){
17930         this.fixDisplay();
17931         this.beforeAction();
17932         this.storeXY(xy);
17933         var cb = this.createCB(c);
17934         supr.setXY.call(this, xy, a, d, cb, e);
17935         if(!a){
17936             cb();
17937         }
17938     },
17939
17940     // private
17941     createCB : function(c){
17942         var el = this;
17943         return function(){
17944             el.constrainXY();
17945             el.sync(true);
17946             if(c){
17947                 c();
17948             }
17949         };
17950     },
17951
17952     // overridden Element method
17953     setX : function(x, a, d, c, e){
17954         this.setXY([x, this.getY()], a, d, c, e);
17955     },
17956
17957     // overridden Element method
17958     setY : function(y, a, d, c, e){
17959         this.setXY([this.getX(), y], a, d, c, e);
17960     },
17961
17962     // overridden Element method
17963     setSize : function(w, h, a, d, c, e){
17964         this.beforeAction();
17965         var cb = this.createCB(c);
17966         supr.setSize.call(this, w, h, a, d, cb, e);
17967         if(!a){
17968             cb();
17969         }
17970     },
17971
17972     // overridden Element method
17973     setWidth : function(w, a, d, c, e){
17974         this.beforeAction();
17975         var cb = this.createCB(c);
17976         supr.setWidth.call(this, w, a, d, cb, e);
17977         if(!a){
17978             cb();
17979         }
17980     },
17981
17982     // overridden Element method
17983     setHeight : function(h, a, d, c, e){
17984         this.beforeAction();
17985         var cb = this.createCB(c);
17986         supr.setHeight.call(this, h, a, d, cb, e);
17987         if(!a){
17988             cb();
17989         }
17990     },
17991
17992     // overridden Element method
17993     setBounds : function(x, y, w, h, a, d, c, e){
17994         this.beforeAction();
17995         var cb = this.createCB(c);
17996         if(!a){
17997             this.storeXY([x, y]);
17998             supr.setXY.call(this, [x, y]);
17999             supr.setSize.call(this, w, h, a, d, cb, e);
18000             cb();
18001         }else{
18002             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
18003         }
18004         return this;
18005     },
18006     
18007     /**
18008      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
18009      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
18010      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18011      * @param {Number} zindex The new z-index to set
18012      * @return {this} The Layer
18013      */
18014     setZIndex : function(zindex){
18015         this.zindex = zindex;
18016         this.setStyle("z-index", zindex + 2);
18017         if(this.shadow){
18018             this.shadow.setZIndex(zindex + 1);
18019         }
18020         if(this.shim){
18021             this.shim.setStyle("z-index", zindex);
18022         }
18023     }
18024 });
18025 })();/*
18026  * Original code for Roojs - LGPL
18027  * <script type="text/javascript">
18028  */
18029  
18030 /**
18031  * @class Roo.XComponent
18032  * A delayed Element creator...
18033  * Or a way to group chunks of interface together.
18034  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18035  *  used in conjunction with XComponent.build() it will create an instance of each element,
18036  *  then call addxtype() to build the User interface.
18037  * 
18038  * Mypart.xyx = new Roo.XComponent({
18039
18040     parent : 'Mypart.xyz', // empty == document.element.!!
18041     order : '001',
18042     name : 'xxxx'
18043     region : 'xxxx'
18044     disabled : function() {} 
18045      
18046     tree : function() { // return an tree of xtype declared components
18047         var MODULE = this;
18048         return 
18049         {
18050             xtype : 'NestedLayoutPanel',
18051             // technicall
18052         }
18053      ]
18054  *})
18055  *
18056  *
18057  * It can be used to build a big heiracy, with parent etc.
18058  * or you can just use this to render a single compoent to a dom element
18059  * MYPART.render(Roo.Element | String(id) | dom_element )
18060  *
18061  *
18062  * Usage patterns.
18063  *
18064  * Classic Roo
18065  *
18066  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18067  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18068  *
18069  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18070  *
18071  * When the top level is false, a 'Roo.layout.Border' is created and the element is flagged as 'topModule'
18072  * - if mulitple topModules exist, the last one is defined as the top module.
18073  *
18074  * Embeded Roo
18075  * 
18076  * When the top level or multiple modules are to embedded into a existing HTML page,
18077  * the parent element can container '#id' of the element where the module will be drawn.
18078  *
18079  * Bootstrap Roo
18080  *
18081  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18082  * it relies more on a include mechanism, where sub modules are included into an outer page.
18083  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18084  * 
18085  * Bootstrap Roo Included elements
18086  *
18087  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18088  * hence confusing the component builder as it thinks there are multiple top level elements. 
18089  *
18090  * String Over-ride & Translations
18091  *
18092  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18093  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18094  * are needed. @see Roo.XComponent.overlayString  
18095  * 
18096  * 
18097  * 
18098  * @extends Roo.util.Observable
18099  * @constructor
18100  * @param cfg {Object} configuration of component
18101  * 
18102  */
18103 Roo.XComponent = function(cfg) {
18104     Roo.apply(this, cfg);
18105     this.addEvents({ 
18106         /**
18107              * @event built
18108              * Fires when this the componnt is built
18109              * @param {Roo.XComponent} c the component
18110              */
18111         'built' : true
18112         
18113     });
18114     this.region = this.region || 'center'; // default..
18115     Roo.XComponent.register(this);
18116     this.modules = false;
18117     this.el = false; // where the layout goes..
18118     
18119     
18120 }
18121 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18122     /**
18123      * @property el
18124      * The created element (with Roo.factory())
18125      * @type {Roo.Layout}
18126      */
18127     el  : false,
18128     
18129     /**
18130      * @property el
18131      * for BC  - use el in new code
18132      * @type {Roo.Layout}
18133      */
18134     panel : false,
18135     
18136     /**
18137      * @property layout
18138      * for BC  - use el in new code
18139      * @type {Roo.Layout}
18140      */
18141     layout : false,
18142     
18143      /**
18144      * @cfg {Function|boolean} disabled
18145      * If this module is disabled by some rule, return true from the funtion
18146      */
18147     disabled : false,
18148     
18149     /**
18150      * @cfg {String} parent 
18151      * Name of parent element which it get xtype added to..
18152      */
18153     parent: false,
18154     
18155     /**
18156      * @cfg {String} order
18157      * Used to set the order in which elements are created (usefull for multiple tabs)
18158      */
18159     
18160     order : false,
18161     /**
18162      * @cfg {String} name
18163      * String to display while loading.
18164      */
18165     name : false,
18166     /**
18167      * @cfg {String} region
18168      * Region to render component to (defaults to center)
18169      */
18170     region : 'center',
18171     
18172     /**
18173      * @cfg {Array} items
18174      * A single item array - the first element is the root of the tree..
18175      * It's done this way to stay compatible with the Xtype system...
18176      */
18177     items : false,
18178     
18179     /**
18180      * @property _tree
18181      * The method that retuns the tree of parts that make up this compoennt 
18182      * @type {function}
18183      */
18184     _tree  : false,
18185     
18186      /**
18187      * render
18188      * render element to dom or tree
18189      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18190      */
18191     
18192     render : function(el)
18193     {
18194         
18195         el = el || false;
18196         var hp = this.parent ? 1 : 0;
18197         Roo.debug &&  Roo.log(this);
18198         
18199         var tree = this._tree ? this._tree() : this.tree();
18200
18201         
18202         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18203             // if parent is a '#.....' string, then let's use that..
18204             var ename = this.parent.substr(1);
18205             this.parent = false;
18206             Roo.debug && Roo.log(ename);
18207             switch (ename) {
18208                 case 'bootstrap-body':
18209                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18210                         // this is the BorderLayout standard?
18211                        this.parent = { el : true };
18212                        break;
18213                     }
18214                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18215                         // need to insert stuff...
18216                         this.parent =  {
18217                              el : new Roo.bootstrap.layout.Border({
18218                                  el : document.body, 
18219                      
18220                                  center: {
18221                                     titlebar: false,
18222                                     autoScroll:false,
18223                                     closeOnTab: true,
18224                                     tabPosition: 'top',
18225                                       //resizeTabs: true,
18226                                     alwaysShowTabs: true,
18227                                     hideTabs: false
18228                                      //minTabWidth: 140
18229                                  }
18230                              })
18231                         
18232                          };
18233                          break;
18234                     }
18235                          
18236                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18237                         this.parent = { el :  new  Roo.bootstrap.Body() };
18238                         Roo.debug && Roo.log("setting el to doc body");
18239                          
18240                     } else {
18241                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18242                     }
18243                     break;
18244                 case 'bootstrap':
18245                     this.parent = { el : true};
18246                     // fall through
18247                 default:
18248                     el = Roo.get(ename);
18249                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18250                         this.parent = { el : true};
18251                     }
18252                     
18253                     break;
18254             }
18255                 
18256             
18257             if (!el && !this.parent) {
18258                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18259                 return;
18260             }
18261         }
18262         
18263         Roo.debug && Roo.log("EL:");
18264         Roo.debug && Roo.log(el);
18265         Roo.debug && Roo.log("this.parent.el:");
18266         Roo.debug && Roo.log(this.parent.el);
18267         
18268
18269         // altertive root elements ??? - we need a better way to indicate these.
18270         var is_alt = Roo.XComponent.is_alt ||
18271                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18272                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18273                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18274         
18275         
18276         
18277         if (!this.parent && is_alt) {
18278             //el = Roo.get(document.body);
18279             this.parent = { el : true };
18280         }
18281             
18282             
18283         
18284         if (!this.parent) {
18285             
18286             Roo.debug && Roo.log("no parent - creating one");
18287             
18288             el = el ? Roo.get(el) : false;      
18289             
18290             if (typeof(Roo.layout.Border) == 'undefined' ) {
18291                 
18292                 this.parent =  {
18293                     el : new Roo.bootstrap.layout.Border({
18294                         el: el || document.body,
18295                     
18296                         center: {
18297                             titlebar: false,
18298                             autoScroll:false,
18299                             closeOnTab: true,
18300                             tabPosition: 'top',
18301                              //resizeTabs: true,
18302                             alwaysShowTabs: false,
18303                             hideTabs: true,
18304                             minTabWidth: 140,
18305                             overflow: 'visible'
18306                          }
18307                      })
18308                 };
18309             } else {
18310             
18311                 // it's a top level one..
18312                 this.parent =  {
18313                     el : new Roo.layout.Border(el || document.body, {
18314                         center: {
18315                             titlebar: false,
18316                             autoScroll:false,
18317                             closeOnTab: true,
18318                             tabPosition: 'top',
18319                              //resizeTabs: true,
18320                             alwaysShowTabs: el && hp? false :  true,
18321                             hideTabs: el || !hp ? true :  false,
18322                             minTabWidth: 140
18323                          }
18324                     })
18325                 };
18326             }
18327         }
18328         
18329         if (!this.parent.el) {
18330                 // probably an old style ctor, which has been disabled.
18331                 return;
18332
18333         }
18334                 // The 'tree' method is  '_tree now' 
18335             
18336         tree.region = tree.region || this.region;
18337         var is_body = false;
18338         if (this.parent.el === true) {
18339             // bootstrap... - body..
18340             if (el) {
18341                 tree.el = el;
18342             }
18343             this.parent.el = Roo.factory(tree);
18344             is_body = true;
18345         }
18346         
18347         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18348         this.fireEvent('built', this);
18349         
18350         this.panel = this.el;
18351         this.layout = this.panel.layout;
18352         this.parentLayout = this.parent.layout  || false;  
18353          
18354     }
18355     
18356 });
18357
18358 Roo.apply(Roo.XComponent, {
18359     /**
18360      * @property  hideProgress
18361      * true to disable the building progress bar.. usefull on single page renders.
18362      * @type Boolean
18363      */
18364     hideProgress : false,
18365     /**
18366      * @property  buildCompleted
18367      * True when the builder has completed building the interface.
18368      * @type Boolean
18369      */
18370     buildCompleted : false,
18371      
18372     /**
18373      * @property  topModule
18374      * the upper most module - uses document.element as it's constructor.
18375      * @type Object
18376      */
18377      
18378     topModule  : false,
18379       
18380     /**
18381      * @property  modules
18382      * array of modules to be created by registration system.
18383      * @type {Array} of Roo.XComponent
18384      */
18385     
18386     modules : [],
18387     /**
18388      * @property  elmodules
18389      * array of modules to be created by which use #ID 
18390      * @type {Array} of Roo.XComponent
18391      */
18392      
18393     elmodules : [],
18394
18395      /**
18396      * @property  is_alt
18397      * Is an alternative Root - normally used by bootstrap or other systems,
18398      *    where the top element in the tree can wrap 'body' 
18399      * @type {boolean}  (default false)
18400      */
18401      
18402     is_alt : false,
18403     /**
18404      * @property  build_from_html
18405      * Build elements from html - used by bootstrap HTML stuff 
18406      *    - this is cleared after build is completed
18407      * @type {boolean}    (default false)
18408      */
18409      
18410     build_from_html : false,
18411     /**
18412      * Register components to be built later.
18413      *
18414      * This solves the following issues
18415      * - Building is not done on page load, but after an authentication process has occured.
18416      * - Interface elements are registered on page load
18417      * - Parent Interface elements may not be loaded before child, so this handles that..
18418      * 
18419      *
18420      * example:
18421      * 
18422      * MyApp.register({
18423           order : '000001',
18424           module : 'Pman.Tab.projectMgr',
18425           region : 'center',
18426           parent : 'Pman.layout',
18427           disabled : false,  // or use a function..
18428         })
18429      
18430      * * @param {Object} details about module
18431      */
18432     register : function(obj) {
18433                 
18434         Roo.XComponent.event.fireEvent('register', obj);
18435         switch(typeof(obj.disabled) ) {
18436                 
18437             case 'undefined':
18438                 break;
18439             
18440             case 'function':
18441                 if ( obj.disabled() ) {
18442                         return;
18443                 }
18444                 break;
18445             
18446             default:
18447                 if (obj.disabled || obj.region == '#disabled') {
18448                         return;
18449                 }
18450                 break;
18451         }
18452                 
18453         this.modules.push(obj);
18454          
18455     },
18456     /**
18457      * convert a string to an object..
18458      * eg. 'AAA.BBB' -> finds AAA.BBB
18459
18460      */
18461     
18462     toObject : function(str)
18463     {
18464         if (!str || typeof(str) == 'object') {
18465             return str;
18466         }
18467         if (str.substring(0,1) == '#') {
18468             return str;
18469         }
18470
18471         var ar = str.split('.');
18472         var rt, o;
18473         rt = ar.shift();
18474             /** eval:var:o */
18475         try {
18476             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18477         } catch (e) {
18478             throw "Module not found : " + str;
18479         }
18480         
18481         if (o === false) {
18482             throw "Module not found : " + str;
18483         }
18484         Roo.each(ar, function(e) {
18485             if (typeof(o[e]) == 'undefined') {
18486                 throw "Module not found : " + str;
18487             }
18488             o = o[e];
18489         });
18490         
18491         return o;
18492         
18493     },
18494     
18495     
18496     /**
18497      * move modules into their correct place in the tree..
18498      * 
18499      */
18500     preBuild : function ()
18501     {
18502         var _t = this;
18503         Roo.each(this.modules , function (obj)
18504         {
18505             Roo.XComponent.event.fireEvent('beforebuild', obj);
18506             
18507             var opar = obj.parent;
18508             try { 
18509                 obj.parent = this.toObject(opar);
18510             } catch(e) {
18511                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18512                 return;
18513             }
18514             
18515             if (!obj.parent) {
18516                 Roo.debug && Roo.log("GOT top level module");
18517                 Roo.debug && Roo.log(obj);
18518                 obj.modules = new Roo.util.MixedCollection(false, 
18519                     function(o) { return o.order + '' }
18520                 );
18521                 this.topModule = obj;
18522                 return;
18523             }
18524                         // parent is a string (usually a dom element name..)
18525             if (typeof(obj.parent) == 'string') {
18526                 this.elmodules.push(obj);
18527                 return;
18528             }
18529             if (obj.parent.constructor != Roo.XComponent) {
18530                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18531             }
18532             if (!obj.parent.modules) {
18533                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18534                     function(o) { return o.order + '' }
18535                 );
18536             }
18537             if (obj.parent.disabled) {
18538                 obj.disabled = true;
18539             }
18540             obj.parent.modules.add(obj);
18541         }, this);
18542     },
18543     
18544      /**
18545      * make a list of modules to build.
18546      * @return {Array} list of modules. 
18547      */ 
18548     
18549     buildOrder : function()
18550     {
18551         var _this = this;
18552         var cmp = function(a,b) {   
18553             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18554         };
18555         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18556             throw "No top level modules to build";
18557         }
18558         
18559         // make a flat list in order of modules to build.
18560         var mods = this.topModule ? [ this.topModule ] : [];
18561                 
18562         
18563         // elmodules (is a list of DOM based modules )
18564         Roo.each(this.elmodules, function(e) {
18565             mods.push(e);
18566             if (!this.topModule &&
18567                 typeof(e.parent) == 'string' &&
18568                 e.parent.substring(0,1) == '#' &&
18569                 Roo.get(e.parent.substr(1))
18570                ) {
18571                 
18572                 _this.topModule = e;
18573             }
18574             
18575         });
18576
18577         
18578         // add modules to their parents..
18579         var addMod = function(m) {
18580             Roo.debug && Roo.log("build Order: add: " + m.name);
18581                 
18582             mods.push(m);
18583             if (m.modules && !m.disabled) {
18584                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18585                 m.modules.keySort('ASC',  cmp );
18586                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18587     
18588                 m.modules.each(addMod);
18589             } else {
18590                 Roo.debug && Roo.log("build Order: no child modules");
18591             }
18592             // not sure if this is used any more..
18593             if (m.finalize) {
18594                 m.finalize.name = m.name + " (clean up) ";
18595                 mods.push(m.finalize);
18596             }
18597             
18598         }
18599         if (this.topModule && this.topModule.modules) { 
18600             this.topModule.modules.keySort('ASC',  cmp );
18601             this.topModule.modules.each(addMod);
18602         } 
18603         return mods;
18604     },
18605     
18606      /**
18607      * Build the registered modules.
18608      * @param {Object} parent element.
18609      * @param {Function} optional method to call after module has been added.
18610      * 
18611      */ 
18612    
18613     build : function(opts) 
18614     {
18615         
18616         if (typeof(opts) != 'undefined') {
18617             Roo.apply(this,opts);
18618         }
18619         
18620         this.preBuild();
18621         var mods = this.buildOrder();
18622       
18623         //this.allmods = mods;
18624         //Roo.debug && Roo.log(mods);
18625         //return;
18626         if (!mods.length) { // should not happen
18627             throw "NO modules!!!";
18628         }
18629         
18630         
18631         var msg = "Building Interface...";
18632         // flash it up as modal - so we store the mask!?
18633         if (!this.hideProgress && Roo.MessageBox) {
18634             Roo.MessageBox.show({ title: 'loading' });
18635             Roo.MessageBox.show({
18636                title: "Please wait...",
18637                msg: msg,
18638                width:450,
18639                progress:true,
18640                buttons : false,
18641                closable:false,
18642                modal: false
18643               
18644             });
18645         }
18646         var total = mods.length;
18647         
18648         var _this = this;
18649         var progressRun = function() {
18650             if (!mods.length) {
18651                 Roo.debug && Roo.log('hide?');
18652                 if (!this.hideProgress && Roo.MessageBox) {
18653                     Roo.MessageBox.hide();
18654                 }
18655                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18656                 
18657                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18658                 
18659                 // THE END...
18660                 return false;   
18661             }
18662             
18663             var m = mods.shift();
18664             
18665             
18666             Roo.debug && Roo.log(m);
18667             // not sure if this is supported any more.. - modules that are are just function
18668             if (typeof(m) == 'function') { 
18669                 m.call(this);
18670                 return progressRun.defer(10, _this);
18671             } 
18672             
18673             
18674             msg = "Building Interface " + (total  - mods.length) + 
18675                     " of " + total + 
18676                     (m.name ? (' - ' + m.name) : '');
18677                         Roo.debug && Roo.log(msg);
18678             if (!_this.hideProgress &&  Roo.MessageBox) { 
18679                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18680             }
18681             
18682          
18683             // is the module disabled?
18684             var disabled = (typeof(m.disabled) == 'function') ?
18685                 m.disabled.call(m.module.disabled) : m.disabled;    
18686             
18687             
18688             if (disabled) {
18689                 return progressRun(); // we do not update the display!
18690             }
18691             
18692             // now build 
18693             
18694                         
18695                         
18696             m.render();
18697             // it's 10 on top level, and 1 on others??? why...
18698             return progressRun.defer(10, _this);
18699              
18700         }
18701         progressRun.defer(1, _this);
18702      
18703         
18704         
18705     },
18706     /**
18707      * Overlay a set of modified strings onto a component
18708      * This is dependant on our builder exporting the strings and 'named strings' elements.
18709      * 
18710      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18711      * @param {Object} associative array of 'named' string and it's new value.
18712      * 
18713      */
18714         overlayStrings : function( component, strings )
18715     {
18716         if (typeof(component['_named_strings']) == 'undefined') {
18717             throw "ERROR: component does not have _named_strings";
18718         }
18719         for ( var k in strings ) {
18720             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18721             if (md !== false) {
18722                 component['_strings'][md] = strings[k];
18723             } else {
18724                 Roo.log('could not find named string: ' + k + ' in');
18725                 Roo.log(component);
18726             }
18727             
18728         }
18729         
18730     },
18731     
18732         
18733         /**
18734          * Event Object.
18735          *
18736          *
18737          */
18738         event: false, 
18739     /**
18740          * wrapper for event.on - aliased later..  
18741          * Typically use to register a event handler for register:
18742          *
18743          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18744          *
18745          */
18746     on : false
18747    
18748     
18749     
18750 });
18751
18752 Roo.XComponent.event = new Roo.util.Observable({
18753                 events : { 
18754                         /**
18755                          * @event register
18756                          * Fires when an Component is registered,
18757                          * set the disable property on the Component to stop registration.
18758                          * @param {Roo.XComponent} c the component being registerd.
18759                          * 
18760                          */
18761                         'register' : true,
18762             /**
18763                          * @event beforebuild
18764                          * Fires before each Component is built
18765                          * can be used to apply permissions.
18766                          * @param {Roo.XComponent} c the component being registerd.
18767                          * 
18768                          */
18769                         'beforebuild' : true,
18770                         /**
18771                          * @event buildcomplete
18772                          * Fires on the top level element when all elements have been built
18773                          * @param {Roo.XComponent} the top level component.
18774                          */
18775                         'buildcomplete' : true
18776                         
18777                 }
18778 });
18779
18780 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18781  //
18782  /**
18783  * marked - a markdown parser
18784  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18785  * https://github.com/chjj/marked
18786  */
18787
18788
18789 /**
18790  *
18791  * Roo.Markdown - is a very crude wrapper around marked..
18792  *
18793  * usage:
18794  * 
18795  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18796  * 
18797  * Note: move the sample code to the bottom of this
18798  * file before uncommenting it.
18799  *
18800  */
18801
18802 Roo.Markdown = {};
18803 Roo.Markdown.toHtml = function(text) {
18804     
18805     var c = new Roo.Markdown.marked.setOptions({
18806             renderer: new Roo.Markdown.marked.Renderer(),
18807             gfm: true,
18808             tables: true,
18809             breaks: false,
18810             pedantic: false,
18811             sanitize: false,
18812             smartLists: true,
18813             smartypants: false
18814           });
18815     // A FEW HACKS!!?
18816     
18817     text = text.replace(/\\\n/g,' ');
18818     return Roo.Markdown.marked(text);
18819 };
18820 //
18821 // converter
18822 //
18823 // Wraps all "globals" so that the only thing
18824 // exposed is makeHtml().
18825 //
18826 (function() {
18827     
18828      /**
18829          * eval:var:escape
18830          * eval:var:unescape
18831          * eval:var:replace
18832          */
18833       
18834     /**
18835      * Helpers
18836      */
18837     
18838     var escape = function (html, encode) {
18839       return html
18840         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18841         .replace(/</g, '&lt;')
18842         .replace(/>/g, '&gt;')
18843         .replace(/"/g, '&quot;')
18844         .replace(/'/g, '&#39;');
18845     }
18846     
18847     var unescape = function (html) {
18848         // explicitly match decimal, hex, and named HTML entities 
18849       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18850         n = n.toLowerCase();
18851         if (n === 'colon') { return ':'; }
18852         if (n.charAt(0) === '#') {
18853           return n.charAt(1) === 'x'
18854             ? String.fromCharCode(parseInt(n.substring(2), 16))
18855             : String.fromCharCode(+n.substring(1));
18856         }
18857         return '';
18858       });
18859     }
18860     
18861     var replace = function (regex, opt) {
18862       regex = regex.source;
18863       opt = opt || '';
18864       return function self(name, val) {
18865         if (!name) { return new RegExp(regex, opt); }
18866         val = val.source || val;
18867         val = val.replace(/(^|[^\[])\^/g, '$1');
18868         regex = regex.replace(name, val);
18869         return self;
18870       };
18871     }
18872
18873
18874          /**
18875          * eval:var:noop
18876     */
18877     var noop = function () {}
18878     noop.exec = noop;
18879     
18880          /**
18881          * eval:var:merge
18882     */
18883     var merge = function (obj) {
18884       var i = 1
18885         , target
18886         , key;
18887     
18888       for (; i < arguments.length; i++) {
18889         target = arguments[i];
18890         for (key in target) {
18891           if (Object.prototype.hasOwnProperty.call(target, key)) {
18892             obj[key] = target[key];
18893           }
18894         }
18895       }
18896     
18897       return obj;
18898     }
18899     
18900     
18901     /**
18902      * Block-Level Grammar
18903      */
18904     
18905     
18906     
18907     
18908     var block = {
18909       newline: /^\n+/,
18910       code: /^( {4}[^\n]+\n*)+/,
18911       fences: noop,
18912       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18913       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18914       nptable: noop,
18915       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18916       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18917       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18918       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18919       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18920       table: noop,
18921       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18922       text: /^[^\n]+/
18923     };
18924     
18925     block.bullet = /(?:[*+-]|\d+\.)/;
18926     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18927     block.item = replace(block.item, 'gm')
18928       (/bull/g, block.bullet)
18929       ();
18930     
18931     block.list = replace(block.list)
18932       (/bull/g, block.bullet)
18933       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18934       ('def', '\\n+(?=' + block.def.source + ')')
18935       ();
18936     
18937     block.blockquote = replace(block.blockquote)
18938       ('def', block.def)
18939       ();
18940     
18941     block._tag = '(?!(?:'
18942       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18943       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18944       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18945     
18946     block.html = replace(block.html)
18947       ('comment', /<!--[\s\S]*?-->/)
18948       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18949       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18950       (/tag/g, block._tag)
18951       ();
18952     
18953     block.paragraph = replace(block.paragraph)
18954       ('hr', block.hr)
18955       ('heading', block.heading)
18956       ('lheading', block.lheading)
18957       ('blockquote', block.blockquote)
18958       ('tag', '<' + block._tag)
18959       ('def', block.def)
18960       ();
18961     
18962     /**
18963      * Normal Block Grammar
18964      */
18965     
18966     block.normal = merge({}, block);
18967     
18968     /**
18969      * GFM Block Grammar
18970      */
18971     
18972     block.gfm = merge({}, block.normal, {
18973       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18974       paragraph: /^/,
18975       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18976     });
18977     
18978     block.gfm.paragraph = replace(block.paragraph)
18979       ('(?!', '(?!'
18980         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18981         + block.list.source.replace('\\1', '\\3') + '|')
18982       ();
18983     
18984     /**
18985      * GFM + Tables Block Grammar
18986      */
18987     
18988     block.tables = merge({}, block.gfm, {
18989       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18990       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18991     });
18992     
18993     /**
18994      * Block Lexer
18995      */
18996     
18997     var Lexer = function (options) {
18998       this.tokens = [];
18999       this.tokens.links = {};
19000       this.options = options || marked.defaults;
19001       this.rules = block.normal;
19002     
19003       if (this.options.gfm) {
19004         if (this.options.tables) {
19005           this.rules = block.tables;
19006         } else {
19007           this.rules = block.gfm;
19008         }
19009       }
19010     }
19011     
19012     /**
19013      * Expose Block Rules
19014      */
19015     
19016     Lexer.rules = block;
19017     
19018     /**
19019      * Static Lex Method
19020      */
19021     
19022     Lexer.lex = function(src, options) {
19023       var lexer = new Lexer(options);
19024       return lexer.lex(src);
19025     };
19026     
19027     /**
19028      * Preprocessing
19029      */
19030     
19031     Lexer.prototype.lex = function(src) {
19032       src = src
19033         .replace(/\r\n|\r/g, '\n')
19034         .replace(/\t/g, '    ')
19035         .replace(/\u00a0/g, ' ')
19036         .replace(/\u2424/g, '\n');
19037     
19038       return this.token(src, true);
19039     };
19040     
19041     /**
19042      * Lexing
19043      */
19044     
19045     Lexer.prototype.token = function(src, top, bq) {
19046       var src = src.replace(/^ +$/gm, '')
19047         , next
19048         , loose
19049         , cap
19050         , bull
19051         , b
19052         , item
19053         , space
19054         , i
19055         , l;
19056     
19057       while (src) {
19058         // newline
19059         if (cap = this.rules.newline.exec(src)) {
19060           src = src.substring(cap[0].length);
19061           if (cap[0].length > 1) {
19062             this.tokens.push({
19063               type: 'space'
19064             });
19065           }
19066         }
19067     
19068         // code
19069         if (cap = this.rules.code.exec(src)) {
19070           src = src.substring(cap[0].length);
19071           cap = cap[0].replace(/^ {4}/gm, '');
19072           this.tokens.push({
19073             type: 'code',
19074             text: !this.options.pedantic
19075               ? cap.replace(/\n+$/, '')
19076               : cap
19077           });
19078           continue;
19079         }
19080     
19081         // fences (gfm)
19082         if (cap = this.rules.fences.exec(src)) {
19083           src = src.substring(cap[0].length);
19084           this.tokens.push({
19085             type: 'code',
19086             lang: cap[2],
19087             text: cap[3] || ''
19088           });
19089           continue;
19090         }
19091     
19092         // heading
19093         if (cap = this.rules.heading.exec(src)) {
19094           src = src.substring(cap[0].length);
19095           this.tokens.push({
19096             type: 'heading',
19097             depth: cap[1].length,
19098             text: cap[2]
19099           });
19100           continue;
19101         }
19102     
19103         // table no leading pipe (gfm)
19104         if (top && (cap = this.rules.nptable.exec(src))) {
19105           src = src.substring(cap[0].length);
19106     
19107           item = {
19108             type: 'table',
19109             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19110             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19111             cells: cap[3].replace(/\n$/, '').split('\n')
19112           };
19113     
19114           for (i = 0; i < item.align.length; i++) {
19115             if (/^ *-+: *$/.test(item.align[i])) {
19116               item.align[i] = 'right';
19117             } else if (/^ *:-+: *$/.test(item.align[i])) {
19118               item.align[i] = 'center';
19119             } else if (/^ *:-+ *$/.test(item.align[i])) {
19120               item.align[i] = 'left';
19121             } else {
19122               item.align[i] = null;
19123             }
19124           }
19125     
19126           for (i = 0; i < item.cells.length; i++) {
19127             item.cells[i] = item.cells[i].split(/ *\| */);
19128           }
19129     
19130           this.tokens.push(item);
19131     
19132           continue;
19133         }
19134     
19135         // lheading
19136         if (cap = this.rules.lheading.exec(src)) {
19137           src = src.substring(cap[0].length);
19138           this.tokens.push({
19139             type: 'heading',
19140             depth: cap[2] === '=' ? 1 : 2,
19141             text: cap[1]
19142           });
19143           continue;
19144         }
19145     
19146         // hr
19147         if (cap = this.rules.hr.exec(src)) {
19148           src = src.substring(cap[0].length);
19149           this.tokens.push({
19150             type: 'hr'
19151           });
19152           continue;
19153         }
19154     
19155         // blockquote
19156         if (cap = this.rules.blockquote.exec(src)) {
19157           src = src.substring(cap[0].length);
19158     
19159           this.tokens.push({
19160             type: 'blockquote_start'
19161           });
19162     
19163           cap = cap[0].replace(/^ *> ?/gm, '');
19164     
19165           // Pass `top` to keep the current
19166           // "toplevel" state. This is exactly
19167           // how markdown.pl works.
19168           this.token(cap, top, true);
19169     
19170           this.tokens.push({
19171             type: 'blockquote_end'
19172           });
19173     
19174           continue;
19175         }
19176     
19177         // list
19178         if (cap = this.rules.list.exec(src)) {
19179           src = src.substring(cap[0].length);
19180           bull = cap[2];
19181     
19182           this.tokens.push({
19183             type: 'list_start',
19184             ordered: bull.length > 1
19185           });
19186     
19187           // Get each top-level item.
19188           cap = cap[0].match(this.rules.item);
19189     
19190           next = false;
19191           l = cap.length;
19192           i = 0;
19193     
19194           for (; i < l; i++) {
19195             item = cap[i];
19196     
19197             // Remove the list item's bullet
19198             // so it is seen as the next token.
19199             space = item.length;
19200             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19201     
19202             // Outdent whatever the
19203             // list item contains. Hacky.
19204             if (~item.indexOf('\n ')) {
19205               space -= item.length;
19206               item = !this.options.pedantic
19207                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19208                 : item.replace(/^ {1,4}/gm, '');
19209             }
19210     
19211             // Determine whether the next list item belongs here.
19212             // Backpedal if it does not belong in this list.
19213             if (this.options.smartLists && i !== l - 1) {
19214               b = block.bullet.exec(cap[i + 1])[0];
19215               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19216                 src = cap.slice(i + 1).join('\n') + src;
19217                 i = l - 1;
19218               }
19219             }
19220     
19221             // Determine whether item is loose or not.
19222             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19223             // for discount behavior.
19224             loose = next || /\n\n(?!\s*$)/.test(item);
19225             if (i !== l - 1) {
19226               next = item.charAt(item.length - 1) === '\n';
19227               if (!loose) { loose = next; }
19228             }
19229     
19230             this.tokens.push({
19231               type: loose
19232                 ? 'loose_item_start'
19233                 : 'list_item_start'
19234             });
19235     
19236             // Recurse.
19237             this.token(item, false, bq);
19238     
19239             this.tokens.push({
19240               type: 'list_item_end'
19241             });
19242           }
19243     
19244           this.tokens.push({
19245             type: 'list_end'
19246           });
19247     
19248           continue;
19249         }
19250     
19251         // html
19252         if (cap = this.rules.html.exec(src)) {
19253           src = src.substring(cap[0].length);
19254           this.tokens.push({
19255             type: this.options.sanitize
19256               ? 'paragraph'
19257               : 'html',
19258             pre: !this.options.sanitizer
19259               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19260             text: cap[0]
19261           });
19262           continue;
19263         }
19264     
19265         // def
19266         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19267           src = src.substring(cap[0].length);
19268           this.tokens.links[cap[1].toLowerCase()] = {
19269             href: cap[2],
19270             title: cap[3]
19271           };
19272           continue;
19273         }
19274     
19275         // table (gfm)
19276         if (top && (cap = this.rules.table.exec(src))) {
19277           src = src.substring(cap[0].length);
19278     
19279           item = {
19280             type: 'table',
19281             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19282             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19283             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19284           };
19285     
19286           for (i = 0; i < item.align.length; i++) {
19287             if (/^ *-+: *$/.test(item.align[i])) {
19288               item.align[i] = 'right';
19289             } else if (/^ *:-+: *$/.test(item.align[i])) {
19290               item.align[i] = 'center';
19291             } else if (/^ *:-+ *$/.test(item.align[i])) {
19292               item.align[i] = 'left';
19293             } else {
19294               item.align[i] = null;
19295             }
19296           }
19297     
19298           for (i = 0; i < item.cells.length; i++) {
19299             item.cells[i] = item.cells[i]
19300               .replace(/^ *\| *| *\| *$/g, '')
19301               .split(/ *\| */);
19302           }
19303     
19304           this.tokens.push(item);
19305     
19306           continue;
19307         }
19308     
19309         // top-level paragraph
19310         if (top && (cap = this.rules.paragraph.exec(src))) {
19311           src = src.substring(cap[0].length);
19312           this.tokens.push({
19313             type: 'paragraph',
19314             text: cap[1].charAt(cap[1].length - 1) === '\n'
19315               ? cap[1].slice(0, -1)
19316               : cap[1]
19317           });
19318           continue;
19319         }
19320     
19321         // text
19322         if (cap = this.rules.text.exec(src)) {
19323           // Top-level should never reach here.
19324           src = src.substring(cap[0].length);
19325           this.tokens.push({
19326             type: 'text',
19327             text: cap[0]
19328           });
19329           continue;
19330         }
19331     
19332         if (src) {
19333           throw new
19334             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19335         }
19336       }
19337     
19338       return this.tokens;
19339     };
19340     
19341     /**
19342      * Inline-Level Grammar
19343      */
19344     
19345     var inline = {
19346       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19347       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19348       url: noop,
19349       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19350       link: /^!?\[(inside)\]\(href\)/,
19351       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19352       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19353       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19354       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19355       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19356       br: /^ {2,}\n(?!\s*$)/,
19357       del: noop,
19358       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19359     };
19360     
19361     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19362     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19363     
19364     inline.link = replace(inline.link)
19365       ('inside', inline._inside)
19366       ('href', inline._href)
19367       ();
19368     
19369     inline.reflink = replace(inline.reflink)
19370       ('inside', inline._inside)
19371       ();
19372     
19373     /**
19374      * Normal Inline Grammar
19375      */
19376     
19377     inline.normal = merge({}, inline);
19378     
19379     /**
19380      * Pedantic Inline Grammar
19381      */
19382     
19383     inline.pedantic = merge({}, inline.normal, {
19384       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19385       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19386     });
19387     
19388     /**
19389      * GFM Inline Grammar
19390      */
19391     
19392     inline.gfm = merge({}, inline.normal, {
19393       escape: replace(inline.escape)('])', '~|])')(),
19394       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19395       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19396       text: replace(inline.text)
19397         (']|', '~]|')
19398         ('|', '|https?://|')
19399         ()
19400     });
19401     
19402     /**
19403      * GFM + Line Breaks Inline Grammar
19404      */
19405     
19406     inline.breaks = merge({}, inline.gfm, {
19407       br: replace(inline.br)('{2,}', '*')(),
19408       text: replace(inline.gfm.text)('{2,}', '*')()
19409     });
19410     
19411     /**
19412      * Inline Lexer & Compiler
19413      */
19414     
19415     var InlineLexer  = function (links, options) {
19416       this.options = options || marked.defaults;
19417       this.links = links;
19418       this.rules = inline.normal;
19419       this.renderer = this.options.renderer || new Renderer;
19420       this.renderer.options = this.options;
19421     
19422       if (!this.links) {
19423         throw new
19424           Error('Tokens array requires a `links` property.');
19425       }
19426     
19427       if (this.options.gfm) {
19428         if (this.options.breaks) {
19429           this.rules = inline.breaks;
19430         } else {
19431           this.rules = inline.gfm;
19432         }
19433       } else if (this.options.pedantic) {
19434         this.rules = inline.pedantic;
19435       }
19436     }
19437     
19438     /**
19439      * Expose Inline Rules
19440      */
19441     
19442     InlineLexer.rules = inline;
19443     
19444     /**
19445      * Static Lexing/Compiling Method
19446      */
19447     
19448     InlineLexer.output = function(src, links, options) {
19449       var inline = new InlineLexer(links, options);
19450       return inline.output(src);
19451     };
19452     
19453     /**
19454      * Lexing/Compiling
19455      */
19456     
19457     InlineLexer.prototype.output = function(src) {
19458       var out = ''
19459         , link
19460         , text
19461         , href
19462         , cap;
19463     
19464       while (src) {
19465         // escape
19466         if (cap = this.rules.escape.exec(src)) {
19467           src = src.substring(cap[0].length);
19468           out += cap[1];
19469           continue;
19470         }
19471     
19472         // autolink
19473         if (cap = this.rules.autolink.exec(src)) {
19474           src = src.substring(cap[0].length);
19475           if (cap[2] === '@') {
19476             text = cap[1].charAt(6) === ':'
19477               ? this.mangle(cap[1].substring(7))
19478               : this.mangle(cap[1]);
19479             href = this.mangle('mailto:') + text;
19480           } else {
19481             text = escape(cap[1]);
19482             href = text;
19483           }
19484           out += this.renderer.link(href, null, text);
19485           continue;
19486         }
19487     
19488         // url (gfm)
19489         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19490           src = src.substring(cap[0].length);
19491           text = escape(cap[1]);
19492           href = text;
19493           out += this.renderer.link(href, null, text);
19494           continue;
19495         }
19496     
19497         // tag
19498         if (cap = this.rules.tag.exec(src)) {
19499           if (!this.inLink && /^<a /i.test(cap[0])) {
19500             this.inLink = true;
19501           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19502             this.inLink = false;
19503           }
19504           src = src.substring(cap[0].length);
19505           out += this.options.sanitize
19506             ? this.options.sanitizer
19507               ? this.options.sanitizer(cap[0])
19508               : escape(cap[0])
19509             : cap[0];
19510           continue;
19511         }
19512     
19513         // link
19514         if (cap = this.rules.link.exec(src)) {
19515           src = src.substring(cap[0].length);
19516           this.inLink = true;
19517           out += this.outputLink(cap, {
19518             href: cap[2],
19519             title: cap[3]
19520           });
19521           this.inLink = false;
19522           continue;
19523         }
19524     
19525         // reflink, nolink
19526         if ((cap = this.rules.reflink.exec(src))
19527             || (cap = this.rules.nolink.exec(src))) {
19528           src = src.substring(cap[0].length);
19529           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19530           link = this.links[link.toLowerCase()];
19531           if (!link || !link.href) {
19532             out += cap[0].charAt(0);
19533             src = cap[0].substring(1) + src;
19534             continue;
19535           }
19536           this.inLink = true;
19537           out += this.outputLink(cap, link);
19538           this.inLink = false;
19539           continue;
19540         }
19541     
19542         // strong
19543         if (cap = this.rules.strong.exec(src)) {
19544           src = src.substring(cap[0].length);
19545           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19546           continue;
19547         }
19548     
19549         // em
19550         if (cap = this.rules.em.exec(src)) {
19551           src = src.substring(cap[0].length);
19552           out += this.renderer.em(this.output(cap[2] || cap[1]));
19553           continue;
19554         }
19555     
19556         // code
19557         if (cap = this.rules.code.exec(src)) {
19558           src = src.substring(cap[0].length);
19559           out += this.renderer.codespan(escape(cap[2], true));
19560           continue;
19561         }
19562     
19563         // br
19564         if (cap = this.rules.br.exec(src)) {
19565           src = src.substring(cap[0].length);
19566           out += this.renderer.br();
19567           continue;
19568         }
19569     
19570         // del (gfm)
19571         if (cap = this.rules.del.exec(src)) {
19572           src = src.substring(cap[0].length);
19573           out += this.renderer.del(this.output(cap[1]));
19574           continue;
19575         }
19576     
19577         // text
19578         if (cap = this.rules.text.exec(src)) {
19579           src = src.substring(cap[0].length);
19580           out += this.renderer.text(escape(this.smartypants(cap[0])));
19581           continue;
19582         }
19583     
19584         if (src) {
19585           throw new
19586             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19587         }
19588       }
19589     
19590       return out;
19591     };
19592     
19593     /**
19594      * Compile Link
19595      */
19596     
19597     InlineLexer.prototype.outputLink = function(cap, link) {
19598       var href = escape(link.href)
19599         , title = link.title ? escape(link.title) : null;
19600     
19601       return cap[0].charAt(0) !== '!'
19602         ? this.renderer.link(href, title, this.output(cap[1]))
19603         : this.renderer.image(href, title, escape(cap[1]));
19604     };
19605     
19606     /**
19607      * Smartypants Transformations
19608      */
19609     
19610     InlineLexer.prototype.smartypants = function(text) {
19611       if (!this.options.smartypants)  { return text; }
19612       return text
19613         // em-dashes
19614         .replace(/---/g, '\u2014')
19615         // en-dashes
19616         .replace(/--/g, '\u2013')
19617         // opening singles
19618         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19619         // closing singles & apostrophes
19620         .replace(/'/g, '\u2019')
19621         // opening doubles
19622         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19623         // closing doubles
19624         .replace(/"/g, '\u201d')
19625         // ellipses
19626         .replace(/\.{3}/g, '\u2026');
19627     };
19628     
19629     /**
19630      * Mangle Links
19631      */
19632     
19633     InlineLexer.prototype.mangle = function(text) {
19634       if (!this.options.mangle) { return text; }
19635       var out = ''
19636         , l = text.length
19637         , i = 0
19638         , ch;
19639     
19640       for (; i < l; i++) {
19641         ch = text.charCodeAt(i);
19642         if (Math.random() > 0.5) {
19643           ch = 'x' + ch.toString(16);
19644         }
19645         out += '&#' + ch + ';';
19646       }
19647     
19648       return out;
19649     };
19650     
19651     /**
19652      * Renderer
19653      */
19654     
19655      /**
19656          * eval:var:Renderer
19657     */
19658     
19659     var Renderer   = function (options) {
19660       this.options = options || {};
19661     }
19662     
19663     Renderer.prototype.code = function(code, lang, escaped) {
19664       if (this.options.highlight) {
19665         var out = this.options.highlight(code, lang);
19666         if (out != null && out !== code) {
19667           escaped = true;
19668           code = out;
19669         }
19670       } else {
19671             // hack!!! - it's already escapeD?
19672             escaped = true;
19673       }
19674     
19675       if (!lang) {
19676         return '<pre><code>'
19677           + (escaped ? code : escape(code, true))
19678           + '\n</code></pre>';
19679       }
19680     
19681       return '<pre><code class="'
19682         + this.options.langPrefix
19683         + escape(lang, true)
19684         + '">'
19685         + (escaped ? code : escape(code, true))
19686         + '\n</code></pre>\n';
19687     };
19688     
19689     Renderer.prototype.blockquote = function(quote) {
19690       return '<blockquote>\n' + quote + '</blockquote>\n';
19691     };
19692     
19693     Renderer.prototype.html = function(html) {
19694       return html;
19695     };
19696     
19697     Renderer.prototype.heading = function(text, level, raw) {
19698       return '<h'
19699         + level
19700         + ' id="'
19701         + this.options.headerPrefix
19702         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19703         + '">'
19704         + text
19705         + '</h'
19706         + level
19707         + '>\n';
19708     };
19709     
19710     Renderer.prototype.hr = function() {
19711       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19712     };
19713     
19714     Renderer.prototype.list = function(body, ordered) {
19715       var type = ordered ? 'ol' : 'ul';
19716       return '<' + type + '>\n' + body + '</' + type + '>\n';
19717     };
19718     
19719     Renderer.prototype.listitem = function(text) {
19720       return '<li>' + text + '</li>\n';
19721     };
19722     
19723     Renderer.prototype.paragraph = function(text) {
19724       return '<p>' + text + '</p>\n';
19725     };
19726     
19727     Renderer.prototype.table = function(header, body) {
19728       return '<table class="table table-striped">\n'
19729         + '<thead>\n'
19730         + header
19731         + '</thead>\n'
19732         + '<tbody>\n'
19733         + body
19734         + '</tbody>\n'
19735         + '</table>\n';
19736     };
19737     
19738     Renderer.prototype.tablerow = function(content) {
19739       return '<tr>\n' + content + '</tr>\n';
19740     };
19741     
19742     Renderer.prototype.tablecell = function(content, flags) {
19743       var type = flags.header ? 'th' : 'td';
19744       var tag = flags.align
19745         ? '<' + type + ' style="text-align:' + flags.align + '">'
19746         : '<' + type + '>';
19747       return tag + content + '</' + type + '>\n';
19748     };
19749     
19750     // span level renderer
19751     Renderer.prototype.strong = function(text) {
19752       return '<strong>' + text + '</strong>';
19753     };
19754     
19755     Renderer.prototype.em = function(text) {
19756       return '<em>' + text + '</em>';
19757     };
19758     
19759     Renderer.prototype.codespan = function(text) {
19760       return '<code>' + text + '</code>';
19761     };
19762     
19763     Renderer.prototype.br = function() {
19764       return this.options.xhtml ? '<br/>' : '<br>';
19765     };
19766     
19767     Renderer.prototype.del = function(text) {
19768       return '<del>' + text + '</del>';
19769     };
19770     
19771     Renderer.prototype.link = function(href, title, text) {
19772       if (this.options.sanitize) {
19773         try {
19774           var prot = decodeURIComponent(unescape(href))
19775             .replace(/[^\w:]/g, '')
19776             .toLowerCase();
19777         } catch (e) {
19778           return '';
19779         }
19780         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19781           return '';
19782         }
19783       }
19784       var out = '<a href="' + href + '"';
19785       if (title) {
19786         out += ' title="' + title + '"';
19787       }
19788       out += '>' + text + '</a>';
19789       return out;
19790     };
19791     
19792     Renderer.prototype.image = function(href, title, text) {
19793       var out = '<img src="' + href + '" alt="' + text + '"';
19794       if (title) {
19795         out += ' title="' + title + '"';
19796       }
19797       out += this.options.xhtml ? '/>' : '>';
19798       return out;
19799     };
19800     
19801     Renderer.prototype.text = function(text) {
19802       return text;
19803     };
19804     
19805     /**
19806      * Parsing & Compiling
19807      */
19808          /**
19809          * eval:var:Parser
19810     */
19811     
19812     var Parser= function (options) {
19813       this.tokens = [];
19814       this.token = null;
19815       this.options = options || marked.defaults;
19816       this.options.renderer = this.options.renderer || new Renderer;
19817       this.renderer = this.options.renderer;
19818       this.renderer.options = this.options;
19819     }
19820     
19821     /**
19822      * Static Parse Method
19823      */
19824     
19825     Parser.parse = function(src, options, renderer) {
19826       var parser = new Parser(options, renderer);
19827       return parser.parse(src);
19828     };
19829     
19830     /**
19831      * Parse Loop
19832      */
19833     
19834     Parser.prototype.parse = function(src) {
19835       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19836       this.tokens = src.reverse();
19837     
19838       var out = '';
19839       while (this.next()) {
19840         out += this.tok();
19841       }
19842     
19843       return out;
19844     };
19845     
19846     /**
19847      * Next Token
19848      */
19849     
19850     Parser.prototype.next = function() {
19851       return this.token = this.tokens.pop();
19852     };
19853     
19854     /**
19855      * Preview Next Token
19856      */
19857     
19858     Parser.prototype.peek = function() {
19859       return this.tokens[this.tokens.length - 1] || 0;
19860     };
19861     
19862     /**
19863      * Parse Text Tokens
19864      */
19865     
19866     Parser.prototype.parseText = function() {
19867       var body = this.token.text;
19868     
19869       while (this.peek().type === 'text') {
19870         body += '\n' + this.next().text;
19871       }
19872     
19873       return this.inline.output(body);
19874     };
19875     
19876     /**
19877      * Parse Current Token
19878      */
19879     
19880     Parser.prototype.tok = function() {
19881       switch (this.token.type) {
19882         case 'space': {
19883           return '';
19884         }
19885         case 'hr': {
19886           return this.renderer.hr();
19887         }
19888         case 'heading': {
19889           return this.renderer.heading(
19890             this.inline.output(this.token.text),
19891             this.token.depth,
19892             this.token.text);
19893         }
19894         case 'code': {
19895           return this.renderer.code(this.token.text,
19896             this.token.lang,
19897             this.token.escaped);
19898         }
19899         case 'table': {
19900           var header = ''
19901             , body = ''
19902             , i
19903             , row
19904             , cell
19905             , flags
19906             , j;
19907     
19908           // header
19909           cell = '';
19910           for (i = 0; i < this.token.header.length; i++) {
19911             flags = { header: true, align: this.token.align[i] };
19912             cell += this.renderer.tablecell(
19913               this.inline.output(this.token.header[i]),
19914               { header: true, align: this.token.align[i] }
19915             );
19916           }
19917           header += this.renderer.tablerow(cell);
19918     
19919           for (i = 0; i < this.token.cells.length; i++) {
19920             row = this.token.cells[i];
19921     
19922             cell = '';
19923             for (j = 0; j < row.length; j++) {
19924               cell += this.renderer.tablecell(
19925                 this.inline.output(row[j]),
19926                 { header: false, align: this.token.align[j] }
19927               );
19928             }
19929     
19930             body += this.renderer.tablerow(cell);
19931           }
19932           return this.renderer.table(header, body);
19933         }
19934         case 'blockquote_start': {
19935           var body = '';
19936     
19937           while (this.next().type !== 'blockquote_end') {
19938             body += this.tok();
19939           }
19940     
19941           return this.renderer.blockquote(body);
19942         }
19943         case 'list_start': {
19944           var body = ''
19945             , ordered = this.token.ordered;
19946     
19947           while (this.next().type !== 'list_end') {
19948             body += this.tok();
19949           }
19950     
19951           return this.renderer.list(body, ordered);
19952         }
19953         case 'list_item_start': {
19954           var body = '';
19955     
19956           while (this.next().type !== 'list_item_end') {
19957             body += this.token.type === 'text'
19958               ? this.parseText()
19959               : this.tok();
19960           }
19961     
19962           return this.renderer.listitem(body);
19963         }
19964         case 'loose_item_start': {
19965           var body = '';
19966     
19967           while (this.next().type !== 'list_item_end') {
19968             body += this.tok();
19969           }
19970     
19971           return this.renderer.listitem(body);
19972         }
19973         case 'html': {
19974           var html = !this.token.pre && !this.options.pedantic
19975             ? this.inline.output(this.token.text)
19976             : this.token.text;
19977           return this.renderer.html(html);
19978         }
19979         case 'paragraph': {
19980           return this.renderer.paragraph(this.inline.output(this.token.text));
19981         }
19982         case 'text': {
19983           return this.renderer.paragraph(this.parseText());
19984         }
19985       }
19986     };
19987   
19988     
19989     /**
19990      * Marked
19991      */
19992          /**
19993          * eval:var:marked
19994     */
19995     var marked = function (src, opt, callback) {
19996       if (callback || typeof opt === 'function') {
19997         if (!callback) {
19998           callback = opt;
19999           opt = null;
20000         }
20001     
20002         opt = merge({}, marked.defaults, opt || {});
20003     
20004         var highlight = opt.highlight
20005           , tokens
20006           , pending
20007           , i = 0;
20008     
20009         try {
20010           tokens = Lexer.lex(src, opt)
20011         } catch (e) {
20012           return callback(e);
20013         }
20014     
20015         pending = tokens.length;
20016          /**
20017          * eval:var:done
20018     */
20019         var done = function(err) {
20020           if (err) {
20021             opt.highlight = highlight;
20022             return callback(err);
20023           }
20024     
20025           var out;
20026     
20027           try {
20028             out = Parser.parse(tokens, opt);
20029           } catch (e) {
20030             err = e;
20031           }
20032     
20033           opt.highlight = highlight;
20034     
20035           return err
20036             ? callback(err)
20037             : callback(null, out);
20038         };
20039     
20040         if (!highlight || highlight.length < 3) {
20041           return done();
20042         }
20043     
20044         delete opt.highlight;
20045     
20046         if (!pending) { return done(); }
20047     
20048         for (; i < tokens.length; i++) {
20049           (function(token) {
20050             if (token.type !== 'code') {
20051               return --pending || done();
20052             }
20053             return highlight(token.text, token.lang, function(err, code) {
20054               if (err) { return done(err); }
20055               if (code == null || code === token.text) {
20056                 return --pending || done();
20057               }
20058               token.text = code;
20059               token.escaped = true;
20060               --pending || done();
20061             });
20062           })(tokens[i]);
20063         }
20064     
20065         return;
20066       }
20067       try {
20068         if (opt) { opt = merge({}, marked.defaults, opt); }
20069         return Parser.parse(Lexer.lex(src, opt), opt);
20070       } catch (e) {
20071         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20072         if ((opt || marked.defaults).silent) {
20073           return '<p>An error occured:</p><pre>'
20074             + escape(e.message + '', true)
20075             + '</pre>';
20076         }
20077         throw e;
20078       }
20079     }
20080     
20081     /**
20082      * Options
20083      */
20084     
20085     marked.options =
20086     marked.setOptions = function(opt) {
20087       merge(marked.defaults, opt);
20088       return marked;
20089     };
20090     
20091     marked.defaults = {
20092       gfm: true,
20093       tables: true,
20094       breaks: false,
20095       pedantic: false,
20096       sanitize: false,
20097       sanitizer: null,
20098       mangle: true,
20099       smartLists: false,
20100       silent: false,
20101       highlight: null,
20102       langPrefix: 'lang-',
20103       smartypants: false,
20104       headerPrefix: '',
20105       renderer: new Renderer,
20106       xhtml: false
20107     };
20108     
20109     /**
20110      * Expose
20111      */
20112     
20113     marked.Parser = Parser;
20114     marked.parser = Parser.parse;
20115     
20116     marked.Renderer = Renderer;
20117     
20118     marked.Lexer = Lexer;
20119     marked.lexer = Lexer.lex;
20120     
20121     marked.InlineLexer = InlineLexer;
20122     marked.inlineLexer = InlineLexer.output;
20123     
20124     marked.parse = marked;
20125     
20126     Roo.Markdown.marked = marked;
20127
20128 })();/*
20129  * Based on:
20130  * Ext JS Library 1.1.1
20131  * Copyright(c) 2006-2007, Ext JS, LLC.
20132  *
20133  * Originally Released Under LGPL - original licence link has changed is not relivant.
20134  *
20135  * Fork - LGPL
20136  * <script type="text/javascript">
20137  */
20138
20139
20140
20141 /*
20142  * These classes are derivatives of the similarly named classes in the YUI Library.
20143  * The original license:
20144  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20145  * Code licensed under the BSD License:
20146  * http://developer.yahoo.net/yui/license.txt
20147  */
20148
20149 (function() {
20150
20151 var Event=Roo.EventManager;
20152 var Dom=Roo.lib.Dom;
20153
20154 /**
20155  * @class Roo.dd.DragDrop
20156  * @extends Roo.util.Observable
20157  * Defines the interface and base operation of items that that can be
20158  * dragged or can be drop targets.  It was designed to be extended, overriding
20159  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20160  * Up to three html elements can be associated with a DragDrop instance:
20161  * <ul>
20162  * <li>linked element: the element that is passed into the constructor.
20163  * This is the element which defines the boundaries for interaction with
20164  * other DragDrop objects.</li>
20165  * <li>handle element(s): The drag operation only occurs if the element that
20166  * was clicked matches a handle element.  By default this is the linked
20167  * element, but there are times that you will want only a portion of the
20168  * linked element to initiate the drag operation, and the setHandleElId()
20169  * method provides a way to define this.</li>
20170  * <li>drag element: this represents the element that would be moved along
20171  * with the cursor during a drag operation.  By default, this is the linked
20172  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20173  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20174  * </li>
20175  * </ul>
20176  * This class should not be instantiated until the onload event to ensure that
20177  * the associated elements are available.
20178  * The following would define a DragDrop obj that would interact with any
20179  * other DragDrop obj in the "group1" group:
20180  * <pre>
20181  *  dd = new Roo.dd.DragDrop("div1", "group1");
20182  * </pre>
20183  * Since none of the event handlers have been implemented, nothing would
20184  * actually happen if you were to run the code above.  Normally you would
20185  * override this class or one of the default implementations, but you can
20186  * also override the methods you want on an instance of the class...
20187  * <pre>
20188  *  dd.onDragDrop = function(e, id) {
20189  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20190  *  }
20191  * </pre>
20192  * @constructor
20193  * @param {String} id of the element that is linked to this instance
20194  * @param {String} sGroup the group of related DragDrop objects
20195  * @param {object} config an object containing configurable attributes
20196  *                Valid properties for DragDrop:
20197  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20198  */
20199 Roo.dd.DragDrop = function(id, sGroup, config) {
20200     if (id) {
20201         this.init(id, sGroup, config);
20202     }
20203     
20204 };
20205
20206 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20207
20208     /**
20209      * The id of the element associated with this object.  This is what we
20210      * refer to as the "linked element" because the size and position of
20211      * this element is used to determine when the drag and drop objects have
20212      * interacted.
20213      * @property id
20214      * @type String
20215      */
20216     id: null,
20217
20218     /**
20219      * Configuration attributes passed into the constructor
20220      * @property config
20221      * @type object
20222      */
20223     config: null,
20224
20225     /**
20226      * The id of the element that will be dragged.  By default this is same
20227      * as the linked element , but could be changed to another element. Ex:
20228      * Roo.dd.DDProxy
20229      * @property dragElId
20230      * @type String
20231      * @private
20232      */
20233     dragElId: null,
20234
20235     /**
20236      * the id of the element that initiates the drag operation.  By default
20237      * this is the linked element, but could be changed to be a child of this
20238      * element.  This lets us do things like only starting the drag when the
20239      * header element within the linked html element is clicked.
20240      * @property handleElId
20241      * @type String
20242      * @private
20243      */
20244     handleElId: null,
20245
20246     /**
20247      * An associative array of HTML tags that will be ignored if clicked.
20248      * @property invalidHandleTypes
20249      * @type {string: string}
20250      */
20251     invalidHandleTypes: null,
20252
20253     /**
20254      * An associative array of ids for elements that will be ignored if clicked
20255      * @property invalidHandleIds
20256      * @type {string: string}
20257      */
20258     invalidHandleIds: null,
20259
20260     /**
20261      * An indexted array of css class names for elements that will be ignored
20262      * if clicked.
20263      * @property invalidHandleClasses
20264      * @type string[]
20265      */
20266     invalidHandleClasses: null,
20267
20268     /**
20269      * The linked element's absolute X position at the time the drag was
20270      * started
20271      * @property startPageX
20272      * @type int
20273      * @private
20274      */
20275     startPageX: 0,
20276
20277     /**
20278      * The linked element's absolute X position at the time the drag was
20279      * started
20280      * @property startPageY
20281      * @type int
20282      * @private
20283      */
20284     startPageY: 0,
20285
20286     /**
20287      * The group defines a logical collection of DragDrop objects that are
20288      * related.  Instances only get events when interacting with other
20289      * DragDrop object in the same group.  This lets us define multiple
20290      * groups using a single DragDrop subclass if we want.
20291      * @property groups
20292      * @type {string: string}
20293      */
20294     groups: null,
20295
20296     /**
20297      * Individual drag/drop instances can be locked.  This will prevent
20298      * onmousedown start drag.
20299      * @property locked
20300      * @type boolean
20301      * @private
20302      */
20303     locked: false,
20304
20305     /**
20306      * Lock this instance
20307      * @method lock
20308      */
20309     lock: function() { this.locked = true; },
20310
20311     /**
20312      * Unlock this instace
20313      * @method unlock
20314      */
20315     unlock: function() { this.locked = false; },
20316
20317     /**
20318      * By default, all insances can be a drop target.  This can be disabled by
20319      * setting isTarget to false.
20320      * @method isTarget
20321      * @type boolean
20322      */
20323     isTarget: true,
20324
20325     /**
20326      * The padding configured for this drag and drop object for calculating
20327      * the drop zone intersection with this object.
20328      * @method padding
20329      * @type int[]
20330      */
20331     padding: null,
20332
20333     /**
20334      * Cached reference to the linked element
20335      * @property _domRef
20336      * @private
20337      */
20338     _domRef: null,
20339
20340     /**
20341      * Internal typeof flag
20342      * @property __ygDragDrop
20343      * @private
20344      */
20345     __ygDragDrop: true,
20346
20347     /**
20348      * Set to true when horizontal contraints are applied
20349      * @property constrainX
20350      * @type boolean
20351      * @private
20352      */
20353     constrainX: false,
20354
20355     /**
20356      * Set to true when vertical contraints are applied
20357      * @property constrainY
20358      * @type boolean
20359      * @private
20360      */
20361     constrainY: false,
20362
20363     /**
20364      * The left constraint
20365      * @property minX
20366      * @type int
20367      * @private
20368      */
20369     minX: 0,
20370
20371     /**
20372      * The right constraint
20373      * @property maxX
20374      * @type int
20375      * @private
20376      */
20377     maxX: 0,
20378
20379     /**
20380      * The up constraint
20381      * @property minY
20382      * @type int
20383      * @type int
20384      * @private
20385      */
20386     minY: 0,
20387
20388     /**
20389      * The down constraint
20390      * @property maxY
20391      * @type int
20392      * @private
20393      */
20394     maxY: 0,
20395
20396     /**
20397      * Maintain offsets when we resetconstraints.  Set to true when you want
20398      * the position of the element relative to its parent to stay the same
20399      * when the page changes
20400      *
20401      * @property maintainOffset
20402      * @type boolean
20403      */
20404     maintainOffset: false,
20405
20406     /**
20407      * Array of pixel locations the element will snap to if we specified a
20408      * horizontal graduation/interval.  This array is generated automatically
20409      * when you define a tick interval.
20410      * @property xTicks
20411      * @type int[]
20412      */
20413     xTicks: null,
20414
20415     /**
20416      * Array of pixel locations the element will snap to if we specified a
20417      * vertical graduation/interval.  This array is generated automatically
20418      * when you define a tick interval.
20419      * @property yTicks
20420      * @type int[]
20421      */
20422     yTicks: null,
20423
20424     /**
20425      * By default the drag and drop instance will only respond to the primary
20426      * button click (left button for a right-handed mouse).  Set to true to
20427      * allow drag and drop to start with any mouse click that is propogated
20428      * by the browser
20429      * @property primaryButtonOnly
20430      * @type boolean
20431      */
20432     primaryButtonOnly: true,
20433
20434     /**
20435      * The availabe property is false until the linked dom element is accessible.
20436      * @property available
20437      * @type boolean
20438      */
20439     available: false,
20440
20441     /**
20442      * By default, drags can only be initiated if the mousedown occurs in the
20443      * region the linked element is.  This is done in part to work around a
20444      * bug in some browsers that mis-report the mousedown if the previous
20445      * mouseup happened outside of the window.  This property is set to true
20446      * if outer handles are defined.
20447      *
20448      * @property hasOuterHandles
20449      * @type boolean
20450      * @default false
20451      */
20452     hasOuterHandles: false,
20453
20454     /**
20455      * Code that executes immediately before the startDrag event
20456      * @method b4StartDrag
20457      * @private
20458      */
20459     b4StartDrag: function(x, y) { },
20460
20461     /**
20462      * Abstract method called after a drag/drop object is clicked
20463      * and the drag or mousedown time thresholds have beeen met.
20464      * @method startDrag
20465      * @param {int} X click location
20466      * @param {int} Y click location
20467      */
20468     startDrag: function(x, y) { /* override this */ },
20469
20470     /**
20471      * Code that executes immediately before the onDrag event
20472      * @method b4Drag
20473      * @private
20474      */
20475     b4Drag: function(e) { },
20476
20477     /**
20478      * Abstract method called during the onMouseMove event while dragging an
20479      * object.
20480      * @method onDrag
20481      * @param {Event} e the mousemove event
20482      */
20483     onDrag: function(e) { /* override this */ },
20484
20485     /**
20486      * Abstract method called when this element fist begins hovering over
20487      * another DragDrop obj
20488      * @method onDragEnter
20489      * @param {Event} e the mousemove event
20490      * @param {String|DragDrop[]} id In POINT mode, the element
20491      * id this is hovering over.  In INTERSECT mode, an array of one or more
20492      * dragdrop items being hovered over.
20493      */
20494     onDragEnter: function(e, id) { /* override this */ },
20495
20496     /**
20497      * Code that executes immediately before the onDragOver event
20498      * @method b4DragOver
20499      * @private
20500      */
20501     b4DragOver: function(e) { },
20502
20503     /**
20504      * Abstract method called when this element is hovering over another
20505      * DragDrop obj
20506      * @method onDragOver
20507      * @param {Event} e the mousemove event
20508      * @param {String|DragDrop[]} id In POINT mode, the element
20509      * id this is hovering over.  In INTERSECT mode, an array of dd items
20510      * being hovered over.
20511      */
20512     onDragOver: function(e, id) { /* override this */ },
20513
20514     /**
20515      * Code that executes immediately before the onDragOut event
20516      * @method b4DragOut
20517      * @private
20518      */
20519     b4DragOut: function(e) { },
20520
20521     /**
20522      * Abstract method called when we are no longer hovering over an element
20523      * @method onDragOut
20524      * @param {Event} e the mousemove event
20525      * @param {String|DragDrop[]} id In POINT mode, the element
20526      * id this was hovering over.  In INTERSECT mode, an array of dd items
20527      * that the mouse is no longer over.
20528      */
20529     onDragOut: function(e, id) { /* override this */ },
20530
20531     /**
20532      * Code that executes immediately before the onDragDrop event
20533      * @method b4DragDrop
20534      * @private
20535      */
20536     b4DragDrop: function(e) { },
20537
20538     /**
20539      * Abstract method called when this item is dropped on another DragDrop
20540      * obj
20541      * @method onDragDrop
20542      * @param {Event} e the mouseup event
20543      * @param {String|DragDrop[]} id In POINT mode, the element
20544      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20545      * was dropped on.
20546      */
20547     onDragDrop: function(e, id) { /* override this */ },
20548
20549     /**
20550      * Abstract method called when this item is dropped on an area with no
20551      * drop target
20552      * @method onInvalidDrop
20553      * @param {Event} e the mouseup event
20554      */
20555     onInvalidDrop: function(e) { /* override this */ },
20556
20557     /**
20558      * Code that executes immediately before the endDrag event
20559      * @method b4EndDrag
20560      * @private
20561      */
20562     b4EndDrag: function(e) { },
20563
20564     /**
20565      * Fired when we are done dragging the object
20566      * @method endDrag
20567      * @param {Event} e the mouseup event
20568      */
20569     endDrag: function(e) { /* override this */ },
20570
20571     /**
20572      * Code executed immediately before the onMouseDown event
20573      * @method b4MouseDown
20574      * @param {Event} e the mousedown event
20575      * @private
20576      */
20577     b4MouseDown: function(e) {  },
20578
20579     /**
20580      * Event handler that fires when a drag/drop obj gets a mousedown
20581      * @method onMouseDown
20582      * @param {Event} e the mousedown event
20583      */
20584     onMouseDown: function(e) { /* override this */ },
20585
20586     /**
20587      * Event handler that fires when a drag/drop obj gets a mouseup
20588      * @method onMouseUp
20589      * @param {Event} e the mouseup event
20590      */
20591     onMouseUp: function(e) { /* override this */ },
20592
20593     /**
20594      * Override the onAvailable method to do what is needed after the initial
20595      * position was determined.
20596      * @method onAvailable
20597      */
20598     onAvailable: function () {
20599     },
20600
20601     /*
20602      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20603      * @type Object
20604      */
20605     defaultPadding : {left:0, right:0, top:0, bottom:0},
20606
20607     /*
20608      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20609  *
20610  * Usage:
20611  <pre><code>
20612  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20613                 { dragElId: "existingProxyDiv" });
20614  dd.startDrag = function(){
20615      this.constrainTo("parent-id");
20616  };
20617  </code></pre>
20618  * Or you can initalize it using the {@link Roo.Element} object:
20619  <pre><code>
20620  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20621      startDrag : function(){
20622          this.constrainTo("parent-id");
20623      }
20624  });
20625  </code></pre>
20626      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20627      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20628      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20629      * an object containing the sides to pad. For example: {right:10, bottom:10}
20630      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20631      */
20632     constrainTo : function(constrainTo, pad, inContent){
20633         if(typeof pad == "number"){
20634             pad = {left: pad, right:pad, top:pad, bottom:pad};
20635         }
20636         pad = pad || this.defaultPadding;
20637         var b = Roo.get(this.getEl()).getBox();
20638         var ce = Roo.get(constrainTo);
20639         var s = ce.getScroll();
20640         var c, cd = ce.dom;
20641         if(cd == document.body){
20642             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20643         }else{
20644             xy = ce.getXY();
20645             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20646         }
20647
20648
20649         var topSpace = b.y - c.y;
20650         var leftSpace = b.x - c.x;
20651
20652         this.resetConstraints();
20653         this.setXConstraint(leftSpace - (pad.left||0), // left
20654                 c.width - leftSpace - b.width - (pad.right||0) //right
20655         );
20656         this.setYConstraint(topSpace - (pad.top||0), //top
20657                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20658         );
20659     },
20660
20661     /**
20662      * Returns a reference to the linked element
20663      * @method getEl
20664      * @return {HTMLElement} the html element
20665      */
20666     getEl: function() {
20667         if (!this._domRef) {
20668             this._domRef = Roo.getDom(this.id);
20669         }
20670
20671         return this._domRef;
20672     },
20673
20674     /**
20675      * Returns a reference to the actual element to drag.  By default this is
20676      * the same as the html element, but it can be assigned to another
20677      * element. An example of this can be found in Roo.dd.DDProxy
20678      * @method getDragEl
20679      * @return {HTMLElement} the html element
20680      */
20681     getDragEl: function() {
20682         return Roo.getDom(this.dragElId);
20683     },
20684
20685     /**
20686      * Sets up the DragDrop object.  Must be called in the constructor of any
20687      * Roo.dd.DragDrop subclass
20688      * @method init
20689      * @param id the id of the linked element
20690      * @param {String} sGroup the group of related items
20691      * @param {object} config configuration attributes
20692      */
20693     init: function(id, sGroup, config) {
20694         this.initTarget(id, sGroup, config);
20695         if (!Roo.isTouch) {
20696             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20697         }
20698         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20699         // Event.on(this.id, "selectstart", Event.preventDefault);
20700     },
20701
20702     /**
20703      * Initializes Targeting functionality only... the object does not
20704      * get a mousedown handler.
20705      * @method initTarget
20706      * @param id the id of the linked element
20707      * @param {String} sGroup the group of related items
20708      * @param {object} config configuration attributes
20709      */
20710     initTarget: function(id, sGroup, config) {
20711
20712         // configuration attributes
20713         this.config = config || {};
20714
20715         // create a local reference to the drag and drop manager
20716         this.DDM = Roo.dd.DDM;
20717         // initialize the groups array
20718         this.groups = {};
20719
20720         // assume that we have an element reference instead of an id if the
20721         // parameter is not a string
20722         if (typeof id !== "string") {
20723             id = Roo.id(id);
20724         }
20725
20726         // set the id
20727         this.id = id;
20728
20729         // add to an interaction group
20730         this.addToGroup((sGroup) ? sGroup : "default");
20731
20732         // We don't want to register this as the handle with the manager
20733         // so we just set the id rather than calling the setter.
20734         this.handleElId = id;
20735
20736         // the linked element is the element that gets dragged by default
20737         this.setDragElId(id);
20738
20739         // by default, clicked anchors will not start drag operations.
20740         this.invalidHandleTypes = { A: "A" };
20741         this.invalidHandleIds = {};
20742         this.invalidHandleClasses = [];
20743
20744         this.applyConfig();
20745
20746         this.handleOnAvailable();
20747     },
20748
20749     /**
20750      * Applies the configuration parameters that were passed into the constructor.
20751      * This is supposed to happen at each level through the inheritance chain.  So
20752      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20753      * DragDrop in order to get all of the parameters that are available in
20754      * each object.
20755      * @method applyConfig
20756      */
20757     applyConfig: function() {
20758
20759         // configurable properties:
20760         //    padding, isTarget, maintainOffset, primaryButtonOnly
20761         this.padding           = this.config.padding || [0, 0, 0, 0];
20762         this.isTarget          = (this.config.isTarget !== false);
20763         this.maintainOffset    = (this.config.maintainOffset);
20764         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20765
20766     },
20767
20768     /**
20769      * Executed when the linked element is available
20770      * @method handleOnAvailable
20771      * @private
20772      */
20773     handleOnAvailable: function() {
20774         this.available = true;
20775         this.resetConstraints();
20776         this.onAvailable();
20777     },
20778
20779      /**
20780      * Configures the padding for the target zone in px.  Effectively expands
20781      * (or reduces) the virtual object size for targeting calculations.
20782      * Supports css-style shorthand; if only one parameter is passed, all sides
20783      * will have that padding, and if only two are passed, the top and bottom
20784      * will have the first param, the left and right the second.
20785      * @method setPadding
20786      * @param {int} iTop    Top pad
20787      * @param {int} iRight  Right pad
20788      * @param {int} iBot    Bot pad
20789      * @param {int} iLeft   Left pad
20790      */
20791     setPadding: function(iTop, iRight, iBot, iLeft) {
20792         // this.padding = [iLeft, iRight, iTop, iBot];
20793         if (!iRight && 0 !== iRight) {
20794             this.padding = [iTop, iTop, iTop, iTop];
20795         } else if (!iBot && 0 !== iBot) {
20796             this.padding = [iTop, iRight, iTop, iRight];
20797         } else {
20798             this.padding = [iTop, iRight, iBot, iLeft];
20799         }
20800     },
20801
20802     /**
20803      * Stores the initial placement of the linked element.
20804      * @method setInitialPosition
20805      * @param {int} diffX   the X offset, default 0
20806      * @param {int} diffY   the Y offset, default 0
20807      */
20808     setInitPosition: function(diffX, diffY) {
20809         var el = this.getEl();
20810
20811         if (!this.DDM.verifyEl(el)) {
20812             return;
20813         }
20814
20815         var dx = diffX || 0;
20816         var dy = diffY || 0;
20817
20818         var p = Dom.getXY( el );
20819
20820         this.initPageX = p[0] - dx;
20821         this.initPageY = p[1] - dy;
20822
20823         this.lastPageX = p[0];
20824         this.lastPageY = p[1];
20825
20826
20827         this.setStartPosition(p);
20828     },
20829
20830     /**
20831      * Sets the start position of the element.  This is set when the obj
20832      * is initialized, the reset when a drag is started.
20833      * @method setStartPosition
20834      * @param pos current position (from previous lookup)
20835      * @private
20836      */
20837     setStartPosition: function(pos) {
20838         var p = pos || Dom.getXY( this.getEl() );
20839         this.deltaSetXY = null;
20840
20841         this.startPageX = p[0];
20842         this.startPageY = p[1];
20843     },
20844
20845     /**
20846      * Add this instance to a group of related drag/drop objects.  All
20847      * instances belong to at least one group, and can belong to as many
20848      * groups as needed.
20849      * @method addToGroup
20850      * @param sGroup {string} the name of the group
20851      */
20852     addToGroup: function(sGroup) {
20853         this.groups[sGroup] = true;
20854         this.DDM.regDragDrop(this, sGroup);
20855     },
20856
20857     /**
20858      * Remove's this instance from the supplied interaction group
20859      * @method removeFromGroup
20860      * @param {string}  sGroup  The group to drop
20861      */
20862     removeFromGroup: function(sGroup) {
20863         if (this.groups[sGroup]) {
20864             delete this.groups[sGroup];
20865         }
20866
20867         this.DDM.removeDDFromGroup(this, sGroup);
20868     },
20869
20870     /**
20871      * Allows you to specify that an element other than the linked element
20872      * will be moved with the cursor during a drag
20873      * @method setDragElId
20874      * @param id {string} the id of the element that will be used to initiate the drag
20875      */
20876     setDragElId: function(id) {
20877         this.dragElId = id;
20878     },
20879
20880     /**
20881      * Allows you to specify a child of the linked element that should be
20882      * used to initiate the drag operation.  An example of this would be if
20883      * you have a content div with text and links.  Clicking anywhere in the
20884      * content area would normally start the drag operation.  Use this method
20885      * to specify that an element inside of the content div is the element
20886      * that starts the drag operation.
20887      * @method setHandleElId
20888      * @param id {string} the id of the element that will be used to
20889      * initiate the drag.
20890      */
20891     setHandleElId: function(id) {
20892         if (typeof id !== "string") {
20893             id = Roo.id(id);
20894         }
20895         this.handleElId = id;
20896         this.DDM.regHandle(this.id, id);
20897     },
20898
20899     /**
20900      * Allows you to set an element outside of the linked element as a drag
20901      * handle
20902      * @method setOuterHandleElId
20903      * @param id the id of the element that will be used to initiate the drag
20904      */
20905     setOuterHandleElId: function(id) {
20906         if (typeof id !== "string") {
20907             id = Roo.id(id);
20908         }
20909         Event.on(id, "mousedown",
20910                 this.handleMouseDown, this);
20911         this.setHandleElId(id);
20912
20913         this.hasOuterHandles = true;
20914     },
20915
20916     /**
20917      * Remove all drag and drop hooks for this element
20918      * @method unreg
20919      */
20920     unreg: function() {
20921         Event.un(this.id, "mousedown",
20922                 this.handleMouseDown);
20923         Event.un(this.id, "touchstart",
20924                 this.handleMouseDown);
20925         this._domRef = null;
20926         this.DDM._remove(this);
20927     },
20928
20929     destroy : function(){
20930         this.unreg();
20931     },
20932
20933     /**
20934      * Returns true if this instance is locked, or the drag drop mgr is locked
20935      * (meaning that all drag/drop is disabled on the page.)
20936      * @method isLocked
20937      * @return {boolean} true if this obj or all drag/drop is locked, else
20938      * false
20939      */
20940     isLocked: function() {
20941         return (this.DDM.isLocked() || this.locked);
20942     },
20943
20944     /**
20945      * Fired when this object is clicked
20946      * @method handleMouseDown
20947      * @param {Event} e
20948      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20949      * @private
20950      */
20951     handleMouseDown: function(e, oDD){
20952      
20953         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20954             //Roo.log('not touch/ button !=0');
20955             return;
20956         }
20957         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20958             return; // double touch..
20959         }
20960         
20961
20962         if (this.isLocked()) {
20963             //Roo.log('locked');
20964             return;
20965         }
20966
20967         this.DDM.refreshCache(this.groups);
20968 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20969         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20970         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20971             //Roo.log('no outer handes or not over target');
20972                 // do nothing.
20973         } else {
20974 //            Roo.log('check validator');
20975             if (this.clickValidator(e)) {
20976 //                Roo.log('validate success');
20977                 // set the initial element position
20978                 this.setStartPosition();
20979
20980
20981                 this.b4MouseDown(e);
20982                 this.onMouseDown(e);
20983
20984                 this.DDM.handleMouseDown(e, this);
20985
20986                 this.DDM.stopEvent(e);
20987             } else {
20988
20989
20990             }
20991         }
20992     },
20993
20994     clickValidator: function(e) {
20995         var target = e.getTarget();
20996         return ( this.isValidHandleChild(target) &&
20997                     (this.id == this.handleElId ||
20998                         this.DDM.handleWasClicked(target, this.id)) );
20999     },
21000
21001     /**
21002      * Allows you to specify a tag name that should not start a drag operation
21003      * when clicked.  This is designed to facilitate embedding links within a
21004      * drag handle that do something other than start the drag.
21005      * @method addInvalidHandleType
21006      * @param {string} tagName the type of element to exclude
21007      */
21008     addInvalidHandleType: function(tagName) {
21009         var type = tagName.toUpperCase();
21010         this.invalidHandleTypes[type] = type;
21011     },
21012
21013     /**
21014      * Lets you to specify an element id for a child of a drag handle
21015      * that should not initiate a drag
21016      * @method addInvalidHandleId
21017      * @param {string} id the element id of the element you wish to ignore
21018      */
21019     addInvalidHandleId: function(id) {
21020         if (typeof id !== "string") {
21021             id = Roo.id(id);
21022         }
21023         this.invalidHandleIds[id] = id;
21024     },
21025
21026     /**
21027      * Lets you specify a css class of elements that will not initiate a drag
21028      * @method addInvalidHandleClass
21029      * @param {string} cssClass the class of the elements you wish to ignore
21030      */
21031     addInvalidHandleClass: function(cssClass) {
21032         this.invalidHandleClasses.push(cssClass);
21033     },
21034
21035     /**
21036      * Unsets an excluded tag name set by addInvalidHandleType
21037      * @method removeInvalidHandleType
21038      * @param {string} tagName the type of element to unexclude
21039      */
21040     removeInvalidHandleType: function(tagName) {
21041         var type = tagName.toUpperCase();
21042         // this.invalidHandleTypes[type] = null;
21043         delete this.invalidHandleTypes[type];
21044     },
21045
21046     /**
21047      * Unsets an invalid handle id
21048      * @method removeInvalidHandleId
21049      * @param {string} id the id of the element to re-enable
21050      */
21051     removeInvalidHandleId: function(id) {
21052         if (typeof id !== "string") {
21053             id = Roo.id(id);
21054         }
21055         delete this.invalidHandleIds[id];
21056     },
21057
21058     /**
21059      * Unsets an invalid css class
21060      * @method removeInvalidHandleClass
21061      * @param {string} cssClass the class of the element(s) you wish to
21062      * re-enable
21063      */
21064     removeInvalidHandleClass: function(cssClass) {
21065         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21066             if (this.invalidHandleClasses[i] == cssClass) {
21067                 delete this.invalidHandleClasses[i];
21068             }
21069         }
21070     },
21071
21072     /**
21073      * Checks the tag exclusion list to see if this click should be ignored
21074      * @method isValidHandleChild
21075      * @param {HTMLElement} node the HTMLElement to evaluate
21076      * @return {boolean} true if this is a valid tag type, false if not
21077      */
21078     isValidHandleChild: function(node) {
21079
21080         var valid = true;
21081         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21082         var nodeName;
21083         try {
21084             nodeName = node.nodeName.toUpperCase();
21085         } catch(e) {
21086             nodeName = node.nodeName;
21087         }
21088         valid = valid && !this.invalidHandleTypes[nodeName];
21089         valid = valid && !this.invalidHandleIds[node.id];
21090
21091         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21092             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21093         }
21094
21095
21096         return valid;
21097
21098     },
21099
21100     /**
21101      * Create the array of horizontal tick marks if an interval was specified
21102      * in setXConstraint().
21103      * @method setXTicks
21104      * @private
21105      */
21106     setXTicks: function(iStartX, iTickSize) {
21107         this.xTicks = [];
21108         this.xTickSize = iTickSize;
21109
21110         var tickMap = {};
21111
21112         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21113             if (!tickMap[i]) {
21114                 this.xTicks[this.xTicks.length] = i;
21115                 tickMap[i] = true;
21116             }
21117         }
21118
21119         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21120             if (!tickMap[i]) {
21121                 this.xTicks[this.xTicks.length] = i;
21122                 tickMap[i] = true;
21123             }
21124         }
21125
21126         this.xTicks.sort(this.DDM.numericSort) ;
21127     },
21128
21129     /**
21130      * Create the array of vertical tick marks if an interval was specified in
21131      * setYConstraint().
21132      * @method setYTicks
21133      * @private
21134      */
21135     setYTicks: function(iStartY, iTickSize) {
21136         this.yTicks = [];
21137         this.yTickSize = iTickSize;
21138
21139         var tickMap = {};
21140
21141         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21142             if (!tickMap[i]) {
21143                 this.yTicks[this.yTicks.length] = i;
21144                 tickMap[i] = true;
21145             }
21146         }
21147
21148         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21149             if (!tickMap[i]) {
21150                 this.yTicks[this.yTicks.length] = i;
21151                 tickMap[i] = true;
21152             }
21153         }
21154
21155         this.yTicks.sort(this.DDM.numericSort) ;
21156     },
21157
21158     /**
21159      * By default, the element can be dragged any place on the screen.  Use
21160      * this method to limit the horizontal travel of the element.  Pass in
21161      * 0,0 for the parameters if you want to lock the drag to the y axis.
21162      * @method setXConstraint
21163      * @param {int} iLeft the number of pixels the element can move to the left
21164      * @param {int} iRight the number of pixels the element can move to the
21165      * right
21166      * @param {int} iTickSize optional parameter for specifying that the
21167      * element
21168      * should move iTickSize pixels at a time.
21169      */
21170     setXConstraint: function(iLeft, iRight, iTickSize) {
21171         this.leftConstraint = iLeft;
21172         this.rightConstraint = iRight;
21173
21174         this.minX = this.initPageX - iLeft;
21175         this.maxX = this.initPageX + iRight;
21176         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21177
21178         this.constrainX = true;
21179     },
21180
21181     /**
21182      * Clears any constraints applied to this instance.  Also clears ticks
21183      * since they can't exist independent of a constraint at this time.
21184      * @method clearConstraints
21185      */
21186     clearConstraints: function() {
21187         this.constrainX = false;
21188         this.constrainY = false;
21189         this.clearTicks();
21190     },
21191
21192     /**
21193      * Clears any tick interval defined for this instance
21194      * @method clearTicks
21195      */
21196     clearTicks: function() {
21197         this.xTicks = null;
21198         this.yTicks = null;
21199         this.xTickSize = 0;
21200         this.yTickSize = 0;
21201     },
21202
21203     /**
21204      * By default, the element can be dragged any place on the screen.  Set
21205      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21206      * parameters if you want to lock the drag to the x axis.
21207      * @method setYConstraint
21208      * @param {int} iUp the number of pixels the element can move up
21209      * @param {int} iDown the number of pixels the element can move down
21210      * @param {int} iTickSize optional parameter for specifying that the
21211      * element should move iTickSize pixels at a time.
21212      */
21213     setYConstraint: function(iUp, iDown, iTickSize) {
21214         this.topConstraint = iUp;
21215         this.bottomConstraint = iDown;
21216
21217         this.minY = this.initPageY - iUp;
21218         this.maxY = this.initPageY + iDown;
21219         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21220
21221         this.constrainY = true;
21222
21223     },
21224
21225     /**
21226      * resetConstraints must be called if you manually reposition a dd element.
21227      * @method resetConstraints
21228      * @param {boolean} maintainOffset
21229      */
21230     resetConstraints: function() {
21231
21232
21233         // Maintain offsets if necessary
21234         if (this.initPageX || this.initPageX === 0) {
21235             // figure out how much this thing has moved
21236             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21237             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21238
21239             this.setInitPosition(dx, dy);
21240
21241         // This is the first time we have detected the element's position
21242         } else {
21243             this.setInitPosition();
21244         }
21245
21246         if (this.constrainX) {
21247             this.setXConstraint( this.leftConstraint,
21248                                  this.rightConstraint,
21249                                  this.xTickSize        );
21250         }
21251
21252         if (this.constrainY) {
21253             this.setYConstraint( this.topConstraint,
21254                                  this.bottomConstraint,
21255                                  this.yTickSize         );
21256         }
21257     },
21258
21259     /**
21260      * Normally the drag element is moved pixel by pixel, but we can specify
21261      * that it move a number of pixels at a time.  This method resolves the
21262      * location when we have it set up like this.
21263      * @method getTick
21264      * @param {int} val where we want to place the object
21265      * @param {int[]} tickArray sorted array of valid points
21266      * @return {int} the closest tick
21267      * @private
21268      */
21269     getTick: function(val, tickArray) {
21270
21271         if (!tickArray) {
21272             // If tick interval is not defined, it is effectively 1 pixel,
21273             // so we return the value passed to us.
21274             return val;
21275         } else if (tickArray[0] >= val) {
21276             // The value is lower than the first tick, so we return the first
21277             // tick.
21278             return tickArray[0];
21279         } else {
21280             for (var i=0, len=tickArray.length; i<len; ++i) {
21281                 var next = i + 1;
21282                 if (tickArray[next] && tickArray[next] >= val) {
21283                     var diff1 = val - tickArray[i];
21284                     var diff2 = tickArray[next] - val;
21285                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21286                 }
21287             }
21288
21289             // The value is larger than the last tick, so we return the last
21290             // tick.
21291             return tickArray[tickArray.length - 1];
21292         }
21293     },
21294
21295     /**
21296      * toString method
21297      * @method toString
21298      * @return {string} string representation of the dd obj
21299      */
21300     toString: function() {
21301         return ("DragDrop " + this.id);
21302     }
21303
21304 });
21305
21306 })();
21307 /*
21308  * Based on:
21309  * Ext JS Library 1.1.1
21310  * Copyright(c) 2006-2007, Ext JS, LLC.
21311  *
21312  * Originally Released Under LGPL - original licence link has changed is not relivant.
21313  *
21314  * Fork - LGPL
21315  * <script type="text/javascript">
21316  */
21317
21318
21319 /**
21320  * The drag and drop utility provides a framework for building drag and drop
21321  * applications.  In addition to enabling drag and drop for specific elements,
21322  * the drag and drop elements are tracked by the manager class, and the
21323  * interactions between the various elements are tracked during the drag and
21324  * the implementing code is notified about these important moments.
21325  */
21326
21327 // Only load the library once.  Rewriting the manager class would orphan
21328 // existing drag and drop instances.
21329 if (!Roo.dd.DragDropMgr) {
21330
21331 /**
21332  * @class Roo.dd.DragDropMgr
21333  * DragDropMgr is a singleton that tracks the element interaction for
21334  * all DragDrop items in the window.  Generally, you will not call
21335  * this class directly, but it does have helper methods that could
21336  * be useful in your DragDrop implementations.
21337  * @static
21338  */
21339 Roo.dd.DragDropMgr = function() {
21340
21341     var Event = Roo.EventManager;
21342
21343     return {
21344
21345         /**
21346          * Two dimensional Array of registered DragDrop objects.  The first
21347          * dimension is the DragDrop item group, the second the DragDrop
21348          * object.
21349          * @property ids
21350          * @type {string: string}
21351          * @private
21352          * @static
21353          */
21354         ids: {},
21355
21356         /**
21357          * Array of element ids defined as drag handles.  Used to determine
21358          * if the element that generated the mousedown event is actually the
21359          * handle and not the html element itself.
21360          * @property handleIds
21361          * @type {string: string}
21362          * @private
21363          * @static
21364          */
21365         handleIds: {},
21366
21367         /**
21368          * the DragDrop object that is currently being dragged
21369          * @property dragCurrent
21370          * @type DragDrop
21371          * @private
21372          * @static
21373          **/
21374         dragCurrent: null,
21375
21376         /**
21377          * the DragDrop object(s) that are being hovered over
21378          * @property dragOvers
21379          * @type Array
21380          * @private
21381          * @static
21382          */
21383         dragOvers: {},
21384
21385         /**
21386          * the X distance between the cursor and the object being dragged
21387          * @property deltaX
21388          * @type int
21389          * @private
21390          * @static
21391          */
21392         deltaX: 0,
21393
21394         /**
21395          * the Y distance between the cursor and the object being dragged
21396          * @property deltaY
21397          * @type int
21398          * @private
21399          * @static
21400          */
21401         deltaY: 0,
21402
21403         /**
21404          * Flag to determine if we should prevent the default behavior of the
21405          * events we define. By default this is true, but this can be set to
21406          * false if you need the default behavior (not recommended)
21407          * @property preventDefault
21408          * @type boolean
21409          * @static
21410          */
21411         preventDefault: true,
21412
21413         /**
21414          * Flag to determine if we should stop the propagation of the events
21415          * we generate. This is true by default but you may want to set it to
21416          * false if the html element contains other features that require the
21417          * mouse click.
21418          * @property stopPropagation
21419          * @type boolean
21420          * @static
21421          */
21422         stopPropagation: true,
21423
21424         /**
21425          * Internal flag that is set to true when drag and drop has been
21426          * intialized
21427          * @property initialized
21428          * @private
21429          * @static
21430          */
21431         initalized: false,
21432
21433         /**
21434          * All drag and drop can be disabled.
21435          * @property locked
21436          * @private
21437          * @static
21438          */
21439         locked: false,
21440
21441         /**
21442          * Called the first time an element is registered.
21443          * @method init
21444          * @private
21445          * @static
21446          */
21447         init: function() {
21448             this.initialized = true;
21449         },
21450
21451         /**
21452          * In point mode, drag and drop interaction is defined by the
21453          * location of the cursor during the drag/drop
21454          * @property POINT
21455          * @type int
21456          * @static
21457          */
21458         POINT: 0,
21459
21460         /**
21461          * In intersect mode, drag and drop interactio nis defined by the
21462          * overlap of two or more drag and drop objects.
21463          * @property INTERSECT
21464          * @type int
21465          * @static
21466          */
21467         INTERSECT: 1,
21468
21469         /**
21470          * The current drag and drop mode.  Default: POINT
21471          * @property mode
21472          * @type int
21473          * @static
21474          */
21475         mode: 0,
21476
21477         /**
21478          * Runs method on all drag and drop objects
21479          * @method _execOnAll
21480          * @private
21481          * @static
21482          */
21483         _execOnAll: function(sMethod, args) {
21484             for (var i in this.ids) {
21485                 for (var j in this.ids[i]) {
21486                     var oDD = this.ids[i][j];
21487                     if (! this.isTypeOfDD(oDD)) {
21488                         continue;
21489                     }
21490                     oDD[sMethod].apply(oDD, args);
21491                 }
21492             }
21493         },
21494
21495         /**
21496          * Drag and drop initialization.  Sets up the global event handlers
21497          * @method _onLoad
21498          * @private
21499          * @static
21500          */
21501         _onLoad: function() {
21502
21503             this.init();
21504
21505             if (!Roo.isTouch) {
21506                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21507                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21508             }
21509             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21510             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21511             
21512             Event.on(window,   "unload",    this._onUnload, this, true);
21513             Event.on(window,   "resize",    this._onResize, this, true);
21514             // Event.on(window,   "mouseout",    this._test);
21515
21516         },
21517
21518         /**
21519          * Reset constraints on all drag and drop objs
21520          * @method _onResize
21521          * @private
21522          * @static
21523          */
21524         _onResize: function(e) {
21525             this._execOnAll("resetConstraints", []);
21526         },
21527
21528         /**
21529          * Lock all drag and drop functionality
21530          * @method lock
21531          * @static
21532          */
21533         lock: function() { this.locked = true; },
21534
21535         /**
21536          * Unlock all drag and drop functionality
21537          * @method unlock
21538          * @static
21539          */
21540         unlock: function() { this.locked = false; },
21541
21542         /**
21543          * Is drag and drop locked?
21544          * @method isLocked
21545          * @return {boolean} True if drag and drop is locked, false otherwise.
21546          * @static
21547          */
21548         isLocked: function() { return this.locked; },
21549
21550         /**
21551          * Location cache that is set for all drag drop objects when a drag is
21552          * initiated, cleared when the drag is finished.
21553          * @property locationCache
21554          * @private
21555          * @static
21556          */
21557         locationCache: {},
21558
21559         /**
21560          * Set useCache to false if you want to force object the lookup of each
21561          * drag and drop linked element constantly during a drag.
21562          * @property useCache
21563          * @type boolean
21564          * @static
21565          */
21566         useCache: true,
21567
21568         /**
21569          * The number of pixels that the mouse needs to move after the
21570          * mousedown before the drag is initiated.  Default=3;
21571          * @property clickPixelThresh
21572          * @type int
21573          * @static
21574          */
21575         clickPixelThresh: 3,
21576
21577         /**
21578          * The number of milliseconds after the mousedown event to initiate the
21579          * drag if we don't get a mouseup event. Default=1000
21580          * @property clickTimeThresh
21581          * @type int
21582          * @static
21583          */
21584         clickTimeThresh: 350,
21585
21586         /**
21587          * Flag that indicates that either the drag pixel threshold or the
21588          * mousdown time threshold has been met
21589          * @property dragThreshMet
21590          * @type boolean
21591          * @private
21592          * @static
21593          */
21594         dragThreshMet: false,
21595
21596         /**
21597          * Timeout used for the click time threshold
21598          * @property clickTimeout
21599          * @type Object
21600          * @private
21601          * @static
21602          */
21603         clickTimeout: null,
21604
21605         /**
21606          * The X position of the mousedown event stored for later use when a
21607          * drag threshold is met.
21608          * @property startX
21609          * @type int
21610          * @private
21611          * @static
21612          */
21613         startX: 0,
21614
21615         /**
21616          * The Y position of the mousedown event stored for later use when a
21617          * drag threshold is met.
21618          * @property startY
21619          * @type int
21620          * @private
21621          * @static
21622          */
21623         startY: 0,
21624
21625         /**
21626          * Each DragDrop instance must be registered with the DragDropMgr.
21627          * This is executed in DragDrop.init()
21628          * @method regDragDrop
21629          * @param {DragDrop} oDD the DragDrop object to register
21630          * @param {String} sGroup the name of the group this element belongs to
21631          * @static
21632          */
21633         regDragDrop: function(oDD, sGroup) {
21634             if (!this.initialized) { this.init(); }
21635
21636             if (!this.ids[sGroup]) {
21637                 this.ids[sGroup] = {};
21638             }
21639             this.ids[sGroup][oDD.id] = oDD;
21640         },
21641
21642         /**
21643          * Removes the supplied dd instance from the supplied group. Executed
21644          * by DragDrop.removeFromGroup, so don't call this function directly.
21645          * @method removeDDFromGroup
21646          * @private
21647          * @static
21648          */
21649         removeDDFromGroup: function(oDD, sGroup) {
21650             if (!this.ids[sGroup]) {
21651                 this.ids[sGroup] = {};
21652             }
21653
21654             var obj = this.ids[sGroup];
21655             if (obj && obj[oDD.id]) {
21656                 delete obj[oDD.id];
21657             }
21658         },
21659
21660         /**
21661          * Unregisters a drag and drop item.  This is executed in
21662          * DragDrop.unreg, use that method instead of calling this directly.
21663          * @method _remove
21664          * @private
21665          * @static
21666          */
21667         _remove: function(oDD) {
21668             for (var g in oDD.groups) {
21669                 if (g && this.ids[g][oDD.id]) {
21670                     delete this.ids[g][oDD.id];
21671                 }
21672             }
21673             delete this.handleIds[oDD.id];
21674         },
21675
21676         /**
21677          * Each DragDrop handle element must be registered.  This is done
21678          * automatically when executing DragDrop.setHandleElId()
21679          * @method regHandle
21680          * @param {String} sDDId the DragDrop id this element is a handle for
21681          * @param {String} sHandleId the id of the element that is the drag
21682          * handle
21683          * @static
21684          */
21685         regHandle: function(sDDId, sHandleId) {
21686             if (!this.handleIds[sDDId]) {
21687                 this.handleIds[sDDId] = {};
21688             }
21689             this.handleIds[sDDId][sHandleId] = sHandleId;
21690         },
21691
21692         /**
21693          * Utility function to determine if a given element has been
21694          * registered as a drag drop item.
21695          * @method isDragDrop
21696          * @param {String} id the element id to check
21697          * @return {boolean} true if this element is a DragDrop item,
21698          * false otherwise
21699          * @static
21700          */
21701         isDragDrop: function(id) {
21702             return ( this.getDDById(id) ) ? true : false;
21703         },
21704
21705         /**
21706          * Returns the drag and drop instances that are in all groups the
21707          * passed in instance belongs to.
21708          * @method getRelated
21709          * @param {DragDrop} p_oDD the obj to get related data for
21710          * @param {boolean} bTargetsOnly if true, only return targetable objs
21711          * @return {DragDrop[]} the related instances
21712          * @static
21713          */
21714         getRelated: function(p_oDD, bTargetsOnly) {
21715             var oDDs = [];
21716             for (var i in p_oDD.groups) {
21717                 for (j in this.ids[i]) {
21718                     var dd = this.ids[i][j];
21719                     if (! this.isTypeOfDD(dd)) {
21720                         continue;
21721                     }
21722                     if (!bTargetsOnly || dd.isTarget) {
21723                         oDDs[oDDs.length] = dd;
21724                     }
21725                 }
21726             }
21727
21728             return oDDs;
21729         },
21730
21731         /**
21732          * Returns true if the specified dd target is a legal target for
21733          * the specifice drag obj
21734          * @method isLegalTarget
21735          * @param {DragDrop} the drag obj
21736          * @param {DragDrop} the target
21737          * @return {boolean} true if the target is a legal target for the
21738          * dd obj
21739          * @static
21740          */
21741         isLegalTarget: function (oDD, oTargetDD) {
21742             var targets = this.getRelated(oDD, true);
21743             for (var i=0, len=targets.length;i<len;++i) {
21744                 if (targets[i].id == oTargetDD.id) {
21745                     return true;
21746                 }
21747             }
21748
21749             return false;
21750         },
21751
21752         /**
21753          * My goal is to be able to transparently determine if an object is
21754          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21755          * returns "object", oDD.constructor.toString() always returns
21756          * "DragDrop" and not the name of the subclass.  So for now it just
21757          * evaluates a well-known variable in DragDrop.
21758          * @method isTypeOfDD
21759          * @param {Object} the object to evaluate
21760          * @return {boolean} true if typeof oDD = DragDrop
21761          * @static
21762          */
21763         isTypeOfDD: function (oDD) {
21764             return (oDD && oDD.__ygDragDrop);
21765         },
21766
21767         /**
21768          * Utility function to determine if a given element has been
21769          * registered as a drag drop handle for the given Drag Drop object.
21770          * @method isHandle
21771          * @param {String} id the element id to check
21772          * @return {boolean} true if this element is a DragDrop handle, false
21773          * otherwise
21774          * @static
21775          */
21776         isHandle: function(sDDId, sHandleId) {
21777             return ( this.handleIds[sDDId] &&
21778                             this.handleIds[sDDId][sHandleId] );
21779         },
21780
21781         /**
21782          * Returns the DragDrop instance for a given id
21783          * @method getDDById
21784          * @param {String} id the id of the DragDrop object
21785          * @return {DragDrop} the drag drop object, null if it is not found
21786          * @static
21787          */
21788         getDDById: function(id) {
21789             for (var i in this.ids) {
21790                 if (this.ids[i][id]) {
21791                     return this.ids[i][id];
21792                 }
21793             }
21794             return null;
21795         },
21796
21797         /**
21798          * Fired after a registered DragDrop object gets the mousedown event.
21799          * Sets up the events required to track the object being dragged
21800          * @method handleMouseDown
21801          * @param {Event} e the event
21802          * @param oDD the DragDrop object being dragged
21803          * @private
21804          * @static
21805          */
21806         handleMouseDown: function(e, oDD) {
21807             if(Roo.QuickTips){
21808                 Roo.QuickTips.disable();
21809             }
21810             this.currentTarget = e.getTarget();
21811
21812             this.dragCurrent = oDD;
21813
21814             var el = oDD.getEl();
21815
21816             // track start position
21817             this.startX = e.getPageX();
21818             this.startY = e.getPageY();
21819
21820             this.deltaX = this.startX - el.offsetLeft;
21821             this.deltaY = this.startY - el.offsetTop;
21822
21823             this.dragThreshMet = false;
21824
21825             this.clickTimeout = setTimeout(
21826                     function() {
21827                         var DDM = Roo.dd.DDM;
21828                         DDM.startDrag(DDM.startX, DDM.startY);
21829                     },
21830                     this.clickTimeThresh );
21831         },
21832
21833         /**
21834          * Fired when either the drag pixel threshol or the mousedown hold
21835          * time threshold has been met.
21836          * @method startDrag
21837          * @param x {int} the X position of the original mousedown
21838          * @param y {int} the Y position of the original mousedown
21839          * @static
21840          */
21841         startDrag: function(x, y) {
21842             clearTimeout(this.clickTimeout);
21843             if (this.dragCurrent) {
21844                 this.dragCurrent.b4StartDrag(x, y);
21845                 this.dragCurrent.startDrag(x, y);
21846             }
21847             this.dragThreshMet = true;
21848         },
21849
21850         /**
21851          * Internal function to handle the mouseup event.  Will be invoked
21852          * from the context of the document.
21853          * @method handleMouseUp
21854          * @param {Event} e the event
21855          * @private
21856          * @static
21857          */
21858         handleMouseUp: function(e) {
21859
21860             if(Roo.QuickTips){
21861                 Roo.QuickTips.enable();
21862             }
21863             if (! this.dragCurrent) {
21864                 return;
21865             }
21866
21867             clearTimeout(this.clickTimeout);
21868
21869             if (this.dragThreshMet) {
21870                 this.fireEvents(e, true);
21871             } else {
21872             }
21873
21874             this.stopDrag(e);
21875
21876             this.stopEvent(e);
21877         },
21878
21879         /**
21880          * Utility to stop event propagation and event default, if these
21881          * features are turned on.
21882          * @method stopEvent
21883          * @param {Event} e the event as returned by this.getEvent()
21884          * @static
21885          */
21886         stopEvent: function(e){
21887             if(this.stopPropagation) {
21888                 e.stopPropagation();
21889             }
21890
21891             if (this.preventDefault) {
21892                 e.preventDefault();
21893             }
21894         },
21895
21896         /**
21897          * Internal function to clean up event handlers after the drag
21898          * operation is complete
21899          * @method stopDrag
21900          * @param {Event} e the event
21901          * @private
21902          * @static
21903          */
21904         stopDrag: function(e) {
21905             // Fire the drag end event for the item that was dragged
21906             if (this.dragCurrent) {
21907                 if (this.dragThreshMet) {
21908                     this.dragCurrent.b4EndDrag(e);
21909                     this.dragCurrent.endDrag(e);
21910                 }
21911
21912                 this.dragCurrent.onMouseUp(e);
21913             }
21914
21915             this.dragCurrent = null;
21916             this.dragOvers = {};
21917         },
21918
21919         /**
21920          * Internal function to handle the mousemove event.  Will be invoked
21921          * from the context of the html element.
21922          *
21923          * @TODO figure out what we can do about mouse events lost when the
21924          * user drags objects beyond the window boundary.  Currently we can
21925          * detect this in internet explorer by verifying that the mouse is
21926          * down during the mousemove event.  Firefox doesn't give us the
21927          * button state on the mousemove event.
21928          * @method handleMouseMove
21929          * @param {Event} e the event
21930          * @private
21931          * @static
21932          */
21933         handleMouseMove: function(e) {
21934             if (! this.dragCurrent) {
21935                 return true;
21936             }
21937
21938             // var button = e.which || e.button;
21939
21940             // check for IE mouseup outside of page boundary
21941             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21942                 this.stopEvent(e);
21943                 return this.handleMouseUp(e);
21944             }
21945
21946             if (!this.dragThreshMet) {
21947                 var diffX = Math.abs(this.startX - e.getPageX());
21948                 var diffY = Math.abs(this.startY - e.getPageY());
21949                 if (diffX > this.clickPixelThresh ||
21950                             diffY > this.clickPixelThresh) {
21951                     this.startDrag(this.startX, this.startY);
21952                 }
21953             }
21954
21955             if (this.dragThreshMet) {
21956                 this.dragCurrent.b4Drag(e);
21957                 this.dragCurrent.onDrag(e);
21958                 if(!this.dragCurrent.moveOnly){
21959                     this.fireEvents(e, false);
21960                 }
21961             }
21962
21963             this.stopEvent(e);
21964
21965             return true;
21966         },
21967
21968         /**
21969          * Iterates over all of the DragDrop elements to find ones we are
21970          * hovering over or dropping on
21971          * @method fireEvents
21972          * @param {Event} e the event
21973          * @param {boolean} isDrop is this a drop op or a mouseover op?
21974          * @private
21975          * @static
21976          */
21977         fireEvents: function(e, isDrop) {
21978             var dc = this.dragCurrent;
21979
21980             // If the user did the mouse up outside of the window, we could
21981             // get here even though we have ended the drag.
21982             if (!dc || dc.isLocked()) {
21983                 return;
21984             }
21985
21986             var pt = e.getPoint();
21987
21988             // cache the previous dragOver array
21989             var oldOvers = [];
21990
21991             var outEvts   = [];
21992             var overEvts  = [];
21993             var dropEvts  = [];
21994             var enterEvts = [];
21995
21996             // Check to see if the object(s) we were hovering over is no longer
21997             // being hovered over so we can fire the onDragOut event
21998             for (var i in this.dragOvers) {
21999
22000                 var ddo = this.dragOvers[i];
22001
22002                 if (! this.isTypeOfDD(ddo)) {
22003                     continue;
22004                 }
22005
22006                 if (! this.isOverTarget(pt, ddo, this.mode)) {
22007                     outEvts.push( ddo );
22008                 }
22009
22010                 oldOvers[i] = true;
22011                 delete this.dragOvers[i];
22012             }
22013
22014             for (var sGroup in dc.groups) {
22015
22016                 if ("string" != typeof sGroup) {
22017                     continue;
22018                 }
22019
22020                 for (i in this.ids[sGroup]) {
22021                     var oDD = this.ids[sGroup][i];
22022                     if (! this.isTypeOfDD(oDD)) {
22023                         continue;
22024                     }
22025
22026                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22027                         if (this.isOverTarget(pt, oDD, this.mode)) {
22028                             // look for drop interactions
22029                             if (isDrop) {
22030                                 dropEvts.push( oDD );
22031                             // look for drag enter and drag over interactions
22032                             } else {
22033
22034                                 // initial drag over: dragEnter fires
22035                                 if (!oldOvers[oDD.id]) {
22036                                     enterEvts.push( oDD );
22037                                 // subsequent drag overs: dragOver fires
22038                                 } else {
22039                                     overEvts.push( oDD );
22040                                 }
22041
22042                                 this.dragOvers[oDD.id] = oDD;
22043                             }
22044                         }
22045                     }
22046                 }
22047             }
22048
22049             if (this.mode) {
22050                 if (outEvts.length) {
22051                     dc.b4DragOut(e, outEvts);
22052                     dc.onDragOut(e, outEvts);
22053                 }
22054
22055                 if (enterEvts.length) {
22056                     dc.onDragEnter(e, enterEvts);
22057                 }
22058
22059                 if (overEvts.length) {
22060                     dc.b4DragOver(e, overEvts);
22061                     dc.onDragOver(e, overEvts);
22062                 }
22063
22064                 if (dropEvts.length) {
22065                     dc.b4DragDrop(e, dropEvts);
22066                     dc.onDragDrop(e, dropEvts);
22067                 }
22068
22069             } else {
22070                 // fire dragout events
22071                 var len = 0;
22072                 for (i=0, len=outEvts.length; i<len; ++i) {
22073                     dc.b4DragOut(e, outEvts[i].id);
22074                     dc.onDragOut(e, outEvts[i].id);
22075                 }
22076
22077                 // fire enter events
22078                 for (i=0,len=enterEvts.length; i<len; ++i) {
22079                     // dc.b4DragEnter(e, oDD.id);
22080                     dc.onDragEnter(e, enterEvts[i].id);
22081                 }
22082
22083                 // fire over events
22084                 for (i=0,len=overEvts.length; i<len; ++i) {
22085                     dc.b4DragOver(e, overEvts[i].id);
22086                     dc.onDragOver(e, overEvts[i].id);
22087                 }
22088
22089                 // fire drop events
22090                 for (i=0, len=dropEvts.length; i<len; ++i) {
22091                     dc.b4DragDrop(e, dropEvts[i].id);
22092                     dc.onDragDrop(e, dropEvts[i].id);
22093                 }
22094
22095             }
22096
22097             // notify about a drop that did not find a target
22098             if (isDrop && !dropEvts.length) {
22099                 dc.onInvalidDrop(e);
22100             }
22101
22102         },
22103
22104         /**
22105          * Helper function for getting the best match from the list of drag
22106          * and drop objects returned by the drag and drop events when we are
22107          * in INTERSECT mode.  It returns either the first object that the
22108          * cursor is over, or the object that has the greatest overlap with
22109          * the dragged element.
22110          * @method getBestMatch
22111          * @param  {DragDrop[]} dds The array of drag and drop objects
22112          * targeted
22113          * @return {DragDrop}       The best single match
22114          * @static
22115          */
22116         getBestMatch: function(dds) {
22117             var winner = null;
22118             // Return null if the input is not what we expect
22119             //if (!dds || !dds.length || dds.length == 0) {
22120                // winner = null;
22121             // If there is only one item, it wins
22122             //} else if (dds.length == 1) {
22123
22124             var len = dds.length;
22125
22126             if (len == 1) {
22127                 winner = dds[0];
22128             } else {
22129                 // Loop through the targeted items
22130                 for (var i=0; i<len; ++i) {
22131                     var dd = dds[i];
22132                     // If the cursor is over the object, it wins.  If the
22133                     // cursor is over multiple matches, the first one we come
22134                     // to wins.
22135                     if (dd.cursorIsOver) {
22136                         winner = dd;
22137                         break;
22138                     // Otherwise the object with the most overlap wins
22139                     } else {
22140                         if (!winner ||
22141                             winner.overlap.getArea() < dd.overlap.getArea()) {
22142                             winner = dd;
22143                         }
22144                     }
22145                 }
22146             }
22147
22148             return winner;
22149         },
22150
22151         /**
22152          * Refreshes the cache of the top-left and bottom-right points of the
22153          * drag and drop objects in the specified group(s).  This is in the
22154          * format that is stored in the drag and drop instance, so typical
22155          * usage is:
22156          * <code>
22157          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22158          * </code>
22159          * Alternatively:
22160          * <code>
22161          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22162          * </code>
22163          * @TODO this really should be an indexed array.  Alternatively this
22164          * method could accept both.
22165          * @method refreshCache
22166          * @param {Object} groups an associative array of groups to refresh
22167          * @static
22168          */
22169         refreshCache: function(groups) {
22170             for (var sGroup in groups) {
22171                 if ("string" != typeof sGroup) {
22172                     continue;
22173                 }
22174                 for (var i in this.ids[sGroup]) {
22175                     var oDD = this.ids[sGroup][i];
22176
22177                     if (this.isTypeOfDD(oDD)) {
22178                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22179                         var loc = this.getLocation(oDD);
22180                         if (loc) {
22181                             this.locationCache[oDD.id] = loc;
22182                         } else {
22183                             delete this.locationCache[oDD.id];
22184                             // this will unregister the drag and drop object if
22185                             // the element is not in a usable state
22186                             // oDD.unreg();
22187                         }
22188                     }
22189                 }
22190             }
22191         },
22192
22193         /**
22194          * This checks to make sure an element exists and is in the DOM.  The
22195          * main purpose is to handle cases where innerHTML is used to remove
22196          * drag and drop objects from the DOM.  IE provides an 'unspecified
22197          * error' when trying to access the offsetParent of such an element
22198          * @method verifyEl
22199          * @param {HTMLElement} el the element to check
22200          * @return {boolean} true if the element looks usable
22201          * @static
22202          */
22203         verifyEl: function(el) {
22204             if (el) {
22205                 var parent;
22206                 if(Roo.isIE){
22207                     try{
22208                         parent = el.offsetParent;
22209                     }catch(e){}
22210                 }else{
22211                     parent = el.offsetParent;
22212                 }
22213                 if (parent) {
22214                     return true;
22215                 }
22216             }
22217
22218             return false;
22219         },
22220
22221         /**
22222          * Returns a Region object containing the drag and drop element's position
22223          * and size, including the padding configured for it
22224          * @method getLocation
22225          * @param {DragDrop} oDD the drag and drop object to get the
22226          *                       location for
22227          * @return {Roo.lib.Region} a Region object representing the total area
22228          *                             the element occupies, including any padding
22229          *                             the instance is configured for.
22230          * @static
22231          */
22232         getLocation: function(oDD) {
22233             if (! this.isTypeOfDD(oDD)) {
22234                 return null;
22235             }
22236
22237             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22238
22239             try {
22240                 pos= Roo.lib.Dom.getXY(el);
22241             } catch (e) { }
22242
22243             if (!pos) {
22244                 return null;
22245             }
22246
22247             x1 = pos[0];
22248             x2 = x1 + el.offsetWidth;
22249             y1 = pos[1];
22250             y2 = y1 + el.offsetHeight;
22251
22252             t = y1 - oDD.padding[0];
22253             r = x2 + oDD.padding[1];
22254             b = y2 + oDD.padding[2];
22255             l = x1 - oDD.padding[3];
22256
22257             return new Roo.lib.Region( t, r, b, l );
22258         },
22259
22260         /**
22261          * Checks the cursor location to see if it over the target
22262          * @method isOverTarget
22263          * @param {Roo.lib.Point} pt The point to evaluate
22264          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22265          * @return {boolean} true if the mouse is over the target
22266          * @private
22267          * @static
22268          */
22269         isOverTarget: function(pt, oTarget, intersect) {
22270             // use cache if available
22271             var loc = this.locationCache[oTarget.id];
22272             if (!loc || !this.useCache) {
22273                 loc = this.getLocation(oTarget);
22274                 this.locationCache[oTarget.id] = loc;
22275
22276             }
22277
22278             if (!loc) {
22279                 return false;
22280             }
22281
22282             oTarget.cursorIsOver = loc.contains( pt );
22283
22284             // DragDrop is using this as a sanity check for the initial mousedown
22285             // in this case we are done.  In POINT mode, if the drag obj has no
22286             // contraints, we are also done. Otherwise we need to evaluate the
22287             // location of the target as related to the actual location of the
22288             // dragged element.
22289             var dc = this.dragCurrent;
22290             if (!dc || !dc.getTargetCoord ||
22291                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22292                 return oTarget.cursorIsOver;
22293             }
22294
22295             oTarget.overlap = null;
22296
22297             // Get the current location of the drag element, this is the
22298             // location of the mouse event less the delta that represents
22299             // where the original mousedown happened on the element.  We
22300             // need to consider constraints and ticks as well.
22301             var pos = dc.getTargetCoord(pt.x, pt.y);
22302
22303             var el = dc.getDragEl();
22304             var curRegion = new Roo.lib.Region( pos.y,
22305                                                    pos.x + el.offsetWidth,
22306                                                    pos.y + el.offsetHeight,
22307                                                    pos.x );
22308
22309             var overlap = curRegion.intersect(loc);
22310
22311             if (overlap) {
22312                 oTarget.overlap = overlap;
22313                 return (intersect) ? true : oTarget.cursorIsOver;
22314             } else {
22315                 return false;
22316             }
22317         },
22318
22319         /**
22320          * unload event handler
22321          * @method _onUnload
22322          * @private
22323          * @static
22324          */
22325         _onUnload: function(e, me) {
22326             Roo.dd.DragDropMgr.unregAll();
22327         },
22328
22329         /**
22330          * Cleans up the drag and drop events and objects.
22331          * @method unregAll
22332          * @private
22333          * @static
22334          */
22335         unregAll: function() {
22336
22337             if (this.dragCurrent) {
22338                 this.stopDrag();
22339                 this.dragCurrent = null;
22340             }
22341
22342             this._execOnAll("unreg", []);
22343
22344             for (i in this.elementCache) {
22345                 delete this.elementCache[i];
22346             }
22347
22348             this.elementCache = {};
22349             this.ids = {};
22350         },
22351
22352         /**
22353          * A cache of DOM elements
22354          * @property elementCache
22355          * @private
22356          * @static
22357          */
22358         elementCache: {},
22359
22360         /**
22361          * Get the wrapper for the DOM element specified
22362          * @method getElWrapper
22363          * @param {String} id the id of the element to get
22364          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22365          * @private
22366          * @deprecated This wrapper isn't that useful
22367          * @static
22368          */
22369         getElWrapper: function(id) {
22370             var oWrapper = this.elementCache[id];
22371             if (!oWrapper || !oWrapper.el) {
22372                 oWrapper = this.elementCache[id] =
22373                     new this.ElementWrapper(Roo.getDom(id));
22374             }
22375             return oWrapper;
22376         },
22377
22378         /**
22379          * Returns the actual DOM element
22380          * @method getElement
22381          * @param {String} id the id of the elment to get
22382          * @return {Object} The element
22383          * @deprecated use Roo.getDom instead
22384          * @static
22385          */
22386         getElement: function(id) {
22387             return Roo.getDom(id);
22388         },
22389
22390         /**
22391          * Returns the style property for the DOM element (i.e.,
22392          * document.getElById(id).style)
22393          * @method getCss
22394          * @param {String} id the id of the elment to get
22395          * @return {Object} The style property of the element
22396          * @deprecated use Roo.getDom instead
22397          * @static
22398          */
22399         getCss: function(id) {
22400             var el = Roo.getDom(id);
22401             return (el) ? el.style : null;
22402         },
22403
22404         /**
22405          * Inner class for cached elements
22406          * @class DragDropMgr.ElementWrapper
22407          * @for DragDropMgr
22408          * @private
22409          * @deprecated
22410          */
22411         ElementWrapper: function(el) {
22412                 /**
22413                  * The element
22414                  * @property el
22415                  */
22416                 this.el = el || null;
22417                 /**
22418                  * The element id
22419                  * @property id
22420                  */
22421                 this.id = this.el && el.id;
22422                 /**
22423                  * A reference to the style property
22424                  * @property css
22425                  */
22426                 this.css = this.el && el.style;
22427             },
22428
22429         /**
22430          * Returns the X position of an html element
22431          * @method getPosX
22432          * @param el the element for which to get the position
22433          * @return {int} the X coordinate
22434          * @for DragDropMgr
22435          * @deprecated use Roo.lib.Dom.getX instead
22436          * @static
22437          */
22438         getPosX: function(el) {
22439             return Roo.lib.Dom.getX(el);
22440         },
22441
22442         /**
22443          * Returns the Y position of an html element
22444          * @method getPosY
22445          * @param el the element for which to get the position
22446          * @return {int} the Y coordinate
22447          * @deprecated use Roo.lib.Dom.getY instead
22448          * @static
22449          */
22450         getPosY: function(el) {
22451             return Roo.lib.Dom.getY(el);
22452         },
22453
22454         /**
22455          * Swap two nodes.  In IE, we use the native method, for others we
22456          * emulate the IE behavior
22457          * @method swapNode
22458          * @param n1 the first node to swap
22459          * @param n2 the other node to swap
22460          * @static
22461          */
22462         swapNode: function(n1, n2) {
22463             if (n1.swapNode) {
22464                 n1.swapNode(n2);
22465             } else {
22466                 var p = n2.parentNode;
22467                 var s = n2.nextSibling;
22468
22469                 if (s == n1) {
22470                     p.insertBefore(n1, n2);
22471                 } else if (n2 == n1.nextSibling) {
22472                     p.insertBefore(n2, n1);
22473                 } else {
22474                     n1.parentNode.replaceChild(n2, n1);
22475                     p.insertBefore(n1, s);
22476                 }
22477             }
22478         },
22479
22480         /**
22481          * Returns the current scroll position
22482          * @method getScroll
22483          * @private
22484          * @static
22485          */
22486         getScroll: function () {
22487             var t, l, dde=document.documentElement, db=document.body;
22488             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22489                 t = dde.scrollTop;
22490                 l = dde.scrollLeft;
22491             } else if (db) {
22492                 t = db.scrollTop;
22493                 l = db.scrollLeft;
22494             } else {
22495
22496             }
22497             return { top: t, left: l };
22498         },
22499
22500         /**
22501          * Returns the specified element style property
22502          * @method getStyle
22503          * @param {HTMLElement} el          the element
22504          * @param {string}      styleProp   the style property
22505          * @return {string} The value of the style property
22506          * @deprecated use Roo.lib.Dom.getStyle
22507          * @static
22508          */
22509         getStyle: function(el, styleProp) {
22510             return Roo.fly(el).getStyle(styleProp);
22511         },
22512
22513         /**
22514          * Gets the scrollTop
22515          * @method getScrollTop
22516          * @return {int} the document's scrollTop
22517          * @static
22518          */
22519         getScrollTop: function () { return this.getScroll().top; },
22520
22521         /**
22522          * Gets the scrollLeft
22523          * @method getScrollLeft
22524          * @return {int} the document's scrollTop
22525          * @static
22526          */
22527         getScrollLeft: function () { return this.getScroll().left; },
22528
22529         /**
22530          * Sets the x/y position of an element to the location of the
22531          * target element.
22532          * @method moveToEl
22533          * @param {HTMLElement} moveEl      The element to move
22534          * @param {HTMLElement} targetEl    The position reference element
22535          * @static
22536          */
22537         moveToEl: function (moveEl, targetEl) {
22538             var aCoord = Roo.lib.Dom.getXY(targetEl);
22539             Roo.lib.Dom.setXY(moveEl, aCoord);
22540         },
22541
22542         /**
22543          * Numeric array sort function
22544          * @method numericSort
22545          * @static
22546          */
22547         numericSort: function(a, b) { return (a - b); },
22548
22549         /**
22550          * Internal counter
22551          * @property _timeoutCount
22552          * @private
22553          * @static
22554          */
22555         _timeoutCount: 0,
22556
22557         /**
22558          * Trying to make the load order less important.  Without this we get
22559          * an error if this file is loaded before the Event Utility.
22560          * @method _addListeners
22561          * @private
22562          * @static
22563          */
22564         _addListeners: function() {
22565             var DDM = Roo.dd.DDM;
22566             if ( Roo.lib.Event && document ) {
22567                 DDM._onLoad();
22568             } else {
22569                 if (DDM._timeoutCount > 2000) {
22570                 } else {
22571                     setTimeout(DDM._addListeners, 10);
22572                     if (document && document.body) {
22573                         DDM._timeoutCount += 1;
22574                     }
22575                 }
22576             }
22577         },
22578
22579         /**
22580          * Recursively searches the immediate parent and all child nodes for
22581          * the handle element in order to determine wheter or not it was
22582          * clicked.
22583          * @method handleWasClicked
22584          * @param node the html element to inspect
22585          * @static
22586          */
22587         handleWasClicked: function(node, id) {
22588             if (this.isHandle(id, node.id)) {
22589                 return true;
22590             } else {
22591                 // check to see if this is a text node child of the one we want
22592                 var p = node.parentNode;
22593
22594                 while (p) {
22595                     if (this.isHandle(id, p.id)) {
22596                         return true;
22597                     } else {
22598                         p = p.parentNode;
22599                     }
22600                 }
22601             }
22602
22603             return false;
22604         }
22605
22606     };
22607
22608 }();
22609
22610 // shorter alias, save a few bytes
22611 Roo.dd.DDM = Roo.dd.DragDropMgr;
22612 Roo.dd.DDM._addListeners();
22613
22614 }/*
22615  * Based on:
22616  * Ext JS Library 1.1.1
22617  * Copyright(c) 2006-2007, Ext JS, LLC.
22618  *
22619  * Originally Released Under LGPL - original licence link has changed is not relivant.
22620  *
22621  * Fork - LGPL
22622  * <script type="text/javascript">
22623  */
22624
22625 /**
22626  * @class Roo.dd.DD
22627  * A DragDrop implementation where the linked element follows the
22628  * mouse cursor during a drag.
22629  * @extends Roo.dd.DragDrop
22630  * @constructor
22631  * @param {String} id the id of the linked element
22632  * @param {String} sGroup the group of related DragDrop items
22633  * @param {object} config an object containing configurable attributes
22634  *                Valid properties for DD:
22635  *                    scroll
22636  */
22637 Roo.dd.DD = function(id, sGroup, config) {
22638     if (id) {
22639         this.init(id, sGroup, config);
22640     }
22641 };
22642
22643 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22644
22645     /**
22646      * When set to true, the utility automatically tries to scroll the browser
22647      * window wehn a drag and drop element is dragged near the viewport boundary.
22648      * Defaults to true.
22649      * @property scroll
22650      * @type boolean
22651      */
22652     scroll: true,
22653
22654     /**
22655      * Sets the pointer offset to the distance between the linked element's top
22656      * left corner and the location the element was clicked
22657      * @method autoOffset
22658      * @param {int} iPageX the X coordinate of the click
22659      * @param {int} iPageY the Y coordinate of the click
22660      */
22661     autoOffset: function(iPageX, iPageY) {
22662         var x = iPageX - this.startPageX;
22663         var y = iPageY - this.startPageY;
22664         this.setDelta(x, y);
22665     },
22666
22667     /**
22668      * Sets the pointer offset.  You can call this directly to force the
22669      * offset to be in a particular location (e.g., pass in 0,0 to set it
22670      * to the center of the object)
22671      * @method setDelta
22672      * @param {int} iDeltaX the distance from the left
22673      * @param {int} iDeltaY the distance from the top
22674      */
22675     setDelta: function(iDeltaX, iDeltaY) {
22676         this.deltaX = iDeltaX;
22677         this.deltaY = iDeltaY;
22678     },
22679
22680     /**
22681      * Sets the drag element to the location of the mousedown or click event,
22682      * maintaining the cursor location relative to the location on the element
22683      * that was clicked.  Override this if you want to place the element in a
22684      * location other than where the cursor is.
22685      * @method setDragElPos
22686      * @param {int} iPageX the X coordinate of the mousedown or drag event
22687      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22688      */
22689     setDragElPos: function(iPageX, iPageY) {
22690         // the first time we do this, we are going to check to make sure
22691         // the element has css positioning
22692
22693         var el = this.getDragEl();
22694         this.alignElWithMouse(el, iPageX, iPageY);
22695     },
22696
22697     /**
22698      * Sets the element to the location of the mousedown or click event,
22699      * maintaining the cursor location relative to the location on the element
22700      * that was clicked.  Override this if you want to place the element in a
22701      * location other than where the cursor is.
22702      * @method alignElWithMouse
22703      * @param {HTMLElement} el the element to move
22704      * @param {int} iPageX the X coordinate of the mousedown or drag event
22705      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22706      */
22707     alignElWithMouse: function(el, iPageX, iPageY) {
22708         var oCoord = this.getTargetCoord(iPageX, iPageY);
22709         var fly = el.dom ? el : Roo.fly(el);
22710         if (!this.deltaSetXY) {
22711             var aCoord = [oCoord.x, oCoord.y];
22712             fly.setXY(aCoord);
22713             var newLeft = fly.getLeft(true);
22714             var newTop  = fly.getTop(true);
22715             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22716         } else {
22717             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22718         }
22719
22720         this.cachePosition(oCoord.x, oCoord.y);
22721         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22722         return oCoord;
22723     },
22724
22725     /**
22726      * Saves the most recent position so that we can reset the constraints and
22727      * tick marks on-demand.  We need to know this so that we can calculate the
22728      * number of pixels the element is offset from its original position.
22729      * @method cachePosition
22730      * @param iPageX the current x position (optional, this just makes it so we
22731      * don't have to look it up again)
22732      * @param iPageY the current y position (optional, this just makes it so we
22733      * don't have to look it up again)
22734      */
22735     cachePosition: function(iPageX, iPageY) {
22736         if (iPageX) {
22737             this.lastPageX = iPageX;
22738             this.lastPageY = iPageY;
22739         } else {
22740             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22741             this.lastPageX = aCoord[0];
22742             this.lastPageY = aCoord[1];
22743         }
22744     },
22745
22746     /**
22747      * Auto-scroll the window if the dragged object has been moved beyond the
22748      * visible window boundary.
22749      * @method autoScroll
22750      * @param {int} x the drag element's x position
22751      * @param {int} y the drag element's y position
22752      * @param {int} h the height of the drag element
22753      * @param {int} w the width of the drag element
22754      * @private
22755      */
22756     autoScroll: function(x, y, h, w) {
22757
22758         if (this.scroll) {
22759             // The client height
22760             var clientH = Roo.lib.Dom.getViewWidth();
22761
22762             // The client width
22763             var clientW = Roo.lib.Dom.getViewHeight();
22764
22765             // The amt scrolled down
22766             var st = this.DDM.getScrollTop();
22767
22768             // The amt scrolled right
22769             var sl = this.DDM.getScrollLeft();
22770
22771             // Location of the bottom of the element
22772             var bot = h + y;
22773
22774             // Location of the right of the element
22775             var right = w + x;
22776
22777             // The distance from the cursor to the bottom of the visible area,
22778             // adjusted so that we don't scroll if the cursor is beyond the
22779             // element drag constraints
22780             var toBot = (clientH + st - y - this.deltaY);
22781
22782             // The distance from the cursor to the right of the visible area
22783             var toRight = (clientW + sl - x - this.deltaX);
22784
22785
22786             // How close to the edge the cursor must be before we scroll
22787             // var thresh = (document.all) ? 100 : 40;
22788             var thresh = 40;
22789
22790             // How many pixels to scroll per autoscroll op.  This helps to reduce
22791             // clunky scrolling. IE is more sensitive about this ... it needs this
22792             // value to be higher.
22793             var scrAmt = (document.all) ? 80 : 30;
22794
22795             // Scroll down if we are near the bottom of the visible page and the
22796             // obj extends below the crease
22797             if ( bot > clientH && toBot < thresh ) {
22798                 window.scrollTo(sl, st + scrAmt);
22799             }
22800
22801             // Scroll up if the window is scrolled down and the top of the object
22802             // goes above the top border
22803             if ( y < st && st > 0 && y - st < thresh ) {
22804                 window.scrollTo(sl, st - scrAmt);
22805             }
22806
22807             // Scroll right if the obj is beyond the right border and the cursor is
22808             // near the border.
22809             if ( right > clientW && toRight < thresh ) {
22810                 window.scrollTo(sl + scrAmt, st);
22811             }
22812
22813             // Scroll left if the window has been scrolled to the right and the obj
22814             // extends past the left border
22815             if ( x < sl && sl > 0 && x - sl < thresh ) {
22816                 window.scrollTo(sl - scrAmt, st);
22817             }
22818         }
22819     },
22820
22821     /**
22822      * Finds the location the element should be placed if we want to move
22823      * it to where the mouse location less the click offset would place us.
22824      * @method getTargetCoord
22825      * @param {int} iPageX the X coordinate of the click
22826      * @param {int} iPageY the Y coordinate of the click
22827      * @return an object that contains the coordinates (Object.x and Object.y)
22828      * @private
22829      */
22830     getTargetCoord: function(iPageX, iPageY) {
22831
22832
22833         var x = iPageX - this.deltaX;
22834         var y = iPageY - this.deltaY;
22835
22836         if (this.constrainX) {
22837             if (x < this.minX) { x = this.minX; }
22838             if (x > this.maxX) { x = this.maxX; }
22839         }
22840
22841         if (this.constrainY) {
22842             if (y < this.minY) { y = this.minY; }
22843             if (y > this.maxY) { y = this.maxY; }
22844         }
22845
22846         x = this.getTick(x, this.xTicks);
22847         y = this.getTick(y, this.yTicks);
22848
22849
22850         return {x:x, y:y};
22851     },
22852
22853     /*
22854      * Sets up config options specific to this class. Overrides
22855      * Roo.dd.DragDrop, but all versions of this method through the
22856      * inheritance chain are called
22857      */
22858     applyConfig: function() {
22859         Roo.dd.DD.superclass.applyConfig.call(this);
22860         this.scroll = (this.config.scroll !== false);
22861     },
22862
22863     /*
22864      * Event that fires prior to the onMouseDown event.  Overrides
22865      * Roo.dd.DragDrop.
22866      */
22867     b4MouseDown: function(e) {
22868         // this.resetConstraints();
22869         this.autoOffset(e.getPageX(),
22870                             e.getPageY());
22871     },
22872
22873     /*
22874      * Event that fires prior to the onDrag event.  Overrides
22875      * Roo.dd.DragDrop.
22876      */
22877     b4Drag: function(e) {
22878         this.setDragElPos(e.getPageX(),
22879                             e.getPageY());
22880     },
22881
22882     toString: function() {
22883         return ("DD " + this.id);
22884     }
22885
22886     //////////////////////////////////////////////////////////////////////////
22887     // Debugging ygDragDrop events that can be overridden
22888     //////////////////////////////////////////////////////////////////////////
22889     /*
22890     startDrag: function(x, y) {
22891     },
22892
22893     onDrag: function(e) {
22894     },
22895
22896     onDragEnter: function(e, id) {
22897     },
22898
22899     onDragOver: function(e, id) {
22900     },
22901
22902     onDragOut: function(e, id) {
22903     },
22904
22905     onDragDrop: function(e, id) {
22906     },
22907
22908     endDrag: function(e) {
22909     }
22910
22911     */
22912
22913 });/*
22914  * Based on:
22915  * Ext JS Library 1.1.1
22916  * Copyright(c) 2006-2007, Ext JS, LLC.
22917  *
22918  * Originally Released Under LGPL - original licence link has changed is not relivant.
22919  *
22920  * Fork - LGPL
22921  * <script type="text/javascript">
22922  */
22923
22924 /**
22925  * @class Roo.dd.DDProxy
22926  * A DragDrop implementation that inserts an empty, bordered div into
22927  * the document that follows the cursor during drag operations.  At the time of
22928  * the click, the frame div is resized to the dimensions of the linked html
22929  * element, and moved to the exact location of the linked element.
22930  *
22931  * References to the "frame" element refer to the single proxy element that
22932  * was created to be dragged in place of all DDProxy elements on the
22933  * page.
22934  *
22935  * @extends Roo.dd.DD
22936  * @constructor
22937  * @param {String} id the id of the linked html element
22938  * @param {String} sGroup the group of related DragDrop objects
22939  * @param {object} config an object containing configurable attributes
22940  *                Valid properties for DDProxy in addition to those in DragDrop:
22941  *                   resizeFrame, centerFrame, dragElId
22942  */
22943 Roo.dd.DDProxy = function(id, sGroup, config) {
22944     if (id) {
22945         this.init(id, sGroup, config);
22946         this.initFrame();
22947     }
22948 };
22949
22950 /**
22951  * The default drag frame div id
22952  * @property Roo.dd.DDProxy.dragElId
22953  * @type String
22954  * @static
22955  */
22956 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22957
22958 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22959
22960     /**
22961      * By default we resize the drag frame to be the same size as the element
22962      * we want to drag (this is to get the frame effect).  We can turn it off
22963      * if we want a different behavior.
22964      * @property resizeFrame
22965      * @type boolean
22966      */
22967     resizeFrame: true,
22968
22969     /**
22970      * By default the frame is positioned exactly where the drag element is, so
22971      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22972      * you do not have constraints on the obj is to have the drag frame centered
22973      * around the cursor.  Set centerFrame to true for this effect.
22974      * @property centerFrame
22975      * @type boolean
22976      */
22977     centerFrame: false,
22978
22979     /**
22980      * Creates the proxy element if it does not yet exist
22981      * @method createFrame
22982      */
22983     createFrame: function() {
22984         var self = this;
22985         var body = document.body;
22986
22987         if (!body || !body.firstChild) {
22988             setTimeout( function() { self.createFrame(); }, 50 );
22989             return;
22990         }
22991
22992         var div = this.getDragEl();
22993
22994         if (!div) {
22995             div    = document.createElement("div");
22996             div.id = this.dragElId;
22997             var s  = div.style;
22998
22999             s.position   = "absolute";
23000             s.visibility = "hidden";
23001             s.cursor     = "move";
23002             s.border     = "2px solid #aaa";
23003             s.zIndex     = 999;
23004
23005             // appendChild can blow up IE if invoked prior to the window load event
23006             // while rendering a table.  It is possible there are other scenarios
23007             // that would cause this to happen as well.
23008             body.insertBefore(div, body.firstChild);
23009         }
23010     },
23011
23012     /**
23013      * Initialization for the drag frame element.  Must be called in the
23014      * constructor of all subclasses
23015      * @method initFrame
23016      */
23017     initFrame: function() {
23018         this.createFrame();
23019     },
23020
23021     applyConfig: function() {
23022         Roo.dd.DDProxy.superclass.applyConfig.call(this);
23023
23024         this.resizeFrame = (this.config.resizeFrame !== false);
23025         this.centerFrame = (this.config.centerFrame);
23026         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23027     },
23028
23029     /**
23030      * Resizes the drag frame to the dimensions of the clicked object, positions
23031      * it over the object, and finally displays it
23032      * @method showFrame
23033      * @param {int} iPageX X click position
23034      * @param {int} iPageY Y click position
23035      * @private
23036      */
23037     showFrame: function(iPageX, iPageY) {
23038         var el = this.getEl();
23039         var dragEl = this.getDragEl();
23040         var s = dragEl.style;
23041
23042         this._resizeProxy();
23043
23044         if (this.centerFrame) {
23045             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23046                            Math.round(parseInt(s.height, 10)/2) );
23047         }
23048
23049         this.setDragElPos(iPageX, iPageY);
23050
23051         Roo.fly(dragEl).show();
23052     },
23053
23054     /**
23055      * The proxy is automatically resized to the dimensions of the linked
23056      * element when a drag is initiated, unless resizeFrame is set to false
23057      * @method _resizeProxy
23058      * @private
23059      */
23060     _resizeProxy: function() {
23061         if (this.resizeFrame) {
23062             var el = this.getEl();
23063             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23064         }
23065     },
23066
23067     // overrides Roo.dd.DragDrop
23068     b4MouseDown: function(e) {
23069         var x = e.getPageX();
23070         var y = e.getPageY();
23071         this.autoOffset(x, y);
23072         this.setDragElPos(x, y);
23073     },
23074
23075     // overrides Roo.dd.DragDrop
23076     b4StartDrag: function(x, y) {
23077         // show the drag frame
23078         this.showFrame(x, y);
23079     },
23080
23081     // overrides Roo.dd.DragDrop
23082     b4EndDrag: function(e) {
23083         Roo.fly(this.getDragEl()).hide();
23084     },
23085
23086     // overrides Roo.dd.DragDrop
23087     // By default we try to move the element to the last location of the frame.
23088     // This is so that the default behavior mirrors that of Roo.dd.DD.
23089     endDrag: function(e) {
23090
23091         var lel = this.getEl();
23092         var del = this.getDragEl();
23093
23094         // Show the drag frame briefly so we can get its position
23095         del.style.visibility = "";
23096
23097         this.beforeMove();
23098         // Hide the linked element before the move to get around a Safari
23099         // rendering bug.
23100         lel.style.visibility = "hidden";
23101         Roo.dd.DDM.moveToEl(lel, del);
23102         del.style.visibility = "hidden";
23103         lel.style.visibility = "";
23104
23105         this.afterDrag();
23106     },
23107
23108     beforeMove : function(){
23109
23110     },
23111
23112     afterDrag : function(){
23113
23114     },
23115
23116     toString: function() {
23117         return ("DDProxy " + this.id);
23118     }
23119
23120 });
23121 /*
23122  * Based on:
23123  * Ext JS Library 1.1.1
23124  * Copyright(c) 2006-2007, Ext JS, LLC.
23125  *
23126  * Originally Released Under LGPL - original licence link has changed is not relivant.
23127  *
23128  * Fork - LGPL
23129  * <script type="text/javascript">
23130  */
23131
23132  /**
23133  * @class Roo.dd.DDTarget
23134  * A DragDrop implementation that does not move, but can be a drop
23135  * target.  You would get the same result by simply omitting implementation
23136  * for the event callbacks, but this way we reduce the processing cost of the
23137  * event listener and the callbacks.
23138  * @extends Roo.dd.DragDrop
23139  * @constructor
23140  * @param {String} id the id of the element that is a drop target
23141  * @param {String} sGroup the group of related DragDrop objects
23142  * @param {object} config an object containing configurable attributes
23143  *                 Valid properties for DDTarget in addition to those in
23144  *                 DragDrop:
23145  *                    none
23146  */
23147 Roo.dd.DDTarget = function(id, sGroup, config) {
23148     if (id) {
23149         this.initTarget(id, sGroup, config);
23150     }
23151     if (config && (config.listeners || config.events)) { 
23152         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23153             listeners : config.listeners || {}, 
23154             events : config.events || {} 
23155         });    
23156     }
23157 };
23158
23159 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23160 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23161     toString: function() {
23162         return ("DDTarget " + this.id);
23163     }
23164 });
23165 /*
23166  * Based on:
23167  * Ext JS Library 1.1.1
23168  * Copyright(c) 2006-2007, Ext JS, LLC.
23169  *
23170  * Originally Released Under LGPL - original licence link has changed is not relivant.
23171  *
23172  * Fork - LGPL
23173  * <script type="text/javascript">
23174  */
23175  
23176
23177 /**
23178  * @class Roo.dd.ScrollManager
23179  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23180  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23181  * @static
23182  */
23183 Roo.dd.ScrollManager = function(){
23184     var ddm = Roo.dd.DragDropMgr;
23185     var els = {};
23186     var dragEl = null;
23187     var proc = {};
23188     
23189     
23190     
23191     var onStop = function(e){
23192         dragEl = null;
23193         clearProc();
23194     };
23195     
23196     var triggerRefresh = function(){
23197         if(ddm.dragCurrent){
23198              ddm.refreshCache(ddm.dragCurrent.groups);
23199         }
23200     };
23201     
23202     var doScroll = function(){
23203         if(ddm.dragCurrent){
23204             var dds = Roo.dd.ScrollManager;
23205             if(!dds.animate){
23206                 if(proc.el.scroll(proc.dir, dds.increment)){
23207                     triggerRefresh();
23208                 }
23209             }else{
23210                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23211             }
23212         }
23213     };
23214     
23215     var clearProc = function(){
23216         if(proc.id){
23217             clearInterval(proc.id);
23218         }
23219         proc.id = 0;
23220         proc.el = null;
23221         proc.dir = "";
23222     };
23223     
23224     var startProc = function(el, dir){
23225          Roo.log('scroll startproc');
23226         clearProc();
23227         proc.el = el;
23228         proc.dir = dir;
23229         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23230     };
23231     
23232     var onFire = function(e, isDrop){
23233        
23234         if(isDrop || !ddm.dragCurrent){ return; }
23235         var dds = Roo.dd.ScrollManager;
23236         if(!dragEl || dragEl != ddm.dragCurrent){
23237             dragEl = ddm.dragCurrent;
23238             // refresh regions on drag start
23239             dds.refreshCache();
23240         }
23241         
23242         var xy = Roo.lib.Event.getXY(e);
23243         var pt = new Roo.lib.Point(xy[0], xy[1]);
23244         for(var id in els){
23245             var el = els[id], r = el._region;
23246             if(r && r.contains(pt) && el.isScrollable()){
23247                 if(r.bottom - pt.y <= dds.thresh){
23248                     if(proc.el != el){
23249                         startProc(el, "down");
23250                     }
23251                     return;
23252                 }else if(r.right - pt.x <= dds.thresh){
23253                     if(proc.el != el){
23254                         startProc(el, "left");
23255                     }
23256                     return;
23257                 }else if(pt.y - r.top <= dds.thresh){
23258                     if(proc.el != el){
23259                         startProc(el, "up");
23260                     }
23261                     return;
23262                 }else if(pt.x - r.left <= dds.thresh){
23263                     if(proc.el != el){
23264                         startProc(el, "right");
23265                     }
23266                     return;
23267                 }
23268             }
23269         }
23270         clearProc();
23271     };
23272     
23273     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23274     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23275     
23276     return {
23277         /**
23278          * Registers new overflow element(s) to auto scroll
23279          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23280          */
23281         register : function(el){
23282             if(el instanceof Array){
23283                 for(var i = 0, len = el.length; i < len; i++) {
23284                         this.register(el[i]);
23285                 }
23286             }else{
23287                 el = Roo.get(el);
23288                 els[el.id] = el;
23289             }
23290             Roo.dd.ScrollManager.els = els;
23291         },
23292         
23293         /**
23294          * Unregisters overflow element(s) so they are no longer scrolled
23295          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23296          */
23297         unregister : function(el){
23298             if(el instanceof Array){
23299                 for(var i = 0, len = el.length; i < len; i++) {
23300                         this.unregister(el[i]);
23301                 }
23302             }else{
23303                 el = Roo.get(el);
23304                 delete els[el.id];
23305             }
23306         },
23307         
23308         /**
23309          * The number of pixels from the edge of a container the pointer needs to be to 
23310          * trigger scrolling (defaults to 25)
23311          * @type Number
23312          */
23313         thresh : 25,
23314         
23315         /**
23316          * The number of pixels to scroll in each scroll increment (defaults to 50)
23317          * @type Number
23318          */
23319         increment : 100,
23320         
23321         /**
23322          * The frequency of scrolls in milliseconds (defaults to 500)
23323          * @type Number
23324          */
23325         frequency : 500,
23326         
23327         /**
23328          * True to animate the scroll (defaults to true)
23329          * @type Boolean
23330          */
23331         animate: true,
23332         
23333         /**
23334          * The animation duration in seconds - 
23335          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23336          * @type Number
23337          */
23338         animDuration: .4,
23339         
23340         /**
23341          * Manually trigger a cache refresh.
23342          */
23343         refreshCache : function(){
23344             for(var id in els){
23345                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23346                     els[id]._region = els[id].getRegion();
23347                 }
23348             }
23349         }
23350     };
23351 }();/*
23352  * Based on:
23353  * Ext JS Library 1.1.1
23354  * Copyright(c) 2006-2007, Ext JS, LLC.
23355  *
23356  * Originally Released Under LGPL - original licence link has changed is not relivant.
23357  *
23358  * Fork - LGPL
23359  * <script type="text/javascript">
23360  */
23361  
23362
23363 /**
23364  * @class Roo.dd.Registry
23365  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23366  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23367  * @static
23368  */
23369 Roo.dd.Registry = function(){
23370     var elements = {}; 
23371     var handles = {}; 
23372     var autoIdSeed = 0;
23373
23374     var getId = function(el, autogen){
23375         if(typeof el == "string"){
23376             return el;
23377         }
23378         var id = el.id;
23379         if(!id && autogen !== false){
23380             id = "roodd-" + (++autoIdSeed);
23381             el.id = id;
23382         }
23383         return id;
23384     };
23385     
23386     return {
23387     /**
23388      * Register a drag drop element
23389      * @param {String|HTMLElement} element The id or DOM node to register
23390      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23391      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23392      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23393      * populated in the data object (if applicable):
23394      * <pre>
23395 Value      Description<br />
23396 ---------  ------------------------------------------<br />
23397 handles    Array of DOM nodes that trigger dragging<br />
23398            for the element being registered<br />
23399 isHandle   True if the element passed in triggers<br />
23400            dragging itself, else false
23401 </pre>
23402      */
23403         register : function(el, data){
23404             data = data || {};
23405             if(typeof el == "string"){
23406                 el = document.getElementById(el);
23407             }
23408             data.ddel = el;
23409             elements[getId(el)] = data;
23410             if(data.isHandle !== false){
23411                 handles[data.ddel.id] = data;
23412             }
23413             if(data.handles){
23414                 var hs = data.handles;
23415                 for(var i = 0, len = hs.length; i < len; i++){
23416                         handles[getId(hs[i])] = data;
23417                 }
23418             }
23419         },
23420
23421     /**
23422      * Unregister a drag drop element
23423      * @param {String|HTMLElement}  element The id or DOM node to unregister
23424      */
23425         unregister : function(el){
23426             var id = getId(el, false);
23427             var data = elements[id];
23428             if(data){
23429                 delete elements[id];
23430                 if(data.handles){
23431                     var hs = data.handles;
23432                     for(var i = 0, len = hs.length; i < len; i++){
23433                         delete handles[getId(hs[i], false)];
23434                     }
23435                 }
23436             }
23437         },
23438
23439     /**
23440      * Returns the handle registered for a DOM Node by id
23441      * @param {String|HTMLElement} id The DOM node or id to look up
23442      * @return {Object} handle The custom handle data
23443      */
23444         getHandle : function(id){
23445             if(typeof id != "string"){ // must be element?
23446                 id = id.id;
23447             }
23448             return handles[id];
23449         },
23450
23451     /**
23452      * Returns the handle that is registered for the DOM node that is the target of the event
23453      * @param {Event} e The event
23454      * @return {Object} handle The custom handle data
23455      */
23456         getHandleFromEvent : function(e){
23457             var t = Roo.lib.Event.getTarget(e);
23458             return t ? handles[t.id] : null;
23459         },
23460
23461     /**
23462      * Returns a custom data object that is registered for a DOM node by id
23463      * @param {String|HTMLElement} id The DOM node or id to look up
23464      * @return {Object} data The custom data
23465      */
23466         getTarget : function(id){
23467             if(typeof id != "string"){ // must be element?
23468                 id = id.id;
23469             }
23470             return elements[id];
23471         },
23472
23473     /**
23474      * Returns a custom data object that is registered for the DOM node that is the target of the event
23475      * @param {Event} e The event
23476      * @return {Object} data The custom data
23477      */
23478         getTargetFromEvent : function(e){
23479             var t = Roo.lib.Event.getTarget(e);
23480             return t ? elements[t.id] || handles[t.id] : null;
23481         }
23482     };
23483 }();/*
23484  * Based on:
23485  * Ext JS Library 1.1.1
23486  * Copyright(c) 2006-2007, Ext JS, LLC.
23487  *
23488  * Originally Released Under LGPL - original licence link has changed is not relivant.
23489  *
23490  * Fork - LGPL
23491  * <script type="text/javascript">
23492  */
23493  
23494
23495 /**
23496  * @class Roo.dd.StatusProxy
23497  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23498  * default drag proxy used by all Roo.dd components.
23499  * @constructor
23500  * @param {Object} config
23501  */
23502 Roo.dd.StatusProxy = function(config){
23503     Roo.apply(this, config);
23504     this.id = this.id || Roo.id();
23505     this.el = new Roo.Layer({
23506         dh: {
23507             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23508                 {tag: "div", cls: "x-dd-drop-icon"},
23509                 {tag: "div", cls: "x-dd-drag-ghost"}
23510             ]
23511         }, 
23512         shadow: !config || config.shadow !== false
23513     });
23514     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23515     this.dropStatus = this.dropNotAllowed;
23516 };
23517
23518 Roo.dd.StatusProxy.prototype = {
23519     /**
23520      * @cfg {String} dropAllowed
23521      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23522      */
23523     dropAllowed : "x-dd-drop-ok",
23524     /**
23525      * @cfg {String} dropNotAllowed
23526      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23527      */
23528     dropNotAllowed : "x-dd-drop-nodrop",
23529
23530     /**
23531      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23532      * over the current target element.
23533      * @param {String} cssClass The css class for the new drop status indicator image
23534      */
23535     setStatus : function(cssClass){
23536         cssClass = cssClass || this.dropNotAllowed;
23537         if(this.dropStatus != cssClass){
23538             this.el.replaceClass(this.dropStatus, cssClass);
23539             this.dropStatus = cssClass;
23540         }
23541     },
23542
23543     /**
23544      * Resets the status indicator to the default dropNotAllowed value
23545      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23546      */
23547     reset : function(clearGhost){
23548         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23549         this.dropStatus = this.dropNotAllowed;
23550         if(clearGhost){
23551             this.ghost.update("");
23552         }
23553     },
23554
23555     /**
23556      * Updates the contents of the ghost element
23557      * @param {String} html The html that will replace the current innerHTML of the ghost element
23558      */
23559     update : function(html){
23560         if(typeof html == "string"){
23561             this.ghost.update(html);
23562         }else{
23563             this.ghost.update("");
23564             html.style.margin = "0";
23565             this.ghost.dom.appendChild(html);
23566         }
23567         // ensure float = none set?? cant remember why though.
23568         var el = this.ghost.dom.firstChild;
23569                 if(el){
23570                         Roo.fly(el).setStyle('float', 'none');
23571                 }
23572     },
23573     
23574     /**
23575      * Returns the underlying proxy {@link Roo.Layer}
23576      * @return {Roo.Layer} el
23577     */
23578     getEl : function(){
23579         return this.el;
23580     },
23581
23582     /**
23583      * Returns the ghost element
23584      * @return {Roo.Element} el
23585      */
23586     getGhost : function(){
23587         return this.ghost;
23588     },
23589
23590     /**
23591      * Hides the proxy
23592      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23593      */
23594     hide : function(clear){
23595         this.el.hide();
23596         if(clear){
23597             this.reset(true);
23598         }
23599     },
23600
23601     /**
23602      * Stops the repair animation if it's currently running
23603      */
23604     stop : function(){
23605         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23606             this.anim.stop();
23607         }
23608     },
23609
23610     /**
23611      * Displays this proxy
23612      */
23613     show : function(){
23614         this.el.show();
23615     },
23616
23617     /**
23618      * Force the Layer to sync its shadow and shim positions to the element
23619      */
23620     sync : function(){
23621         this.el.sync();
23622     },
23623
23624     /**
23625      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23626      * invalid drop operation by the item being dragged.
23627      * @param {Array} xy The XY position of the element ([x, y])
23628      * @param {Function} callback The function to call after the repair is complete
23629      * @param {Object} scope The scope in which to execute the callback
23630      */
23631     repair : function(xy, callback, scope){
23632         this.callback = callback;
23633         this.scope = scope;
23634         if(xy && this.animRepair !== false){
23635             this.el.addClass("x-dd-drag-repair");
23636             this.el.hideUnders(true);
23637             this.anim = this.el.shift({
23638                 duration: this.repairDuration || .5,
23639                 easing: 'easeOut',
23640                 xy: xy,
23641                 stopFx: true,
23642                 callback: this.afterRepair,
23643                 scope: this
23644             });
23645         }else{
23646             this.afterRepair();
23647         }
23648     },
23649
23650     // private
23651     afterRepair : function(){
23652         this.hide(true);
23653         if(typeof this.callback == "function"){
23654             this.callback.call(this.scope || this);
23655         }
23656         this.callback = null;
23657         this.scope = null;
23658     }
23659 };/*
23660  * Based on:
23661  * Ext JS Library 1.1.1
23662  * Copyright(c) 2006-2007, Ext JS, LLC.
23663  *
23664  * Originally Released Under LGPL - original licence link has changed is not relivant.
23665  *
23666  * Fork - LGPL
23667  * <script type="text/javascript">
23668  */
23669
23670 /**
23671  * @class Roo.dd.DragSource
23672  * @extends Roo.dd.DDProxy
23673  * A simple class that provides the basic implementation needed to make any element draggable.
23674  * @constructor
23675  * @param {String/HTMLElement/Element} el The container element
23676  * @param {Object} config
23677  */
23678 Roo.dd.DragSource = function(el, config){
23679     this.el = Roo.get(el);
23680     this.dragData = {};
23681     
23682     Roo.apply(this, config);
23683     
23684     if(!this.proxy){
23685         this.proxy = new Roo.dd.StatusProxy();
23686     }
23687
23688     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23689           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23690     
23691     this.dragging = false;
23692 };
23693
23694 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23695     /**
23696      * @cfg {String} dropAllowed
23697      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23698      */
23699     dropAllowed : "x-dd-drop-ok",
23700     /**
23701      * @cfg {String} dropNotAllowed
23702      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23703      */
23704     dropNotAllowed : "x-dd-drop-nodrop",
23705
23706     /**
23707      * Returns the data object associated with this drag source
23708      * @return {Object} data An object containing arbitrary data
23709      */
23710     getDragData : function(e){
23711         return this.dragData;
23712     },
23713
23714     // private
23715     onDragEnter : function(e, id){
23716         var target = Roo.dd.DragDropMgr.getDDById(id);
23717         this.cachedTarget = target;
23718         if(this.beforeDragEnter(target, e, id) !== false){
23719             if(target.isNotifyTarget){
23720                 var status = target.notifyEnter(this, e, this.dragData);
23721                 this.proxy.setStatus(status);
23722             }else{
23723                 this.proxy.setStatus(this.dropAllowed);
23724             }
23725             
23726             if(this.afterDragEnter){
23727                 /**
23728                  * An empty function by default, but provided so that you can perform a custom action
23729                  * when the dragged item enters the drop target by providing an implementation.
23730                  * @param {Roo.dd.DragDrop} target The drop target
23731                  * @param {Event} e The event object
23732                  * @param {String} id The id of the dragged element
23733                  * @method afterDragEnter
23734                  */
23735                 this.afterDragEnter(target, e, id);
23736             }
23737         }
23738     },
23739
23740     /**
23741      * An empty function by default, but provided so that you can perform a custom action
23742      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23743      * @param {Roo.dd.DragDrop} target The drop target
23744      * @param {Event} e The event object
23745      * @param {String} id The id of the dragged element
23746      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23747      */
23748     beforeDragEnter : function(target, e, id){
23749         return true;
23750     },
23751
23752     // private
23753     alignElWithMouse: function() {
23754         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23755         this.proxy.sync();
23756     },
23757
23758     // private
23759     onDragOver : function(e, id){
23760         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23761         if(this.beforeDragOver(target, e, id) !== false){
23762             if(target.isNotifyTarget){
23763                 var status = target.notifyOver(this, e, this.dragData);
23764                 this.proxy.setStatus(status);
23765             }
23766
23767             if(this.afterDragOver){
23768                 /**
23769                  * An empty function by default, but provided so that you can perform a custom action
23770                  * while the dragged item is over the drop target by providing an implementation.
23771                  * @param {Roo.dd.DragDrop} target The drop target
23772                  * @param {Event} e The event object
23773                  * @param {String} id The id of the dragged element
23774                  * @method afterDragOver
23775                  */
23776                 this.afterDragOver(target, e, id);
23777             }
23778         }
23779     },
23780
23781     /**
23782      * An empty function by default, but provided so that you can perform a custom action
23783      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23784      * @param {Roo.dd.DragDrop} target The drop target
23785      * @param {Event} e The event object
23786      * @param {String} id The id of the dragged element
23787      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23788      */
23789     beforeDragOver : function(target, e, id){
23790         return true;
23791     },
23792
23793     // private
23794     onDragOut : function(e, id){
23795         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23796         if(this.beforeDragOut(target, e, id) !== false){
23797             if(target.isNotifyTarget){
23798                 target.notifyOut(this, e, this.dragData);
23799             }
23800             this.proxy.reset();
23801             if(this.afterDragOut){
23802                 /**
23803                  * An empty function by default, but provided so that you can perform a custom action
23804                  * after the dragged item is dragged out of the target without dropping.
23805                  * @param {Roo.dd.DragDrop} target The drop target
23806                  * @param {Event} e The event object
23807                  * @param {String} id The id of the dragged element
23808                  * @method afterDragOut
23809                  */
23810                 this.afterDragOut(target, e, id);
23811             }
23812         }
23813         this.cachedTarget = null;
23814     },
23815
23816     /**
23817      * An empty function by default, but provided so that you can perform a custom action before the dragged
23818      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23819      * @param {Roo.dd.DragDrop} target The drop target
23820      * @param {Event} e The event object
23821      * @param {String} id The id of the dragged element
23822      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23823      */
23824     beforeDragOut : function(target, e, id){
23825         return true;
23826     },
23827     
23828     // private
23829     onDragDrop : function(e, id){
23830         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23831         if(this.beforeDragDrop(target, e, id) !== false){
23832             if(target.isNotifyTarget){
23833                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23834                     this.onValidDrop(target, e, id);
23835                 }else{
23836                     this.onInvalidDrop(target, e, id);
23837                 }
23838             }else{
23839                 this.onValidDrop(target, e, id);
23840             }
23841             
23842             if(this.afterDragDrop){
23843                 /**
23844                  * An empty function by default, but provided so that you can perform a custom action
23845                  * after a valid drag drop has occurred by providing an implementation.
23846                  * @param {Roo.dd.DragDrop} target The drop target
23847                  * @param {Event} e The event object
23848                  * @param {String} id The id of the dropped element
23849                  * @method afterDragDrop
23850                  */
23851                 this.afterDragDrop(target, e, id);
23852             }
23853         }
23854         delete this.cachedTarget;
23855     },
23856
23857     /**
23858      * An empty function by default, but provided so that you can perform a custom action before the dragged
23859      * item is dropped onto the target and optionally cancel the onDragDrop.
23860      * @param {Roo.dd.DragDrop} target The drop target
23861      * @param {Event} e The event object
23862      * @param {String} id The id of the dragged element
23863      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23864      */
23865     beforeDragDrop : function(target, e, id){
23866         return true;
23867     },
23868
23869     // private
23870     onValidDrop : function(target, e, id){
23871         this.hideProxy();
23872         if(this.afterValidDrop){
23873             /**
23874              * An empty function by default, but provided so that you can perform a custom action
23875              * after a valid drop has occurred by providing an implementation.
23876              * @param {Object} target The target DD 
23877              * @param {Event} e The event object
23878              * @param {String} id The id of the dropped element
23879              * @method afterInvalidDrop
23880              */
23881             this.afterValidDrop(target, e, id);
23882         }
23883     },
23884
23885     // private
23886     getRepairXY : function(e, data){
23887         return this.el.getXY();  
23888     },
23889
23890     // private
23891     onInvalidDrop : function(target, e, id){
23892         this.beforeInvalidDrop(target, e, id);
23893         if(this.cachedTarget){
23894             if(this.cachedTarget.isNotifyTarget){
23895                 this.cachedTarget.notifyOut(this, e, this.dragData);
23896             }
23897             this.cacheTarget = null;
23898         }
23899         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23900
23901         if(this.afterInvalidDrop){
23902             /**
23903              * An empty function by default, but provided so that you can perform a custom action
23904              * after an invalid drop has occurred by providing an implementation.
23905              * @param {Event} e The event object
23906              * @param {String} id The id of the dropped element
23907              * @method afterInvalidDrop
23908              */
23909             this.afterInvalidDrop(e, id);
23910         }
23911     },
23912
23913     // private
23914     afterRepair : function(){
23915         if(Roo.enableFx){
23916             this.el.highlight(this.hlColor || "c3daf9");
23917         }
23918         this.dragging = false;
23919     },
23920
23921     /**
23922      * An empty function by default, but provided so that you can perform a custom action after an invalid
23923      * drop has occurred.
23924      * @param {Roo.dd.DragDrop} target The drop target
23925      * @param {Event} e The event object
23926      * @param {String} id The id of the dragged element
23927      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23928      */
23929     beforeInvalidDrop : function(target, e, id){
23930         return true;
23931     },
23932
23933     // private
23934     handleMouseDown : function(e){
23935         if(this.dragging) {
23936             return;
23937         }
23938         var data = this.getDragData(e);
23939         if(data && this.onBeforeDrag(data, e) !== false){
23940             this.dragData = data;
23941             this.proxy.stop();
23942             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23943         } 
23944     },
23945
23946     /**
23947      * An empty function by default, but provided so that you can perform a custom action before the initial
23948      * drag event begins and optionally cancel it.
23949      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23950      * @param {Event} e The event object
23951      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23952      */
23953     onBeforeDrag : function(data, e){
23954         return true;
23955     },
23956
23957     /**
23958      * An empty function by default, but provided so that you can perform a custom action once the initial
23959      * drag event has begun.  The drag cannot be canceled from this function.
23960      * @param {Number} x The x position of the click on the dragged object
23961      * @param {Number} y The y position of the click on the dragged object
23962      */
23963     onStartDrag : Roo.emptyFn,
23964
23965     // private - YUI override
23966     startDrag : function(x, y){
23967         this.proxy.reset();
23968         this.dragging = true;
23969         this.proxy.update("");
23970         this.onInitDrag(x, y);
23971         this.proxy.show();
23972     },
23973
23974     // private
23975     onInitDrag : function(x, y){
23976         var clone = this.el.dom.cloneNode(true);
23977         clone.id = Roo.id(); // prevent duplicate ids
23978         this.proxy.update(clone);
23979         this.onStartDrag(x, y);
23980         return true;
23981     },
23982
23983     /**
23984      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23985      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23986      */
23987     getProxy : function(){
23988         return this.proxy;  
23989     },
23990
23991     /**
23992      * Hides the drag source's {@link Roo.dd.StatusProxy}
23993      */
23994     hideProxy : function(){
23995         this.proxy.hide();  
23996         this.proxy.reset(true);
23997         this.dragging = false;
23998     },
23999
24000     // private
24001     triggerCacheRefresh : function(){
24002         Roo.dd.DDM.refreshCache(this.groups);
24003     },
24004
24005     // private - override to prevent hiding
24006     b4EndDrag: function(e) {
24007     },
24008
24009     // private - override to prevent moving
24010     endDrag : function(e){
24011         this.onEndDrag(this.dragData, e);
24012     },
24013
24014     // private
24015     onEndDrag : function(data, e){
24016     },
24017     
24018     // private - pin to cursor
24019     autoOffset : function(x, y) {
24020         this.setDelta(-12, -20);
24021     }    
24022 });/*
24023  * Based on:
24024  * Ext JS Library 1.1.1
24025  * Copyright(c) 2006-2007, Ext JS, LLC.
24026  *
24027  * Originally Released Under LGPL - original licence link has changed is not relivant.
24028  *
24029  * Fork - LGPL
24030  * <script type="text/javascript">
24031  */
24032
24033
24034 /**
24035  * @class Roo.dd.DropTarget
24036  * @extends Roo.dd.DDTarget
24037  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24038  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24039  * @constructor
24040  * @param {String/HTMLElement/Element} el The container element
24041  * @param {Object} config
24042  */
24043 Roo.dd.DropTarget = function(el, config){
24044     this.el = Roo.get(el);
24045     
24046     var listeners = false; ;
24047     if (config && config.listeners) {
24048         listeners= config.listeners;
24049         delete config.listeners;
24050     }
24051     Roo.apply(this, config);
24052     
24053     if(this.containerScroll){
24054         Roo.dd.ScrollManager.register(this.el);
24055     }
24056     this.addEvents( {
24057          /**
24058          * @scope Roo.dd.DropTarget
24059          */
24060          
24061          /**
24062          * @event enter
24063          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24064          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24065          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24066          * 
24067          * IMPORTANT : it should set  this.valid to true|false
24068          * 
24069          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24070          * @param {Event} e The event
24071          * @param {Object} data An object containing arbitrary data supplied by the drag source
24072          */
24073         "enter" : true,
24074         
24075          /**
24076          * @event over
24077          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24078          * This method will be called on every mouse movement while the drag source is over the drop target.
24079          * This default implementation simply returns the dropAllowed config value.
24080          * 
24081          * IMPORTANT : it should set  this.valid to true|false
24082          * 
24083          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24084          * @param {Event} e The event
24085          * @param {Object} data An object containing arbitrary data supplied by the drag source
24086          
24087          */
24088         "over" : true,
24089         /**
24090          * @event out
24091          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24092          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24093          * overClass (if any) from the drop element.
24094          * 
24095          * 
24096          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24097          * @param {Event} e The event
24098          * @param {Object} data An object containing arbitrary data supplied by the drag source
24099          */
24100          "out" : true,
24101          
24102         /**
24103          * @event drop
24104          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24105          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24106          * implementation that does something to process the drop event and returns true so that the drag source's
24107          * repair action does not run.
24108          * 
24109          * IMPORTANT : it should set this.success
24110          * 
24111          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24112          * @param {Event} e The event
24113          * @param {Object} data An object containing arbitrary data supplied by the drag source
24114         */
24115          "drop" : true
24116     });
24117             
24118      
24119     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24120         this.el.dom, 
24121         this.ddGroup || this.group,
24122         {
24123             isTarget: true,
24124             listeners : listeners || {} 
24125            
24126         
24127         }
24128     );
24129
24130 };
24131
24132 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24133     /**
24134      * @cfg {String} overClass
24135      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24136      */
24137      /**
24138      * @cfg {String} ddGroup
24139      * The drag drop group to handle drop events for
24140      */
24141      
24142     /**
24143      * @cfg {String} dropAllowed
24144      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24145      */
24146     dropAllowed : "x-dd-drop-ok",
24147     /**
24148      * @cfg {String} dropNotAllowed
24149      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24150      */
24151     dropNotAllowed : "x-dd-drop-nodrop",
24152     /**
24153      * @cfg {boolean} success
24154      * set this after drop listener.. 
24155      */
24156     success : false,
24157     /**
24158      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24159      * if the drop point is valid for over/enter..
24160      */
24161     valid : false,
24162     // private
24163     isTarget : true,
24164
24165     // private
24166     isNotifyTarget : true,
24167     
24168     /**
24169      * @hide
24170      */
24171     notifyEnter : function(dd, e, data)
24172     {
24173         this.valid = true;
24174         this.fireEvent('enter', dd, e, data);
24175         if(this.overClass){
24176             this.el.addClass(this.overClass);
24177         }
24178         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24179             this.valid ? this.dropAllowed : this.dropNotAllowed
24180         );
24181     },
24182
24183     /**
24184      * @hide
24185      */
24186     notifyOver : function(dd, e, data)
24187     {
24188         this.valid = true;
24189         this.fireEvent('over', dd, e, data);
24190         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24191             this.valid ? this.dropAllowed : this.dropNotAllowed
24192         );
24193     },
24194
24195     /**
24196      * @hide
24197      */
24198     notifyOut : function(dd, e, data)
24199     {
24200         this.fireEvent('out', dd, e, data);
24201         if(this.overClass){
24202             this.el.removeClass(this.overClass);
24203         }
24204     },
24205
24206     /**
24207      * @hide
24208      */
24209     notifyDrop : function(dd, e, data)
24210     {
24211         this.success = false;
24212         this.fireEvent('drop', dd, e, data);
24213         return this.success;
24214     }
24215 });/*
24216  * Based on:
24217  * Ext JS Library 1.1.1
24218  * Copyright(c) 2006-2007, Ext JS, LLC.
24219  *
24220  * Originally Released Under LGPL - original licence link has changed is not relivant.
24221  *
24222  * Fork - LGPL
24223  * <script type="text/javascript">
24224  */
24225
24226
24227 /**
24228  * @class Roo.dd.DragZone
24229  * @extends Roo.dd.DragSource
24230  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24231  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24232  * @constructor
24233  * @param {String/HTMLElement/Element} el The container element
24234  * @param {Object} config
24235  */
24236 Roo.dd.DragZone = function(el, config){
24237     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24238     if(this.containerScroll){
24239         Roo.dd.ScrollManager.register(this.el);
24240     }
24241 };
24242
24243 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24244     /**
24245      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24246      * for auto scrolling during drag operations.
24247      */
24248     /**
24249      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24250      * method after a failed drop (defaults to "c3daf9" - light blue)
24251      */
24252
24253     /**
24254      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24255      * for a valid target to drag based on the mouse down. Override this method
24256      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24257      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24258      * @param {EventObject} e The mouse down event
24259      * @return {Object} The dragData
24260      */
24261     getDragData : function(e){
24262         return Roo.dd.Registry.getHandleFromEvent(e);
24263     },
24264     
24265     /**
24266      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24267      * this.dragData.ddel
24268      * @param {Number} x The x position of the click on the dragged object
24269      * @param {Number} y The y position of the click on the dragged object
24270      * @return {Boolean} true to continue the drag, false to cancel
24271      */
24272     onInitDrag : function(x, y){
24273         this.proxy.update(this.dragData.ddel.cloneNode(true));
24274         this.onStartDrag(x, y);
24275         return true;
24276     },
24277     
24278     /**
24279      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24280      */
24281     afterRepair : function(){
24282         if(Roo.enableFx){
24283             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24284         }
24285         this.dragging = false;
24286     },
24287
24288     /**
24289      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24290      * the XY of this.dragData.ddel
24291      * @param {EventObject} e The mouse up event
24292      * @return {Array} The xy location (e.g. [100, 200])
24293      */
24294     getRepairXY : function(e){
24295         return Roo.Element.fly(this.dragData.ddel).getXY();  
24296     }
24297 });/*
24298  * Based on:
24299  * Ext JS Library 1.1.1
24300  * Copyright(c) 2006-2007, Ext JS, LLC.
24301  *
24302  * Originally Released Under LGPL - original licence link has changed is not relivant.
24303  *
24304  * Fork - LGPL
24305  * <script type="text/javascript">
24306  */
24307 /**
24308  * @class Roo.dd.DropZone
24309  * @extends Roo.dd.DropTarget
24310  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24311  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24312  * @constructor
24313  * @param {String/HTMLElement/Element} el The container element
24314  * @param {Object} config
24315  */
24316 Roo.dd.DropZone = function(el, config){
24317     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24318 };
24319
24320 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24321     /**
24322      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24323      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24324      * provide your own custom lookup.
24325      * @param {Event} e The event
24326      * @return {Object} data The custom data
24327      */
24328     getTargetFromEvent : function(e){
24329         return Roo.dd.Registry.getTargetFromEvent(e);
24330     },
24331
24332     /**
24333      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24334      * that it has registered.  This method has no default implementation and should be overridden to provide
24335      * node-specific processing if necessary.
24336      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24337      * {@link #getTargetFromEvent} for this node)
24338      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24339      * @param {Event} e The event
24340      * @param {Object} data An object containing arbitrary data supplied by the drag source
24341      */
24342     onNodeEnter : function(n, dd, e, data){
24343         
24344     },
24345
24346     /**
24347      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24348      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24349      * overridden to provide the proper feedback.
24350      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24351      * {@link #getTargetFromEvent} for this node)
24352      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24353      * @param {Event} e The event
24354      * @param {Object} data An object containing arbitrary data supplied by the drag source
24355      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24356      * underlying {@link Roo.dd.StatusProxy} can be updated
24357      */
24358     onNodeOver : function(n, dd, e, data){
24359         return this.dropAllowed;
24360     },
24361
24362     /**
24363      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24364      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24365      * node-specific processing if necessary.
24366      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24367      * {@link #getTargetFromEvent} for this node)
24368      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24369      * @param {Event} e The event
24370      * @param {Object} data An object containing arbitrary data supplied by the drag source
24371      */
24372     onNodeOut : function(n, dd, e, data){
24373         
24374     },
24375
24376     /**
24377      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24378      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24379      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24380      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24381      * {@link #getTargetFromEvent} for this node)
24382      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24383      * @param {Event} e The event
24384      * @param {Object} data An object containing arbitrary data supplied by the drag source
24385      * @return {Boolean} True if the drop was valid, else false
24386      */
24387     onNodeDrop : function(n, dd, e, data){
24388         return false;
24389     },
24390
24391     /**
24392      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24393      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24394      * it should be overridden to provide the proper feedback if necessary.
24395      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24396      * @param {Event} e The event
24397      * @param {Object} data An object containing arbitrary data supplied by the drag source
24398      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24399      * underlying {@link Roo.dd.StatusProxy} can be updated
24400      */
24401     onContainerOver : function(dd, e, data){
24402         return this.dropNotAllowed;
24403     },
24404
24405     /**
24406      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24407      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24408      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24409      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24410      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24411      * @param {Event} e The event
24412      * @param {Object} data An object containing arbitrary data supplied by the drag source
24413      * @return {Boolean} True if the drop was valid, else false
24414      */
24415     onContainerDrop : function(dd, e, data){
24416         return false;
24417     },
24418
24419     /**
24420      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24421      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24422      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24423      * you should override this method and provide a custom implementation.
24424      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24425      * @param {Event} e The event
24426      * @param {Object} data An object containing arbitrary data supplied by the drag source
24427      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24428      * underlying {@link Roo.dd.StatusProxy} can be updated
24429      */
24430     notifyEnter : function(dd, e, data){
24431         return this.dropNotAllowed;
24432     },
24433
24434     /**
24435      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24436      * This method will be called on every mouse movement while the drag source is over the drop zone.
24437      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24438      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24439      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24440      * registered node, it will call {@link #onContainerOver}.
24441      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24442      * @param {Event} e The event
24443      * @param {Object} data An object containing arbitrary data supplied by the drag source
24444      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24445      * underlying {@link Roo.dd.StatusProxy} can be updated
24446      */
24447     notifyOver : function(dd, e, data){
24448         var n = this.getTargetFromEvent(e);
24449         if(!n){ // not over valid drop target
24450             if(this.lastOverNode){
24451                 this.onNodeOut(this.lastOverNode, dd, e, data);
24452                 this.lastOverNode = null;
24453             }
24454             return this.onContainerOver(dd, e, data);
24455         }
24456         if(this.lastOverNode != n){
24457             if(this.lastOverNode){
24458                 this.onNodeOut(this.lastOverNode, dd, e, data);
24459             }
24460             this.onNodeEnter(n, dd, e, data);
24461             this.lastOverNode = n;
24462         }
24463         return this.onNodeOver(n, dd, e, data);
24464     },
24465
24466     /**
24467      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24468      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24469      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24470      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24471      * @param {Event} e The event
24472      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24473      */
24474     notifyOut : function(dd, e, data){
24475         if(this.lastOverNode){
24476             this.onNodeOut(this.lastOverNode, dd, e, data);
24477             this.lastOverNode = null;
24478         }
24479     },
24480
24481     /**
24482      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24483      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24484      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24485      * otherwise it will call {@link #onContainerDrop}.
24486      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24487      * @param {Event} e The event
24488      * @param {Object} data An object containing arbitrary data supplied by the drag source
24489      * @return {Boolean} True if the drop was valid, else false
24490      */
24491     notifyDrop : function(dd, e, data){
24492         if(this.lastOverNode){
24493             this.onNodeOut(this.lastOverNode, dd, e, data);
24494             this.lastOverNode = null;
24495         }
24496         var n = this.getTargetFromEvent(e);
24497         return n ?
24498             this.onNodeDrop(n, dd, e, data) :
24499             this.onContainerDrop(dd, e, data);
24500     },
24501
24502     // private
24503     triggerCacheRefresh : function(){
24504         Roo.dd.DDM.refreshCache(this.groups);
24505     }  
24506 });