roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             console.log(s);
346             
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isGecko : isGecko,
634         /** @type Boolean */
635         isBorderBox : isBorderBox,
636         /** @type Boolean */
637         isWindows : isWindows,
638         /** @type Boolean */
639         isLinux : isLinux,
640         /** @type Boolean */
641         isMac : isMac,
642         /** @type Boolean */
643         isIOS : isIOS,
644         /** @type Boolean */
645         isAndroid : isAndroid,
646         /** @type Boolean */
647         isTouch : isTouch,
648
649         /**
650          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
651          * you may want to set this to true.
652          * @type Boolean
653          */
654         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655         
656         
657                 
658         /**
659          * Selects a single element as a Roo Element
660          * This is about as close as you can get to jQuery's $('do crazy stuff')
661          * @param {String} selector The selector/xpath query
662          * @param {Node} root (optional) The start of the query (defaults to document).
663          * @return {Roo.Element}
664          */
665         selectNode : function(selector, root) 
666         {
667             var node = Roo.DomQuery.selectNode(selector,root);
668             return node ? Roo.get(node) : new Roo.Element(false);
669         }
670         
671     });
672
673
674 })();
675
676 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
677                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
678                 "Roo.app", "Roo.ux",
679                 "Roo.bootstrap",
680                 "Roo.bootstrap.dash");
681 /*
682  * Based on:
683  * Ext JS Library 1.1.1
684  * Copyright(c) 2006-2007, Ext JS, LLC.
685  *
686  * Originally Released Under LGPL - original licence link has changed is not relivant.
687  *
688  * Fork - LGPL
689  * <script type="text/javascript">
690  */
691
692 (function() {    
693     // wrappedn so fnCleanup is not in global scope...
694     if(Roo.isIE) {
695         function fnCleanUp() {
696             var p = Function.prototype;
697             delete p.createSequence;
698             delete p.defer;
699             delete p.createDelegate;
700             delete p.createCallback;
701             delete p.createInterceptor;
702
703             window.detachEvent("onunload", fnCleanUp);
704         }
705         window.attachEvent("onunload", fnCleanUp);
706     }
707 })();
708
709
710 /**
711  * @class Function
712  * These functions are available on every Function object (any JavaScript function).
713  */
714 Roo.apply(Function.prototype, {
715      /**
716      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
717      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
718      * Will create a function that is bound to those 2 args.
719      * @return {Function} The new function
720     */
721     createCallback : function(/*args...*/){
722         // make args available, in function below
723         var args = arguments;
724         var method = this;
725         return function() {
726             return method.apply(window, args);
727         };
728     },
729
730     /**
731      * Creates a delegate (callback) that sets the scope to obj.
732      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
733      * Will create a function that is automatically scoped to this.
734      * @param {Object} obj (optional) The object for which the scope is set
735      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
736      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
737      *                                             if a number the args are inserted at the specified position
738      * @return {Function} The new function
739      */
740     createDelegate : function(obj, args, appendArgs){
741         var method = this;
742         return function() {
743             var callArgs = args || arguments;
744             if(appendArgs === true){
745                 callArgs = Array.prototype.slice.call(arguments, 0);
746                 callArgs = callArgs.concat(args);
747             }else if(typeof appendArgs == "number"){
748                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
749                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
750                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
751             }
752             return method.apply(obj || window, callArgs);
753         };
754     },
755
756     /**
757      * Calls this function after the number of millseconds specified.
758      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
759      * @param {Object} obj (optional) The object for which the scope is set
760      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762      *                                             if a number the args are inserted at the specified position
763      * @return {Number} The timeout id that can be used with clearTimeout
764      */
765     defer : function(millis, obj, args, appendArgs){
766         var fn = this.createDelegate(obj, args, appendArgs);
767         if(millis){
768             return setTimeout(fn, millis);
769         }
770         fn();
771         return 0;
772     },
773     /**
774      * Create a combined function call sequence of the original function + the passed function.
775      * The resulting function returns the results of the original function.
776      * The passed fcn is called with the parameters of the original function
777      * @param {Function} fcn The function to sequence
778      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
779      * @return {Function} The new function
780      */
781     createSequence : function(fcn, scope){
782         if(typeof fcn != "function"){
783             return this;
784         }
785         var method = this;
786         return function() {
787             var retval = method.apply(this || window, arguments);
788             fcn.apply(scope || this || window, arguments);
789             return retval;
790         };
791     },
792
793     /**
794      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
795      * The resulting function returns the results of the original function.
796      * The passed fcn is called with the parameters of the original function.
797      * @addon
798      * @param {Function} fcn The function to call before the original
799      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
800      * @return {Function} The new function
801      */
802     createInterceptor : function(fcn, scope){
803         if(typeof fcn != "function"){
804             return this;
805         }
806         var method = this;
807         return function() {
808             fcn.target = this;
809             fcn.method = method;
810             if(fcn.apply(scope || this || window, arguments) === false){
811                 return;
812             }
813             return method.apply(this || window, arguments);
814         };
815     }
816 });
817 /*
818  * Based on:
819  * Ext JS Library 1.1.1
820  * Copyright(c) 2006-2007, Ext JS, LLC.
821  *
822  * Originally Released Under LGPL - original licence link has changed is not relivant.
823  *
824  * Fork - LGPL
825  * <script type="text/javascript">
826  */
827
828 Roo.applyIf(String, {
829     
830     /** @scope String */
831     
832     /**
833      * Escapes the passed string for ' and \
834      * @param {String} string The string to escape
835      * @return {String} The escaped string
836      * @static
837      */
838     escape : function(string) {
839         return string.replace(/('|\\)/g, "\\$1");
840     },
841
842     /**
843      * Pads the left side of a string with a specified character.  This is especially useful
844      * for normalizing number and date strings.  Example usage:
845      * <pre><code>
846 var s = String.leftPad('123', 5, '0');
847 // s now contains the string: '00123'
848 </code></pre>
849      * @param {String} string The original string
850      * @param {Number} size The total length of the output string
851      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
852      * @return {String} The padded string
853      * @static
854      */
855     leftPad : function (val, size, ch) {
856         var result = new String(val);
857         if(ch === null || ch === undefined || ch === '') {
858             ch = " ";
859         }
860         while (result.length < size) {
861             result = ch + result;
862         }
863         return result;
864     },
865
866     /**
867      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
868      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
869      * <pre><code>
870 var cls = 'my-class', text = 'Some text';
871 var s = String.format('<div class="{0}">{1}</div>', cls, text);
872 // s now contains the string: '<div class="my-class">Some text</div>'
873 </code></pre>
874      * @param {String} string The tokenized string to be formatted
875      * @param {String} value1 The value to replace token {0}
876      * @param {String} value2 Etc...
877      * @return {String} The formatted string
878      * @static
879      */
880     format : function(format){
881         var args = Array.prototype.slice.call(arguments, 1);
882         return format.replace(/\{(\d+)\}/g, function(m, i){
883             return Roo.util.Format.htmlEncode(args[i]);
884         });
885     }
886 });
887
888 /**
889  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
890  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
891  * they are already different, the first value passed in is returned.  Note that this method returns the new value
892  * but does not change the current string.
893  * <pre><code>
894 // alternate sort directions
895 sort = sort.toggle('ASC', 'DESC');
896
897 // instead of conditional logic:
898 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
899 </code></pre>
900  * @param {String} value The value to compare to the current string
901  * @param {String} other The new value to use if the string already equals the first value passed in
902  * @return {String} The new value
903  */
904  
905 String.prototype.toggle = function(value, other){
906     return this == value ? other : value;
907 };/*
908  * Based on:
909  * Ext JS Library 1.1.1
910  * Copyright(c) 2006-2007, Ext JS, LLC.
911  *
912  * Originally Released Under LGPL - original licence link has changed is not relivant.
913  *
914  * Fork - LGPL
915  * <script type="text/javascript">
916  */
917
918  /**
919  * @class Number
920  */
921 Roo.applyIf(Number.prototype, {
922     /**
923      * Checks whether or not the current number is within a desired range.  If the number is already within the
924      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
925      * exceeded.  Note that this method returns the constrained value but does not change the current number.
926      * @param {Number} min The minimum number in the range
927      * @param {Number} max The maximum number in the range
928      * @return {Number} The constrained value if outside the range, otherwise the current value
929      */
930     constrain : function(min, max){
931         return Math.min(Math.max(this, min), max);
932     }
933 });/*
934  * Based on:
935  * Ext JS Library 1.1.1
936  * Copyright(c) 2006-2007, Ext JS, LLC.
937  *
938  * Originally Released Under LGPL - original licence link has changed is not relivant.
939  *
940  * Fork - LGPL
941  * <script type="text/javascript">
942  */
943  /**
944  * @class Array
945  */
946 Roo.applyIf(Array.prototype, {
947     /**
948      * 
949      * Checks whether or not the specified object exists in the array.
950      * @param {Object} o The object to check for
951      * @return {Number} The index of o in the array (or -1 if it is not found)
952      */
953     indexOf : function(o){
954        for (var i = 0, len = this.length; i < len; i++){
955               if(this[i] == o) { return i; }
956        }
957            return -1;
958     },
959
960     /**
961      * Removes the specified object from the array.  If the object is not found nothing happens.
962      * @param {Object} o The object to remove
963      */
964     remove : function(o){
965        var index = this.indexOf(o);
966        if(index != -1){
967            this.splice(index, 1);
968        }
969     },
970     /**
971      * Map (JS 1.6 compatibility)
972      * @param {Function} function  to call
973      */
974     map : function(fun )
975     {
976         var len = this.length >>> 0;
977         if (typeof fun != "function") {
978             throw new TypeError();
979         }
980         var res = new Array(len);
981         var thisp = arguments[1];
982         for (var i = 0; i < len; i++)
983         {
984             if (i in this) {
985                 res[i] = fun.call(thisp, this[i], i, this);
986             }
987         }
988
989         return res;
990     }
991     
992 });
993
994
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 /**
1008  * @class Date
1009  *
1010  * The date parsing and format syntax is a subset of
1011  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1012  * supported will provide results equivalent to their PHP versions.
1013  *
1014  * Following is the list of all currently supported formats:
1015  *<pre>
1016 Sample date:
1017 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1018
1019 Format  Output      Description
1020 ------  ----------  --------------------------------------------------------------
1021   d      10         Day of the month, 2 digits with leading zeros
1022   D      Wed        A textual representation of a day, three letters
1023   j      10         Day of the month without leading zeros
1024   l      Wednesday  A full textual representation of the day of the week
1025   S      th         English ordinal day of month suffix, 2 chars (use with j)
1026   w      3          Numeric representation of the day of the week
1027   z      9          The julian date, or day of the year (0-365)
1028   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1029   F      January    A full textual representation of the month
1030   m      01         Numeric representation of a month, with leading zeros
1031   M      Jan        Month name abbreviation, three letters
1032   n      1          Numeric representation of a month, without leading zeros
1033   t      31         Number of days in the given month
1034   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1035   Y      2007       A full numeric representation of a year, 4 digits
1036   y      07         A two digit representation of a year
1037   a      pm         Lowercase Ante meridiem and Post meridiem
1038   A      PM         Uppercase Ante meridiem and Post meridiem
1039   g      3          12-hour format of an hour without leading zeros
1040   G      15         24-hour format of an hour without leading zeros
1041   h      03         12-hour format of an hour with leading zeros
1042   H      15         24-hour format of an hour with leading zeros
1043   i      05         Minutes with leading zeros
1044   s      01         Seconds, with leading zeros
1045   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1046   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1047   T      CST        Timezone setting of the machine running the code
1048   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1049 </pre>
1050  *
1051  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1052  * <pre><code>
1053 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1054 document.write(dt.format('Y-m-d'));                         //2007-01-10
1055 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1056 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
1057  </code></pre>
1058  *
1059  * Here are some standard date/time patterns that you might find helpful.  They
1060  * are not part of the source of Date.js, but to use them you can simply copy this
1061  * block of code into any script that is included after Date.js and they will also become
1062  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1063  * <pre><code>
1064 Date.patterns = {
1065     ISO8601Long:"Y-m-d H:i:s",
1066     ISO8601Short:"Y-m-d",
1067     ShortDate: "n/j/Y",
1068     LongDate: "l, F d, Y",
1069     FullDateTime: "l, F d, Y g:i:s A",
1070     MonthDay: "F d",
1071     ShortTime: "g:i A",
1072     LongTime: "g:i:s A",
1073     SortableDateTime: "Y-m-d\\TH:i:s",
1074     UniversalSortableDateTime: "Y-m-d H:i:sO",
1075     YearMonth: "F, Y"
1076 };
1077 </code></pre>
1078  *
1079  * Example usage:
1080  * <pre><code>
1081 var dt = new Date();
1082 document.write(dt.format(Date.patterns.ShortDate));
1083  </code></pre>
1084  */
1085
1086 /*
1087  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1088  * They generate precompiled functions from date formats instead of parsing and
1089  * processing the pattern every time you format a date.  These functions are available
1090  * on every Date object (any javascript function).
1091  *
1092  * The original article and download are here:
1093  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1094  *
1095  */
1096  
1097  
1098  // was in core
1099 /**
1100  Returns the number of milliseconds between this date and date
1101  @param {Date} date (optional) Defaults to now
1102  @return {Number} The diff in milliseconds
1103  @member Date getElapsed
1104  */
1105 Date.prototype.getElapsed = function(date) {
1106         return Math.abs((date || new Date()).getTime()-this.getTime());
1107 };
1108 // was in date file..
1109
1110
1111 // private
1112 Date.parseFunctions = {count:0};
1113 // private
1114 Date.parseRegexes = [];
1115 // private
1116 Date.formatFunctions = {count:0};
1117
1118 // private
1119 Date.prototype.dateFormat = function(format) {
1120     if (Date.formatFunctions[format] == null) {
1121         Date.createNewFormat(format);
1122     }
1123     var func = Date.formatFunctions[format];
1124     return this[func]();
1125 };
1126
1127
1128 /**
1129  * Formats a date given the supplied format string
1130  * @param {String} format The format string
1131  * @return {String} The formatted date
1132  * @method
1133  */
1134 Date.prototype.format = Date.prototype.dateFormat;
1135
1136 // private
1137 Date.createNewFormat = function(format) {
1138     var funcName = "format" + Date.formatFunctions.count++;
1139     Date.formatFunctions[format] = funcName;
1140     var code = "Date.prototype." + funcName + " = function(){return ";
1141     var special = false;
1142     var ch = '';
1143     for (var i = 0; i < format.length; ++i) {
1144         ch = format.charAt(i);
1145         if (!special && ch == "\\") {
1146             special = true;
1147         }
1148         else if (special) {
1149             special = false;
1150             code += "'" + String.escape(ch) + "' + ";
1151         }
1152         else {
1153             code += Date.getFormatCode(ch);
1154         }
1155     }
1156     /** eval:var:zzzzzzzzzzzzz */
1157     eval(code.substring(0, code.length - 3) + ";}");
1158 };
1159
1160 // private
1161 Date.getFormatCode = function(character) {
1162     switch (character) {
1163     case "d":
1164         return "String.leftPad(this.getDate(), 2, '0') + ";
1165     case "D":
1166         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1167     case "j":
1168         return "this.getDate() + ";
1169     case "l":
1170         return "Date.dayNames[this.getDay()] + ";
1171     case "S":
1172         return "this.getSuffix() + ";
1173     case "w":
1174         return "this.getDay() + ";
1175     case "z":
1176         return "this.getDayOfYear() + ";
1177     case "W":
1178         return "this.getWeekOfYear() + ";
1179     case "F":
1180         return "Date.monthNames[this.getMonth()] + ";
1181     case "m":
1182         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1183     case "M":
1184         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1185     case "n":
1186         return "(this.getMonth() + 1) + ";
1187     case "t":
1188         return "this.getDaysInMonth() + ";
1189     case "L":
1190         return "(this.isLeapYear() ? 1 : 0) + ";
1191     case "Y":
1192         return "this.getFullYear() + ";
1193     case "y":
1194         return "('' + this.getFullYear()).substring(2, 4) + ";
1195     case "a":
1196         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1197     case "A":
1198         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1199     case "g":
1200         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1201     case "G":
1202         return "this.getHours() + ";
1203     case "h":
1204         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1205     case "H":
1206         return "String.leftPad(this.getHours(), 2, '0') + ";
1207     case "i":
1208         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1209     case "s":
1210         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1211     case "O":
1212         return "this.getGMTOffset() + ";
1213     case "P":
1214         return "this.getGMTColonOffset() + ";
1215     case "T":
1216         return "this.getTimezone() + ";
1217     case "Z":
1218         return "(this.getTimezoneOffset() * -60) + ";
1219     default:
1220         return "'" + String.escape(character) + "' + ";
1221     }
1222 };
1223
1224 /**
1225  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1226  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1227  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1228  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1229  * string or the parse operation will fail.
1230  * Example Usage:
1231 <pre><code>
1232 //dt = Fri May 25 2007 (current date)
1233 var dt = new Date();
1234
1235 //dt = Thu May 25 2006 (today's month/day in 2006)
1236 dt = Date.parseDate("2006", "Y");
1237
1238 //dt = Sun Jan 15 2006 (all date parts specified)
1239 dt = Date.parseDate("2006-1-15", "Y-m-d");
1240
1241 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1242 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1243 </code></pre>
1244  * @param {String} input The unparsed date as a string
1245  * @param {String} format The format the date is in
1246  * @return {Date} The parsed date
1247  * @static
1248  */
1249 Date.parseDate = function(input, format) {
1250     if (Date.parseFunctions[format] == null) {
1251         Date.createParser(format);
1252     }
1253     var func = Date.parseFunctions[format];
1254     return Date[func](input);
1255 };
1256 /**
1257  * @private
1258  */
1259
1260 Date.createParser = function(format) {
1261     var funcName = "parse" + Date.parseFunctions.count++;
1262     var regexNum = Date.parseRegexes.length;
1263     var currentGroup = 1;
1264     Date.parseFunctions[format] = funcName;
1265
1266     var code = "Date." + funcName + " = function(input){\n"
1267         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1268         + "var d = new Date();\n"
1269         + "y = d.getFullYear();\n"
1270         + "m = d.getMonth();\n"
1271         + "d = d.getDate();\n"
1272         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1273         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1274         + "if (results && results.length > 0) {";
1275     var regex = "";
1276
1277     var special = false;
1278     var ch = '';
1279     for (var i = 0; i < format.length; ++i) {
1280         ch = format.charAt(i);
1281         if (!special && ch == "\\") {
1282             special = true;
1283         }
1284         else if (special) {
1285             special = false;
1286             regex += String.escape(ch);
1287         }
1288         else {
1289             var obj = Date.formatCodeToRegex(ch, currentGroup);
1290             currentGroup += obj.g;
1291             regex += obj.s;
1292             if (obj.g && obj.c) {
1293                 code += obj.c;
1294             }
1295         }
1296     }
1297
1298     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1299         + "{v = new Date(y, m, d, h, i, s);}\n"
1300         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1301         + "{v = new Date(y, m, d, h, i);}\n"
1302         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1303         + "{v = new Date(y, m, d, h);}\n"
1304         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1305         + "{v = new Date(y, m, d);}\n"
1306         + "else if (y >= 0 && m >= 0)\n"
1307         + "{v = new Date(y, m);}\n"
1308         + "else if (y >= 0)\n"
1309         + "{v = new Date(y);}\n"
1310         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1311         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1312         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1313         + ";}";
1314
1315     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1316     /** eval:var:zzzzzzzzzzzzz */
1317     eval(code);
1318 };
1319
1320 // private
1321 Date.formatCodeToRegex = function(character, currentGroup) {
1322     switch (character) {
1323     case "D":
1324         return {g:0,
1325         c:null,
1326         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1327     case "j":
1328         return {g:1,
1329             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330             s:"(\\d{1,2})"}; // day of month without leading zeroes
1331     case "d":
1332         return {g:1,
1333             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1334             s:"(\\d{2})"}; // day of month with leading zeroes
1335     case "l":
1336         return {g:0,
1337             c:null,
1338             s:"(?:" + Date.dayNames.join("|") + ")"};
1339     case "S":
1340         return {g:0,
1341             c:null,
1342             s:"(?:st|nd|rd|th)"};
1343     case "w":
1344         return {g:0,
1345             c:null,
1346             s:"\\d"};
1347     case "z":
1348         return {g:0,
1349             c:null,
1350             s:"(?:\\d{1,3})"};
1351     case "W":
1352         return {g:0,
1353             c:null,
1354             s:"(?:\\d{2})"};
1355     case "F":
1356         return {g:1,
1357             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1358             s:"(" + Date.monthNames.join("|") + ")"};
1359     case "M":
1360         return {g:1,
1361             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1362             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1363     case "n":
1364         return {g:1,
1365             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1367     case "m":
1368         return {g:1,
1369             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1370             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1371     case "t":
1372         return {g:0,
1373             c:null,
1374             s:"\\d{1,2}"};
1375     case "L":
1376         return {g:0,
1377             c:null,
1378             s:"(?:1|0)"};
1379     case "Y":
1380         return {g:1,
1381             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1382             s:"(\\d{4})"};
1383     case "y":
1384         return {g:1,
1385             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1386                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1387             s:"(\\d{1,2})"};
1388     case "a":
1389         return {g:1,
1390             c:"if (results[" + currentGroup + "] == 'am') {\n"
1391                 + "if (h == 12) { h = 0; }\n"
1392                 + "} else { if (h < 12) { h += 12; }}",
1393             s:"(am|pm)"};
1394     case "A":
1395         return {g:1,
1396             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1397                 + "if (h == 12) { h = 0; }\n"
1398                 + "} else { if (h < 12) { h += 12; }}",
1399             s:"(AM|PM)"};
1400     case "g":
1401     case "G":
1402         return {g:1,
1403             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1404             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1405     case "h":
1406     case "H":
1407         return {g:1,
1408             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1409             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1410     case "i":
1411         return {g:1,
1412             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1413             s:"(\\d{2})"};
1414     case "s":
1415         return {g:1,
1416             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417             s:"(\\d{2})"};
1418     case "O":
1419         return {g:1,
1420             c:[
1421                 "o = results[", currentGroup, "];\n",
1422                 "var sn = o.substring(0,1);\n", // get + / - sign
1423                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1424                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1425                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1426                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1427             ].join(""),
1428             s:"([+\-]\\d{2,4})"};
1429     
1430     
1431     case "P":
1432         return {g:1,
1433                 c:[
1434                    "o = results[", currentGroup, "];\n",
1435                    "var sn = o.substring(0,1);\n",
1436                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1437                    "var mn = o.substring(4,6) % 60;\n",
1438                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1439                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1440             ].join(""),
1441             s:"([+\-]\\d{4})"};
1442     case "T":
1443         return {g:0,
1444             c:null,
1445             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1446     case "Z":
1447         return {g:1,
1448             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1449                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1450             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1451     default:
1452         return {g:0,
1453             c:null,
1454             s:String.escape(character)};
1455     }
1456 };
1457
1458 /**
1459  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1460  * @return {String} The abbreviated timezone name (e.g. 'CST')
1461  */
1462 Date.prototype.getTimezone = function() {
1463     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1464 };
1465
1466 /**
1467  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1468  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1469  */
1470 Date.prototype.getGMTOffset = function() {
1471     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1472         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1473         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1474 };
1475
1476 /**
1477  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1478  * @return {String} 2-characters representing hours and 2-characters representing minutes
1479  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1480  */
1481 Date.prototype.getGMTColonOffset = function() {
1482         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1483                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1484                 + ":"
1485                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1486 }
1487
1488 /**
1489  * Get the numeric day number of the year, adjusted for leap year.
1490  * @return {Number} 0 through 364 (365 in leap years)
1491  */
1492 Date.prototype.getDayOfYear = function() {
1493     var num = 0;
1494     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1495     for (var i = 0; i < this.getMonth(); ++i) {
1496         num += Date.daysInMonth[i];
1497     }
1498     return num + this.getDate() - 1;
1499 };
1500
1501 /**
1502  * Get the string representation of the numeric week number of the year
1503  * (equivalent to the format specifier 'W').
1504  * @return {String} '00' through '52'
1505  */
1506 Date.prototype.getWeekOfYear = function() {
1507     // Skip to Thursday of this week
1508     var now = this.getDayOfYear() + (4 - this.getDay());
1509     // Find the first Thursday of the year
1510     var jan1 = new Date(this.getFullYear(), 0, 1);
1511     var then = (7 - jan1.getDay() + 4);
1512     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1513 };
1514
1515 /**
1516  * Whether or not the current date is in a leap year.
1517  * @return {Boolean} True if the current date is in a leap year, else false
1518  */
1519 Date.prototype.isLeapYear = function() {
1520     var year = this.getFullYear();
1521     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1522 };
1523
1524 /**
1525  * Get the first day of the current month, adjusted for leap year.  The returned value
1526  * is the numeric day index within the week (0-6) which can be used in conjunction with
1527  * the {@link #monthNames} array to retrieve the textual day name.
1528  * Example:
1529  *<pre><code>
1530 var dt = new Date('1/10/2007');
1531 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1532 </code></pre>
1533  * @return {Number} The day number (0-6)
1534  */
1535 Date.prototype.getFirstDayOfMonth = function() {
1536     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1537     return (day < 0) ? (day + 7) : day;
1538 };
1539
1540 /**
1541  * Get the last day of the current month, adjusted for leap year.  The returned value
1542  * is the numeric day index within the week (0-6) which can be used in conjunction with
1543  * the {@link #monthNames} array to retrieve the textual day name.
1544  * Example:
1545  *<pre><code>
1546 var dt = new Date('1/10/2007');
1547 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1548 </code></pre>
1549  * @return {Number} The day number (0-6)
1550  */
1551 Date.prototype.getLastDayOfMonth = function() {
1552     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1553     return (day < 0) ? (day + 7) : day;
1554 };
1555
1556
1557 /**
1558  * Get the first date of this date's month
1559  * @return {Date}
1560  */
1561 Date.prototype.getFirstDateOfMonth = function() {
1562     return new Date(this.getFullYear(), this.getMonth(), 1);
1563 };
1564
1565 /**
1566  * Get the last date of this date's month
1567  * @return {Date}
1568  */
1569 Date.prototype.getLastDateOfMonth = function() {
1570     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1571 };
1572 /**
1573  * Get the number of days in the current month, adjusted for leap year.
1574  * @return {Number} The number of days in the month
1575  */
1576 Date.prototype.getDaysInMonth = function() {
1577     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1578     return Date.daysInMonth[this.getMonth()];
1579 };
1580
1581 /**
1582  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1583  * @return {String} 'st, 'nd', 'rd' or 'th'
1584  */
1585 Date.prototype.getSuffix = function() {
1586     switch (this.getDate()) {
1587         case 1:
1588         case 21:
1589         case 31:
1590             return "st";
1591         case 2:
1592         case 22:
1593             return "nd";
1594         case 3:
1595         case 23:
1596             return "rd";
1597         default:
1598             return "th";
1599     }
1600 };
1601
1602 // private
1603 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1604
1605 /**
1606  * An array of textual month names.
1607  * Override these values for international dates, for example...
1608  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1609  * @type Array
1610  * @static
1611  */
1612 Date.monthNames =
1613    ["January",
1614     "February",
1615     "March",
1616     "April",
1617     "May",
1618     "June",
1619     "July",
1620     "August",
1621     "September",
1622     "October",
1623     "November",
1624     "December"];
1625
1626 /**
1627  * An array of textual day names.
1628  * Override these values for international dates, for example...
1629  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1630  * @type Array
1631  * @static
1632  */
1633 Date.dayNames =
1634    ["Sunday",
1635     "Monday",
1636     "Tuesday",
1637     "Wednesday",
1638     "Thursday",
1639     "Friday",
1640     "Saturday"];
1641
1642 // private
1643 Date.y2kYear = 50;
1644 // private
1645 Date.monthNumbers = {
1646     Jan:0,
1647     Feb:1,
1648     Mar:2,
1649     Apr:3,
1650     May:4,
1651     Jun:5,
1652     Jul:6,
1653     Aug:7,
1654     Sep:8,
1655     Oct:9,
1656     Nov:10,
1657     Dec:11};
1658
1659 /**
1660  * Creates and returns a new Date instance with the exact same date value as the called instance.
1661  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1662  * variable will also be changed.  When the intention is to create a new variable that will not
1663  * modify the original instance, you should create a clone.
1664  *
1665  * Example of correctly cloning a date:
1666  * <pre><code>
1667 //wrong way:
1668 var orig = new Date('10/1/2006');
1669 var copy = orig;
1670 copy.setDate(5);
1671 document.write(orig);  //returns 'Thu Oct 05 2006'!
1672
1673 //correct way:
1674 var orig = new Date('10/1/2006');
1675 var copy = orig.clone();
1676 copy.setDate(5);
1677 document.write(orig);  //returns 'Thu Oct 01 2006'
1678 </code></pre>
1679  * @return {Date} The new Date instance
1680  */
1681 Date.prototype.clone = function() {
1682         return new Date(this.getTime());
1683 };
1684
1685 /**
1686  * Clears any time information from this date
1687  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1688  @return {Date} this or the clone
1689  */
1690 Date.prototype.clearTime = function(clone){
1691     if(clone){
1692         return this.clone().clearTime();
1693     }
1694     this.setHours(0);
1695     this.setMinutes(0);
1696     this.setSeconds(0);
1697     this.setMilliseconds(0);
1698     return this;
1699 };
1700
1701 // private
1702 // safari setMonth is broken -- check that this is only donw once...
1703 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1704     Date.brokenSetMonth = Date.prototype.setMonth;
1705         Date.prototype.setMonth = function(num){
1706                 if(num <= -1){
1707                         var n = Math.ceil(-num);
1708                         var back_year = Math.ceil(n/12);
1709                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1710                         this.setFullYear(this.getFullYear() - back_year);
1711                         return Date.brokenSetMonth.call(this, month);
1712                 } else {
1713                         return Date.brokenSetMonth.apply(this, arguments);
1714                 }
1715         };
1716 }
1717
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.MILLI = "ms";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.SECOND = "s";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.MINUTE = "mi";
1730 /** Date interval constant 
1731 * @static 
1732 * @type String */
1733 Date.HOUR = "h";
1734 /** Date interval constant 
1735 * @static 
1736 * @type String */
1737 Date.DAY = "d";
1738 /** Date interval constant 
1739 * @static 
1740 * @type String */
1741 Date.MONTH = "mo";
1742 /** Date interval constant 
1743 * @static 
1744 * @type String */
1745 Date.YEAR = "y";
1746
1747 /**
1748  * Provides a convenient method of performing basic date arithmetic.  This method
1749  * does not modify the Date instance being called - it creates and returns
1750  * a new Date instance containing the resulting date value.
1751  *
1752  * Examples:
1753  * <pre><code>
1754 //Basic usage:
1755 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1756 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1757
1758 //Negative values will subtract correctly:
1759 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1760 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1761
1762 //You can even chain several calls together in one line!
1763 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1764 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1765  </code></pre>
1766  *
1767  * @param {String} interval   A valid date interval enum value
1768  * @param {Number} value      The amount to add to the current date
1769  * @return {Date} The new Date instance
1770  */
1771 Date.prototype.add = function(interval, value){
1772   var d = this.clone();
1773   if (!interval || value === 0) { return d; }
1774   switch(interval.toLowerCase()){
1775     case Date.MILLI:
1776       d.setMilliseconds(this.getMilliseconds() + value);
1777       break;
1778     case Date.SECOND:
1779       d.setSeconds(this.getSeconds() + value);
1780       break;
1781     case Date.MINUTE:
1782       d.setMinutes(this.getMinutes() + value);
1783       break;
1784     case Date.HOUR:
1785       d.setHours(this.getHours() + value);
1786       break;
1787     case Date.DAY:
1788       d.setDate(this.getDate() + value);
1789       break;
1790     case Date.MONTH:
1791       var day = this.getDate();
1792       if(day > 28){
1793           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1794       }
1795       d.setDate(day);
1796       d.setMonth(this.getMonth() + value);
1797       break;
1798     case Date.YEAR:
1799       d.setFullYear(this.getFullYear() + value);
1800       break;
1801   }
1802   return d;
1803 };
1804 /*
1805  * Based on:
1806  * Ext JS Library 1.1.1
1807  * Copyright(c) 2006-2007, Ext JS, LLC.
1808  *
1809  * Originally Released Under LGPL - original licence link has changed is not relivant.
1810  *
1811  * Fork - LGPL
1812  * <script type="text/javascript">
1813  */
1814
1815 /**
1816  * @class Roo.lib.Dom
1817  * @static
1818  * 
1819  * Dom utils (from YIU afaik)
1820  * 
1821  **/
1822 Roo.lib.Dom = {
1823     /**
1824      * Get the view width
1825      * @param {Boolean} full True will get the full document, otherwise it's the view width
1826      * @return {Number} The width
1827      */
1828      
1829     getViewWidth : function(full) {
1830         return full ? this.getDocumentWidth() : this.getViewportWidth();
1831     },
1832     /**
1833      * Get the view height
1834      * @param {Boolean} full True will get the full document, otherwise it's the view height
1835      * @return {Number} The height
1836      */
1837     getViewHeight : function(full) {
1838         return full ? this.getDocumentHeight() : this.getViewportHeight();
1839     },
1840
1841     getDocumentHeight: function() {
1842         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1843         return Math.max(scrollHeight, this.getViewportHeight());
1844     },
1845
1846     getDocumentWidth: function() {
1847         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1848         return Math.max(scrollWidth, this.getViewportWidth());
1849     },
1850
1851     getViewportHeight: function() {
1852         var height = self.innerHeight;
1853         var mode = document.compatMode;
1854
1855         if ((mode || Roo.isIE) && !Roo.isOpera) {
1856             height = (mode == "CSS1Compat") ?
1857                      document.documentElement.clientHeight :
1858                      document.body.clientHeight;
1859         }
1860
1861         return height;
1862     },
1863
1864     getViewportWidth: function() {
1865         var width = self.innerWidth;
1866         var mode = document.compatMode;
1867
1868         if (mode || Roo.isIE) {
1869             width = (mode == "CSS1Compat") ?
1870                     document.documentElement.clientWidth :
1871                     document.body.clientWidth;
1872         }
1873         return width;
1874     },
1875
1876     isAncestor : function(p, c) {
1877         p = Roo.getDom(p);
1878         c = Roo.getDom(c);
1879         if (!p || !c) {
1880             return false;
1881         }
1882
1883         if (p.contains && !Roo.isSafari) {
1884             return p.contains(c);
1885         } else if (p.compareDocumentPosition) {
1886             return !!(p.compareDocumentPosition(c) & 16);
1887         } else {
1888             var parent = c.parentNode;
1889             while (parent) {
1890                 if (parent == p) {
1891                     return true;
1892                 }
1893                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1894                     return false;
1895                 }
1896                 parent = parent.parentNode;
1897             }
1898             return false;
1899         }
1900     },
1901
1902     getRegion : function(el) {
1903         return Roo.lib.Region.getRegion(el);
1904     },
1905
1906     getY : function(el) {
1907         return this.getXY(el)[1];
1908     },
1909
1910     getX : function(el) {
1911         return this.getXY(el)[0];
1912     },
1913
1914     getXY : function(el) {
1915         var p, pe, b, scroll, bd = document.body;
1916         el = Roo.getDom(el);
1917         var fly = Roo.lib.AnimBase.fly;
1918         if (el.getBoundingClientRect) {
1919             b = el.getBoundingClientRect();
1920             scroll = fly(document).getScroll();
1921             return [b.left + scroll.left, b.top + scroll.top];
1922         }
1923         var x = 0, y = 0;
1924
1925         p = el;
1926
1927         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1928
1929         while (p) {
1930
1931             x += p.offsetLeft;
1932             y += p.offsetTop;
1933
1934             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1935                 hasAbsolute = true;
1936             }
1937
1938             if (Roo.isGecko) {
1939                 pe = fly(p);
1940
1941                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1942                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1943
1944
1945                 x += bl;
1946                 y += bt;
1947
1948
1949                 if (p != el && pe.getStyle('overflow') != 'visible') {
1950                     x += bl;
1951                     y += bt;
1952                 }
1953             }
1954             p = p.offsetParent;
1955         }
1956
1957         if (Roo.isSafari && hasAbsolute) {
1958             x -= bd.offsetLeft;
1959             y -= bd.offsetTop;
1960         }
1961
1962         if (Roo.isGecko && !hasAbsolute) {
1963             var dbd = fly(bd);
1964             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1965             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1966         }
1967
1968         p = el.parentNode;
1969         while (p && p != bd) {
1970             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1971                 x -= p.scrollLeft;
1972                 y -= p.scrollTop;
1973             }
1974             p = p.parentNode;
1975         }
1976         return [x, y];
1977     },
1978  
1979   
1980
1981
1982     setXY : function(el, xy) {
1983         el = Roo.fly(el, '_setXY');
1984         el.position();
1985         var pts = el.translatePoints(xy);
1986         if (xy[0] !== false) {
1987             el.dom.style.left = pts.left + "px";
1988         }
1989         if (xy[1] !== false) {
1990             el.dom.style.top = pts.top + "px";
1991         }
1992     },
1993
1994     setX : function(el, x) {
1995         this.setXY(el, [x, false]);
1996     },
1997
1998     setY : function(el, y) {
1999         this.setXY(el, [false, y]);
2000     }
2001 };
2002 /*
2003  * Portions of this file are based on pieces of Yahoo User Interface Library
2004  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2005  * YUI licensed under the BSD License:
2006  * http://developer.yahoo.net/yui/license.txt
2007  * <script type="text/javascript">
2008  *
2009  */
2010
2011 Roo.lib.Event = function() {
2012     var loadComplete = false;
2013     var listeners = [];
2014     var unloadListeners = [];
2015     var retryCount = 0;
2016     var onAvailStack = [];
2017     var counter = 0;
2018     var lastError = null;
2019
2020     return {
2021         POLL_RETRYS: 200,
2022         POLL_INTERVAL: 20,
2023         EL: 0,
2024         TYPE: 1,
2025         FN: 2,
2026         WFN: 3,
2027         OBJ: 3,
2028         ADJ_SCOPE: 4,
2029         _interval: null,
2030
2031         startInterval: function() {
2032             if (!this._interval) {
2033                 var self = this;
2034                 var callback = function() {
2035                     self._tryPreloadAttach();
2036                 };
2037                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038
2039             }
2040         },
2041
2042         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2043             onAvailStack.push({ id:         p_id,
2044                 fn:         p_fn,
2045                 obj:        p_obj,
2046                 override:   p_override,
2047                 checkReady: false    });
2048
2049             retryCount = this.POLL_RETRYS;
2050             this.startInterval();
2051         },
2052
2053
2054         addListener: function(el, eventName, fn) {
2055             el = Roo.getDom(el);
2056             if (!el || !fn) {
2057                 return false;
2058             }
2059
2060             if ("unload" == eventName) {
2061                 unloadListeners[unloadListeners.length] =
2062                 [el, eventName, fn];
2063                 return true;
2064             }
2065
2066             var wrappedFn = function(e) {
2067                 return fn(Roo.lib.Event.getEvent(e));
2068             };
2069
2070             var li = [el, eventName, fn, wrappedFn];
2071
2072             var index = listeners.length;
2073             listeners[index] = li;
2074
2075             this.doAdd(el, eventName, wrappedFn, false);
2076             return true;
2077
2078         },
2079
2080
2081         removeListener: function(el, eventName, fn) {
2082             var i, len;
2083
2084             el = Roo.getDom(el);
2085
2086             if(!fn) {
2087                 return this.purgeElement(el, false, eventName);
2088             }
2089
2090
2091             if ("unload" == eventName) {
2092
2093                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2094                     var li = unloadListeners[i];
2095                     if (li &&
2096                         li[0] == el &&
2097                         li[1] == eventName &&
2098                         li[2] == fn) {
2099                         unloadListeners.splice(i, 1);
2100                         return true;
2101                     }
2102                 }
2103
2104                 return false;
2105             }
2106
2107             var cacheItem = null;
2108
2109
2110             var index = arguments[3];
2111
2112             if ("undefined" == typeof index) {
2113                 index = this._getCacheIndex(el, eventName, fn);
2114             }
2115
2116             if (index >= 0) {
2117                 cacheItem = listeners[index];
2118             }
2119
2120             if (!el || !cacheItem) {
2121                 return false;
2122             }
2123
2124             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2125
2126             delete listeners[index][this.WFN];
2127             delete listeners[index][this.FN];
2128             listeners.splice(index, 1);
2129
2130             return true;
2131
2132         },
2133
2134
2135         getTarget: function(ev, resolveTextNode) {
2136             ev = ev.browserEvent || ev;
2137             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2138             var t = ev.target || ev.srcElement;
2139             return this.resolveTextNode(t);
2140         },
2141
2142
2143         resolveTextNode: function(node) {
2144             if (Roo.isSafari && node && 3 == node.nodeType) {
2145                 return node.parentNode;
2146             } else {
2147                 return node;
2148             }
2149         },
2150
2151
2152         getPageX: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2155             var x = ev.pageX;
2156             if (!x && 0 !== x) {
2157                 x = ev.clientX || 0;
2158
2159                 if (Roo.isIE) {
2160                     x += this.getScroll()[1];
2161                 }
2162             }
2163
2164             return x;
2165         },
2166
2167
2168         getPageY: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2171             var y = ev.pageY;
2172             if (!y && 0 !== y) {
2173                 y = ev.clientY || 0;
2174
2175                 if (Roo.isIE) {
2176                     y += this.getScroll()[0];
2177                 }
2178             }
2179
2180
2181             return y;
2182         },
2183
2184
2185         getXY: function(ev) {
2186             ev = ev.browserEvent || ev;
2187             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2188             return [this.getPageX(ev), this.getPageY(ev)];
2189         },
2190
2191
2192         getRelatedTarget: function(ev) {
2193             ev = ev.browserEvent || ev;
2194             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2195             var t = ev.relatedTarget;
2196             if (!t) {
2197                 if (ev.type == "mouseout") {
2198                     t = ev.toElement;
2199                 } else if (ev.type == "mouseover") {
2200                     t = ev.fromElement;
2201                 }
2202             }
2203
2204             return this.resolveTextNode(t);
2205         },
2206
2207
2208         getTime: function(ev) {
2209             ev = ev.browserEvent || ev;
2210             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2211             if (!ev.time) {
2212                 var t = new Date().getTime();
2213                 try {
2214                     ev.time = t;
2215                 } catch(ex) {
2216                     this.lastError = ex;
2217                     return t;
2218                 }
2219             }
2220
2221             return ev.time;
2222         },
2223
2224
2225         stopEvent: function(ev) {
2226             this.stopPropagation(ev);
2227             this.preventDefault(ev);
2228         },
2229
2230
2231         stopPropagation: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             if (ev.stopPropagation) {
2234                 ev.stopPropagation();
2235             } else {
2236                 ev.cancelBubble = true;
2237             }
2238         },
2239
2240
2241         preventDefault: function(ev) {
2242             ev = ev.browserEvent || ev;
2243             if(ev.preventDefault) {
2244                 ev.preventDefault();
2245             } else {
2246                 ev.returnValue = false;
2247             }
2248         },
2249
2250
2251         getEvent: function(e) {
2252             var ev = e || window.event;
2253             if (!ev) {
2254                 var c = this.getEvent.caller;
2255                 while (c) {
2256                     ev = c.arguments[0];
2257                     if (ev && Event == ev.constructor) {
2258                         break;
2259                     }
2260                     c = c.caller;
2261                 }
2262             }
2263             return ev;
2264         },
2265
2266
2267         getCharCode: function(ev) {
2268             ev = ev.browserEvent || ev;
2269             return ev.charCode || ev.keyCode || 0;
2270         },
2271
2272
2273         _getCacheIndex: function(el, eventName, fn) {
2274             for (var i = 0,len = listeners.length; i < len; ++i) {
2275                 var li = listeners[i];
2276                 if (li &&
2277                     li[this.FN] == fn &&
2278                     li[this.EL] == el &&
2279                     li[this.TYPE] == eventName) {
2280                     return i;
2281                 }
2282             }
2283
2284             return -1;
2285         },
2286
2287
2288         elCache: {},
2289
2290
2291         getEl: function(id) {
2292             return document.getElementById(id);
2293         },
2294
2295
2296         clearCache: function() {
2297         },
2298
2299
2300         _load: function(e) {
2301             loadComplete = true;
2302             var EU = Roo.lib.Event;
2303
2304
2305             if (Roo.isIE) {
2306                 EU.doRemove(window, "load", EU._load);
2307             }
2308         },
2309
2310
2311         _tryPreloadAttach: function() {
2312
2313             if (this.locked) {
2314                 return false;
2315             }
2316
2317             this.locked = true;
2318
2319
2320             var tryAgain = !loadComplete;
2321             if (!tryAgain) {
2322                 tryAgain = (retryCount > 0);
2323             }
2324
2325
2326             var notAvail = [];
2327             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2328                 var item = onAvailStack[i];
2329                 if (item) {
2330                     var el = this.getEl(item.id);
2331
2332                     if (el) {
2333                         if (!item.checkReady ||
2334                             loadComplete ||
2335                             el.nextSibling ||
2336                             (document && document.body)) {
2337
2338                             var scope = el;
2339                             if (item.override) {
2340                                 if (item.override === true) {
2341                                     scope = item.obj;
2342                                 } else {
2343                                     scope = item.override;
2344                                 }
2345                             }
2346                             item.fn.call(scope, item.obj);
2347                             onAvailStack[i] = null;
2348                         }
2349                     } else {
2350                         notAvail.push(item);
2351                     }
2352                 }
2353             }
2354
2355             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2356
2357             if (tryAgain) {
2358
2359                 this.startInterval();
2360             } else {
2361                 clearInterval(this._interval);
2362                 this._interval = null;
2363             }
2364
2365             this.locked = false;
2366
2367             return true;
2368
2369         },
2370
2371
2372         purgeElement: function(el, recurse, eventName) {
2373             var elListeners = this.getListeners(el, eventName);
2374             if (elListeners) {
2375                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2376                     var l = elListeners[i];
2377                     this.removeListener(el, l.type, l.fn);
2378                 }
2379             }
2380
2381             if (recurse && el && el.childNodes) {
2382                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2383                     this.purgeElement(el.childNodes[i], recurse, eventName);
2384                 }
2385             }
2386         },
2387
2388
2389         getListeners: function(el, eventName) {
2390             var results = [], searchLists;
2391             if (!eventName) {
2392                 searchLists = [listeners, unloadListeners];
2393             } else if (eventName == "unload") {
2394                 searchLists = [unloadListeners];
2395             } else {
2396                 searchLists = [listeners];
2397             }
2398
2399             for (var j = 0; j < searchLists.length; ++j) {
2400                 var searchList = searchLists[j];
2401                 if (searchList && searchList.length > 0) {
2402                     for (var i = 0,len = searchList.length; i < len; ++i) {
2403                         var l = searchList[i];
2404                         if (l && l[this.EL] === el &&
2405                             (!eventName || eventName === l[this.TYPE])) {
2406                             results.push({
2407                                 type:   l[this.TYPE],
2408                                 fn:     l[this.FN],
2409                                 obj:    l[this.OBJ],
2410                                 adjust: l[this.ADJ_SCOPE],
2411                                 index:  i
2412                             });
2413                         }
2414                     }
2415                 }
2416             }
2417
2418             return (results.length) ? results : null;
2419         },
2420
2421
2422         _unload: function(e) {
2423
2424             var EU = Roo.lib.Event, i, j, l, len, index;
2425
2426             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2427                 l = unloadListeners[i];
2428                 if (l) {
2429                     var scope = window;
2430                     if (l[EU.ADJ_SCOPE]) {
2431                         if (l[EU.ADJ_SCOPE] === true) {
2432                             scope = l[EU.OBJ];
2433                         } else {
2434                             scope = l[EU.ADJ_SCOPE];
2435                         }
2436                     }
2437                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2438                     unloadListeners[i] = null;
2439                     l = null;
2440                     scope = null;
2441                 }
2442             }
2443
2444             unloadListeners = null;
2445
2446             if (listeners && listeners.length > 0) {
2447                 j = listeners.length;
2448                 while (j) {
2449                     index = j - 1;
2450                     l = listeners[index];
2451                     if (l) {
2452                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2453                                 l[EU.FN], index);
2454                     }
2455                     j = j - 1;
2456                 }
2457                 l = null;
2458
2459                 EU.clearCache();
2460             }
2461
2462             EU.doRemove(window, "unload", EU._unload);
2463
2464         },
2465
2466
2467         getScroll: function() {
2468             var dd = document.documentElement, db = document.body;
2469             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2470                 return [dd.scrollTop, dd.scrollLeft];
2471             } else if (db) {
2472                 return [db.scrollTop, db.scrollLeft];
2473             } else {
2474                 return [0, 0];
2475             }
2476         },
2477
2478
2479         doAdd: function () {
2480             if (window.addEventListener) {
2481                 return function(el, eventName, fn, capture) {
2482                     el.addEventListener(eventName, fn, (capture));
2483                 };
2484             } else if (window.attachEvent) {
2485                 return function(el, eventName, fn, capture) {
2486                     el.attachEvent("on" + eventName, fn);
2487                 };
2488             } else {
2489                 return function() {
2490                 };
2491             }
2492         }(),
2493
2494
2495         doRemove: function() {
2496             if (window.removeEventListener) {
2497                 return function (el, eventName, fn, capture) {
2498                     el.removeEventListener(eventName, fn, (capture));
2499                 };
2500             } else if (window.detachEvent) {
2501                 return function (el, eventName, fn) {
2502                     el.detachEvent("on" + eventName, fn);
2503                 };
2504             } else {
2505                 return function() {
2506                 };
2507             }
2508         }()
2509     };
2510     
2511 }();
2512 (function() {     
2513    
2514     var E = Roo.lib.Event;
2515     E.on = E.addListener;
2516     E.un = E.removeListener;
2517
2518     if (document && document.body) {
2519         E._load();
2520     } else {
2521         E.doAdd(window, "load", E._load);
2522     }
2523     E.doAdd(window, "unload", E._unload);
2524     E._tryPreloadAttach();
2525 })();
2526
2527 /*
2528  * Portions of this file are based on pieces of Yahoo User Interface Library
2529  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2530  * YUI licensed under the BSD License:
2531  * http://developer.yahoo.net/yui/license.txt
2532  * <script type="text/javascript">
2533  *
2534  */
2535
2536 (function() {
2537     /**
2538      * @class Roo.lib.Ajax
2539      *
2540      */
2541     Roo.lib.Ajax = {
2542         /**
2543          * @static 
2544          */
2545         request : function(method, uri, cb, data, options) {
2546             if(options){
2547                 var hs = options.headers;
2548                 if(hs){
2549                     for(var h in hs){
2550                         if(hs.hasOwnProperty(h)){
2551                             this.initHeader(h, hs[h], false);
2552                         }
2553                     }
2554                 }
2555                 if(options.xmlData){
2556                     this.initHeader('Content-Type', 'text/xml', false);
2557                     method = 'POST';
2558                     data = options.xmlData;
2559                 }
2560             }
2561
2562             return this.asyncRequest(method, uri, cb, data);
2563         },
2564
2565         serializeForm : function(form) {
2566             if(typeof form == 'string') {
2567                 form = (document.getElementById(form) || document.forms[form]);
2568             }
2569
2570             var el, name, val, disabled, data = '', hasSubmit = false;
2571             for (var i = 0; i < form.elements.length; i++) {
2572                 el = form.elements[i];
2573                 disabled = form.elements[i].disabled;
2574                 name = form.elements[i].name;
2575                 val = form.elements[i].value;
2576
2577                 if (!disabled && name){
2578                     switch (el.type)
2579                             {
2580                         case 'select-one':
2581                         case 'select-multiple':
2582                             for (var j = 0; j < el.options.length; j++) {
2583                                 if (el.options[j].selected) {
2584                                     if (Roo.isIE) {
2585                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2586                                     }
2587                                     else {
2588                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2589                                     }
2590                                 }
2591                             }
2592                             break;
2593                         case 'radio':
2594                         case 'checkbox':
2595                             if (el.checked) {
2596                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2597                             }
2598                             break;
2599                         case 'file':
2600
2601                         case undefined:
2602
2603                         case 'reset':
2604
2605                         case 'button':
2606
2607                             break;
2608                         case 'submit':
2609                             if(hasSubmit == false) {
2610                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611                                 hasSubmit = true;
2612                             }
2613                             break;
2614                         default:
2615                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616                             break;
2617                     }
2618                 }
2619             }
2620             data = data.substr(0, data.length - 1);
2621             return data;
2622         },
2623
2624         headers:{},
2625
2626         hasHeaders:false,
2627
2628         useDefaultHeader:true,
2629
2630         defaultPostHeader:'application/x-www-form-urlencoded',
2631
2632         useDefaultXhrHeader:true,
2633
2634         defaultXhrHeader:'XMLHttpRequest',
2635
2636         hasDefaultHeaders:true,
2637
2638         defaultHeaders:{},
2639
2640         poll:{},
2641
2642         timeout:{},
2643
2644         pollInterval:50,
2645
2646         transactionId:0,
2647
2648         setProgId:function(id)
2649         {
2650             this.activeX.unshift(id);
2651         },
2652
2653         setDefaultPostHeader:function(b)
2654         {
2655             this.useDefaultHeader = b;
2656         },
2657
2658         setDefaultXhrHeader:function(b)
2659         {
2660             this.useDefaultXhrHeader = b;
2661         },
2662
2663         setPollingInterval:function(i)
2664         {
2665             if (typeof i == 'number' && isFinite(i)) {
2666                 this.pollInterval = i;
2667             }
2668         },
2669
2670         createXhrObject:function(transactionId)
2671         {
2672             var obj,http;
2673             try
2674             {
2675
2676                 http = new XMLHttpRequest();
2677
2678                 obj = { conn:http, tId:transactionId };
2679             }
2680             catch(e)
2681             {
2682                 for (var i = 0; i < this.activeX.length; ++i) {
2683                     try
2684                     {
2685
2686                         http = new ActiveXObject(this.activeX[i]);
2687
2688                         obj = { conn:http, tId:transactionId };
2689                         break;
2690                     }
2691                     catch(e) {
2692                     }
2693                 }
2694             }
2695             finally
2696             {
2697                 return obj;
2698             }
2699         },
2700
2701         getConnectionObject:function()
2702         {
2703             var o;
2704             var tId = this.transactionId;
2705
2706             try
2707             {
2708                 o = this.createXhrObject(tId);
2709                 if (o) {
2710                     this.transactionId++;
2711                 }
2712             }
2713             catch(e) {
2714             }
2715             finally
2716             {
2717                 return o;
2718             }
2719         },
2720
2721         asyncRequest:function(method, uri, callback, postData)
2722         {
2723             var o = this.getConnectionObject();
2724
2725             if (!o) {
2726                 return null;
2727             }
2728             else {
2729                 o.conn.open(method, uri, true);
2730
2731                 if (this.useDefaultXhrHeader) {
2732                     if (!this.defaultHeaders['X-Requested-With']) {
2733                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2734                     }
2735                 }
2736
2737                 if(postData && this.useDefaultHeader){
2738                     this.initHeader('Content-Type', this.defaultPostHeader);
2739                 }
2740
2741                  if (this.hasDefaultHeaders || this.hasHeaders) {
2742                     this.setHeader(o);
2743                 }
2744
2745                 this.handleReadyState(o, callback);
2746                 o.conn.send(postData || null);
2747
2748                 return o;
2749             }
2750         },
2751
2752         handleReadyState:function(o, callback)
2753         {
2754             var oConn = this;
2755
2756             if (callback && callback.timeout) {
2757                 
2758                 this.timeout[o.tId] = window.setTimeout(function() {
2759                     oConn.abort(o, callback, true);
2760                 }, callback.timeout);
2761             }
2762
2763             this.poll[o.tId] = window.setInterval(
2764                     function() {
2765                         if (o.conn && o.conn.readyState == 4) {
2766                             window.clearInterval(oConn.poll[o.tId]);
2767                             delete oConn.poll[o.tId];
2768
2769                             if(callback && callback.timeout) {
2770                                 window.clearTimeout(oConn.timeout[o.tId]);
2771                                 delete oConn.timeout[o.tId];
2772                             }
2773
2774                             oConn.handleTransactionResponse(o, callback);
2775                         }
2776                     }
2777                     , this.pollInterval);
2778         },
2779
2780         handleTransactionResponse:function(o, callback, isAbort)
2781         {
2782
2783             if (!callback) {
2784                 this.releaseObject(o);
2785                 return;
2786             }
2787
2788             var httpStatus, responseObject;
2789
2790             try
2791             {
2792                 if (o.conn.status !== undefined && o.conn.status != 0) {
2793                     httpStatus = o.conn.status;
2794                 }
2795                 else {
2796                     httpStatus = 13030;
2797                 }
2798             }
2799             catch(e) {
2800
2801
2802                 httpStatus = 13030;
2803             }
2804
2805             if (httpStatus >= 200 && httpStatus < 300) {
2806                 responseObject = this.createResponseObject(o, callback.argument);
2807                 if (callback.success) {
2808                     if (!callback.scope) {
2809                         callback.success(responseObject);
2810                     }
2811                     else {
2812
2813
2814                         callback.success.apply(callback.scope, [responseObject]);
2815                     }
2816                 }
2817             }
2818             else {
2819                 switch (httpStatus) {
2820
2821                     case 12002:
2822                     case 12029:
2823                     case 12030:
2824                     case 12031:
2825                     case 12152:
2826                     case 13030:
2827                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2828                         if (callback.failure) {
2829                             if (!callback.scope) {
2830                                 callback.failure(responseObject);
2831                             }
2832                             else {
2833                                 callback.failure.apply(callback.scope, [responseObject]);
2834                             }
2835                         }
2836                         break;
2837                     default:
2838                         responseObject = this.createResponseObject(o, callback.argument);
2839                         if (callback.failure) {
2840                             if (!callback.scope) {
2841                                 callback.failure(responseObject);
2842                             }
2843                             else {
2844                                 callback.failure.apply(callback.scope, [responseObject]);
2845                             }
2846                         }
2847                 }
2848             }
2849
2850             this.releaseObject(o);
2851             responseObject = null;
2852         },
2853
2854         createResponseObject:function(o, callbackArg)
2855         {
2856             var obj = {};
2857             var headerObj = {};
2858
2859             try
2860             {
2861                 var headerStr = o.conn.getAllResponseHeaders();
2862                 var header = headerStr.split('\n');
2863                 for (var i = 0; i < header.length; i++) {
2864                     var delimitPos = header[i].indexOf(':');
2865                     if (delimitPos != -1) {
2866                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2867                     }
2868                 }
2869             }
2870             catch(e) {
2871             }
2872
2873             obj.tId = o.tId;
2874             obj.status = o.conn.status;
2875             obj.statusText = o.conn.statusText;
2876             obj.getResponseHeader = headerObj;
2877             obj.getAllResponseHeaders = headerStr;
2878             obj.responseText = o.conn.responseText;
2879             obj.responseXML = o.conn.responseXML;
2880
2881             if (typeof callbackArg !== undefined) {
2882                 obj.argument = callbackArg;
2883             }
2884
2885             return obj;
2886         },
2887
2888         createExceptionObject:function(tId, callbackArg, isAbort)
2889         {
2890             var COMM_CODE = 0;
2891             var COMM_ERROR = 'communication failure';
2892             var ABORT_CODE = -1;
2893             var ABORT_ERROR = 'transaction aborted';
2894
2895             var obj = {};
2896
2897             obj.tId = tId;
2898             if (isAbort) {
2899                 obj.status = ABORT_CODE;
2900                 obj.statusText = ABORT_ERROR;
2901             }
2902             else {
2903                 obj.status = COMM_CODE;
2904                 obj.statusText = COMM_ERROR;
2905             }
2906
2907             if (callbackArg) {
2908                 obj.argument = callbackArg;
2909             }
2910
2911             return obj;
2912         },
2913
2914         initHeader:function(label, value, isDefault)
2915         {
2916             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2917
2918             if (headerObj[label] === undefined) {
2919                 headerObj[label] = value;
2920             }
2921             else {
2922
2923
2924                 headerObj[label] = value + "," + headerObj[label];
2925             }
2926
2927             if (isDefault) {
2928                 this.hasDefaultHeaders = true;
2929             }
2930             else {
2931                 this.hasHeaders = true;
2932             }
2933         },
2934
2935
2936         setHeader:function(o)
2937         {
2938             if (this.hasDefaultHeaders) {
2939                 for (var prop in this.defaultHeaders) {
2940                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2941                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942                     }
2943                 }
2944             }
2945
2946             if (this.hasHeaders) {
2947                 for (var prop in this.headers) {
2948                     if (this.headers.hasOwnProperty(prop)) {
2949                         o.conn.setRequestHeader(prop, this.headers[prop]);
2950                     }
2951                 }
2952                 this.headers = {};
2953                 this.hasHeaders = false;
2954             }
2955         },
2956
2957         resetDefaultHeaders:function() {
2958             delete this.defaultHeaders;
2959             this.defaultHeaders = {};
2960             this.hasDefaultHeaders = false;
2961         },
2962
2963         abort:function(o, callback, isTimeout)
2964         {
2965             if(this.isCallInProgress(o)) {
2966                 o.conn.abort();
2967                 window.clearInterval(this.poll[o.tId]);
2968                 delete this.poll[o.tId];
2969                 if (isTimeout) {
2970                     delete this.timeout[o.tId];
2971                 }
2972
2973                 this.handleTransactionResponse(o, callback, true);
2974
2975                 return true;
2976             }
2977             else {
2978                 return false;
2979             }
2980         },
2981
2982
2983         isCallInProgress:function(o)
2984         {
2985             if (o && o.conn) {
2986                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2987             }
2988             else {
2989
2990                 return false;
2991             }
2992         },
2993
2994
2995         releaseObject:function(o)
2996         {
2997
2998             o.conn = null;
2999
3000             o = null;
3001         },
3002
3003         activeX:[
3004         'MSXML2.XMLHTTP.3.0',
3005         'MSXML2.XMLHTTP',
3006         'Microsoft.XMLHTTP'
3007         ]
3008
3009
3010     };
3011 })();/*
3012  * Portions of this file are based on pieces of Yahoo User Interface Library
3013  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3014  * YUI licensed under the BSD License:
3015  * http://developer.yahoo.net/yui/license.txt
3016  * <script type="text/javascript">
3017  *
3018  */
3019
3020 Roo.lib.Region = function(t, r, b, l) {
3021     this.top = t;
3022     this[1] = t;
3023     this.right = r;
3024     this.bottom = b;
3025     this.left = l;
3026     this[0] = l;
3027 };
3028
3029
3030 Roo.lib.Region.prototype = {
3031     contains : function(region) {
3032         return ( region.left >= this.left &&
3033                  region.right <= this.right &&
3034                  region.top >= this.top &&
3035                  region.bottom <= this.bottom    );
3036
3037     },
3038
3039     getArea : function() {
3040         return ( (this.bottom - this.top) * (this.right - this.left) );
3041     },
3042
3043     intersect : function(region) {
3044         var t = Math.max(this.top, region.top);
3045         var r = Math.min(this.right, region.right);
3046         var b = Math.min(this.bottom, region.bottom);
3047         var l = Math.max(this.left, region.left);
3048
3049         if (b >= t && r >= l) {
3050             return new Roo.lib.Region(t, r, b, l);
3051         } else {
3052             return null;
3053         }
3054     },
3055     union : function(region) {
3056         var t = Math.min(this.top, region.top);
3057         var r = Math.max(this.right, region.right);
3058         var b = Math.max(this.bottom, region.bottom);
3059         var l = Math.min(this.left, region.left);
3060
3061         return new Roo.lib.Region(t, r, b, l);
3062     },
3063
3064     adjust : function(t, l, b, r) {
3065         this.top += t;
3066         this.left += l;
3067         this.right += r;
3068         this.bottom += b;
3069         return this;
3070     }
3071 };
3072
3073 Roo.lib.Region.getRegion = function(el) {
3074     var p = Roo.lib.Dom.getXY(el);
3075
3076     var t = p[1];
3077     var r = p[0] + el.offsetWidth;
3078     var b = p[1] + el.offsetHeight;
3079     var l = p[0];
3080
3081     return new Roo.lib.Region(t, r, b, l);
3082 };
3083 /*
3084  * Portions of this file are based on pieces of Yahoo User Interface Library
3085  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3086  * YUI licensed under the BSD License:
3087  * http://developer.yahoo.net/yui/license.txt
3088  * <script type="text/javascript">
3089  *
3090  */
3091 //@@dep Roo.lib.Region
3092
3093
3094 Roo.lib.Point = function(x, y) {
3095     if (x instanceof Array) {
3096         y = x[1];
3097         x = x[0];
3098     }
3099     this.x = this.right = this.left = this[0] = x;
3100     this.y = this.top = this.bottom = this[1] = y;
3101 };
3102
3103 Roo.lib.Point.prototype = new Roo.lib.Region();
3104 /*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112  
3113 (function() {   
3114
3115     Roo.lib.Anim = {
3116         scroll : function(el, args, duration, easing, cb, scope) {
3117             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3118         },
3119
3120         motion : function(el, args, duration, easing, cb, scope) {
3121             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3122         },
3123
3124         color : function(el, args, duration, easing, cb, scope) {
3125             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3126         },
3127
3128         run : function(el, args, duration, easing, cb, scope, type) {
3129             type = type || Roo.lib.AnimBase;
3130             if (typeof easing == "string") {
3131                 easing = Roo.lib.Easing[easing];
3132             }
3133             var anim = new type(el, args, duration, easing);
3134             anim.animateX(function() {
3135                 Roo.callback(cb, scope);
3136             });
3137             return anim;
3138         }
3139     };
3140 })();/*
3141  * Portions of this file are based on pieces of Yahoo User Interface Library
3142  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3143  * YUI licensed under the BSD License:
3144  * http://developer.yahoo.net/yui/license.txt
3145  * <script type="text/javascript">
3146  *
3147  */
3148
3149 (function() {    
3150     var libFlyweight;
3151     
3152     function fly(el) {
3153         if (!libFlyweight) {
3154             libFlyweight = new Roo.Element.Flyweight();
3155         }
3156         libFlyweight.dom = el;
3157         return libFlyweight;
3158     }
3159
3160     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3161     
3162    
3163     
3164     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3165         if (el) {
3166             this.init(el, attributes, duration, method);
3167         }
3168     };
3169
3170     Roo.lib.AnimBase.fly = fly;
3171     
3172     
3173     
3174     Roo.lib.AnimBase.prototype = {
3175
3176         toString: function() {
3177             var el = this.getEl();
3178             var id = el.id || el.tagName;
3179             return ("Anim " + id);
3180         },
3181
3182         patterns: {
3183             noNegatives:        /width|height|opacity|padding/i,
3184             offsetAttribute:  /^((width|height)|(top|left))$/,
3185             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3186             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3187         },
3188
3189
3190         doMethod: function(attr, start, end) {
3191             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3192         },
3193
3194
3195         setAttribute: function(attr, val, unit) {
3196             if (this.patterns.noNegatives.test(attr)) {
3197                 val = (val > 0) ? val : 0;
3198             }
3199
3200             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3201         },
3202
3203
3204         getAttribute: function(attr) {
3205             var el = this.getEl();
3206             var val = fly(el).getStyle(attr);
3207
3208             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3209                 return parseFloat(val);
3210             }
3211
3212             var a = this.patterns.offsetAttribute.exec(attr) || [];
3213             var pos = !!( a[3] );
3214             var box = !!( a[2] );
3215
3216
3217             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3218                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3219             } else {
3220                 val = 0;
3221             }
3222
3223             return val;
3224         },
3225
3226
3227         getDefaultUnit: function(attr) {
3228             if (this.patterns.defaultUnit.test(attr)) {
3229                 return 'px';
3230             }
3231
3232             return '';
3233         },
3234
3235         animateX : function(callback, scope) {
3236             var f = function() {
3237                 this.onComplete.removeListener(f);
3238                 if (typeof callback == "function") {
3239                     callback.call(scope || this, this);
3240                 }
3241             };
3242             this.onComplete.addListener(f, this);
3243             this.animate();
3244         },
3245
3246
3247         setRuntimeAttribute: function(attr) {
3248             var start;
3249             var end;
3250             var attributes = this.attributes;
3251
3252             this.runtimeAttributes[attr] = {};
3253
3254             var isset = function(prop) {
3255                 return (typeof prop !== 'undefined');
3256             };
3257
3258             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3259                 return false;
3260             }
3261
3262             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3263
3264
3265             if (isset(attributes[attr]['to'])) {
3266                 end = attributes[attr]['to'];
3267             } else if (isset(attributes[attr]['by'])) {
3268                 if (start.constructor == Array) {
3269                     end = [];
3270                     for (var i = 0, len = start.length; i < len; ++i) {
3271                         end[i] = start[i] + attributes[attr]['by'][i];
3272                     }
3273                 } else {
3274                     end = start + attributes[attr]['by'];
3275                 }
3276             }
3277
3278             this.runtimeAttributes[attr].start = start;
3279             this.runtimeAttributes[attr].end = end;
3280
3281
3282             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3283         },
3284
3285
3286         init: function(el, attributes, duration, method) {
3287
3288             var isAnimated = false;
3289
3290
3291             var startTime = null;
3292
3293
3294             var actualFrames = 0;
3295
3296
3297             el = Roo.getDom(el);
3298
3299
3300             this.attributes = attributes || {};
3301
3302
3303             this.duration = duration || 1;
3304
3305
3306             this.method = method || Roo.lib.Easing.easeNone;
3307
3308
3309             this.useSeconds = true;
3310
3311
3312             this.currentFrame = 0;
3313
3314
3315             this.totalFrames = Roo.lib.AnimMgr.fps;
3316
3317
3318             this.getEl = function() {
3319                 return el;
3320             };
3321
3322
3323             this.isAnimated = function() {
3324                 return isAnimated;
3325             };
3326
3327
3328             this.getStartTime = function() {
3329                 return startTime;
3330             };
3331
3332             this.runtimeAttributes = {};
3333
3334
3335             this.animate = function() {
3336                 if (this.isAnimated()) {
3337                     return false;
3338                 }
3339
3340                 this.currentFrame = 0;
3341
3342                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3343
3344                 Roo.lib.AnimMgr.registerElement(this);
3345             };
3346
3347
3348             this.stop = function(finish) {
3349                 if (finish) {
3350                     this.currentFrame = this.totalFrames;
3351                     this._onTween.fire();
3352                 }
3353                 Roo.lib.AnimMgr.stop(this);
3354             };
3355
3356             var onStart = function() {
3357                 this.onStart.fire();
3358
3359                 this.runtimeAttributes = {};
3360                 for (var attr in this.attributes) {
3361                     this.setRuntimeAttribute(attr);
3362                 }
3363
3364                 isAnimated = true;
3365                 actualFrames = 0;
3366                 startTime = new Date();
3367             };
3368
3369
3370             var onTween = function() {
3371                 var data = {
3372                     duration: new Date() - this.getStartTime(),
3373                     currentFrame: this.currentFrame
3374                 };
3375
3376                 data.toString = function() {
3377                     return (
3378                             'duration: ' + data.duration +
3379                             ', currentFrame: ' + data.currentFrame
3380                             );
3381                 };
3382
3383                 this.onTween.fire(data);
3384
3385                 var runtimeAttributes = this.runtimeAttributes;
3386
3387                 for (var attr in runtimeAttributes) {
3388                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3389                 }
3390
3391                 actualFrames += 1;
3392             };
3393
3394             var onComplete = function() {
3395                 var actual_duration = (new Date() - startTime) / 1000 ;
3396
3397                 var data = {
3398                     duration: actual_duration,
3399                     frames: actualFrames,
3400                     fps: actualFrames / actual_duration
3401                 };
3402
3403                 data.toString = function() {
3404                     return (
3405                             'duration: ' + data.duration +
3406                             ', frames: ' + data.frames +
3407                             ', fps: ' + data.fps
3408                             );
3409                 };
3410
3411                 isAnimated = false;
3412                 actualFrames = 0;
3413                 this.onComplete.fire(data);
3414             };
3415
3416
3417             this._onStart = new Roo.util.Event(this);
3418             this.onStart = new Roo.util.Event(this);
3419             this.onTween = new Roo.util.Event(this);
3420             this._onTween = new Roo.util.Event(this);
3421             this.onComplete = new Roo.util.Event(this);
3422             this._onComplete = new Roo.util.Event(this);
3423             this._onStart.addListener(onStart);
3424             this._onTween.addListener(onTween);
3425             this._onComplete.addListener(onComplete);
3426         }
3427     };
3428 })();
3429 /*
3430  * Portions of this file are based on pieces of Yahoo User Interface Library
3431  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3432  * YUI licensed under the BSD License:
3433  * http://developer.yahoo.net/yui/license.txt
3434  * <script type="text/javascript">
3435  *
3436  */
3437
3438 Roo.lib.AnimMgr = new function() {
3439
3440     var thread = null;
3441
3442
3443     var queue = [];
3444
3445
3446     var tweenCount = 0;
3447
3448
3449     this.fps = 1000;
3450
3451
3452     this.delay = 1;
3453
3454
3455     this.registerElement = function(tween) {
3456         queue[queue.length] = tween;
3457         tweenCount += 1;
3458         tween._onStart.fire();
3459         this.start();
3460     };
3461
3462
3463     this.unRegister = function(tween, index) {
3464         tween._onComplete.fire();
3465         index = index || getIndex(tween);
3466         if (index != -1) {
3467             queue.splice(index, 1);
3468         }
3469
3470         tweenCount -= 1;
3471         if (tweenCount <= 0) {
3472             this.stop();
3473         }
3474     };
3475
3476
3477     this.start = function() {
3478         if (thread === null) {
3479             thread = setInterval(this.run, this.delay);
3480         }
3481     };
3482
3483
3484     this.stop = function(tween) {
3485         if (!tween) {
3486             clearInterval(thread);
3487
3488             for (var i = 0, len = queue.length; i < len; ++i) {
3489                 if (queue[0].isAnimated()) {
3490                     this.unRegister(queue[0], 0);
3491                 }
3492             }
3493
3494             queue = [];
3495             thread = null;
3496             tweenCount = 0;
3497         }
3498         else {
3499             this.unRegister(tween);
3500         }
3501     };
3502
3503
3504     this.run = function() {
3505         for (var i = 0, len = queue.length; i < len; ++i) {
3506             var tween = queue[i];
3507             if (!tween || !tween.isAnimated()) {
3508                 continue;
3509             }
3510
3511             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3512             {
3513                 tween.currentFrame += 1;
3514
3515                 if (tween.useSeconds) {
3516                     correctFrame(tween);
3517                 }
3518                 tween._onTween.fire();
3519             }
3520             else {
3521                 Roo.lib.AnimMgr.stop(tween, i);
3522             }
3523         }
3524     };
3525
3526     var getIndex = function(anim) {
3527         for (var i = 0, len = queue.length; i < len; ++i) {
3528             if (queue[i] == anim) {
3529                 return i;
3530             }
3531         }
3532         return -1;
3533     };
3534
3535
3536     var correctFrame = function(tween) {
3537         var frames = tween.totalFrames;
3538         var frame = tween.currentFrame;
3539         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3540         var elapsed = (new Date() - tween.getStartTime());
3541         var tweak = 0;
3542
3543         if (elapsed < tween.duration * 1000) {
3544             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3545         } else {
3546             tweak = frames - (frame + 1);
3547         }
3548         if (tweak > 0 && isFinite(tweak)) {
3549             if (tween.currentFrame + tweak >= frames) {
3550                 tweak = frames - (frame + 1);
3551             }
3552
3553             tween.currentFrame += tweak;
3554         }
3555     };
3556 };
3557
3558     /*
3559  * Portions of this file are based on pieces of Yahoo User Interface Library
3560  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3561  * YUI licensed under the BSD License:
3562  * http://developer.yahoo.net/yui/license.txt
3563  * <script type="text/javascript">
3564  *
3565  */
3566 Roo.lib.Bezier = new function() {
3567
3568         this.getPosition = function(points, t) {
3569             var n = points.length;
3570             var tmp = [];
3571
3572             for (var i = 0; i < n; ++i) {
3573                 tmp[i] = [points[i][0], points[i][1]];
3574             }
3575
3576             for (var j = 1; j < n; ++j) {
3577                 for (i = 0; i < n - j; ++i) {
3578                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3579                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3580                 }
3581             }
3582
3583             return [ tmp[0][0], tmp[0][1] ];
3584
3585         };
3586     };/*
3587  * Portions of this file are based on pieces of Yahoo User Interface Library
3588  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3589  * YUI licensed under the BSD License:
3590  * http://developer.yahoo.net/yui/license.txt
3591  * <script type="text/javascript">
3592  *
3593  */
3594 (function() {
3595
3596     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3597         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3598     };
3599
3600     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3601
3602     var fly = Roo.lib.AnimBase.fly;
3603     var Y = Roo.lib;
3604     var superclass = Y.ColorAnim.superclass;
3605     var proto = Y.ColorAnim.prototype;
3606
3607     proto.toString = function() {
3608         var el = this.getEl();
3609         var id = el.id || el.tagName;
3610         return ("ColorAnim " + id);
3611     };
3612
3613     proto.patterns.color = /color$/i;
3614     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3615     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3616     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3617     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3618
3619
3620     proto.parseColor = function(s) {
3621         if (s.length == 3) {
3622             return s;
3623         }
3624
3625         var c = this.patterns.hex.exec(s);
3626         if (c && c.length == 4) {
3627             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3628         }
3629
3630         c = this.patterns.rgb.exec(s);
3631         if (c && c.length == 4) {
3632             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3633         }
3634
3635         c = this.patterns.hex3.exec(s);
3636         if (c && c.length == 4) {
3637             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638         }
3639
3640         return null;
3641     };
3642     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3643     proto.getAttribute = function(attr) {
3644         var el = this.getEl();
3645         if (this.patterns.color.test(attr)) {
3646             var val = fly(el).getStyle(attr);
3647
3648             if (this.patterns.transparent.test(val)) {
3649                 var parent = el.parentNode;
3650                 val = fly(parent).getStyle(attr);
3651
3652                 while (parent && this.patterns.transparent.test(val)) {
3653                     parent = parent.parentNode;
3654                     val = fly(parent).getStyle(attr);
3655                     if (parent.tagName.toUpperCase() == 'HTML') {
3656                         val = '#fff';
3657                     }
3658                 }
3659             }
3660         } else {
3661             val = superclass.getAttribute.call(this, attr);
3662         }
3663
3664         return val;
3665     };
3666     proto.getAttribute = function(attr) {
3667         var el = this.getEl();
3668         if (this.patterns.color.test(attr)) {
3669             var val = fly(el).getStyle(attr);
3670
3671             if (this.patterns.transparent.test(val)) {
3672                 var parent = el.parentNode;
3673                 val = fly(parent).getStyle(attr);
3674
3675                 while (parent && this.patterns.transparent.test(val)) {
3676                     parent = parent.parentNode;
3677                     val = fly(parent).getStyle(attr);
3678                     if (parent.tagName.toUpperCase() == 'HTML') {
3679                         val = '#fff';
3680                     }
3681                 }
3682             }
3683         } else {
3684             val = superclass.getAttribute.call(this, attr);
3685         }
3686
3687         return val;
3688     };
3689
3690     proto.doMethod = function(attr, start, end) {
3691         var val;
3692
3693         if (this.patterns.color.test(attr)) {
3694             val = [];
3695             for (var i = 0, len = start.length; i < len; ++i) {
3696                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3697             }
3698
3699             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3700         }
3701         else {
3702             val = superclass.doMethod.call(this, attr, start, end);
3703         }
3704
3705         return val;
3706     };
3707
3708     proto.setRuntimeAttribute = function(attr) {
3709         superclass.setRuntimeAttribute.call(this, attr);
3710
3711         if (this.patterns.color.test(attr)) {
3712             var attributes = this.attributes;
3713             var start = this.parseColor(this.runtimeAttributes[attr].start);
3714             var end = this.parseColor(this.runtimeAttributes[attr].end);
3715
3716             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3717                 end = this.parseColor(attributes[attr].by);
3718
3719                 for (var i = 0, len = start.length; i < len; ++i) {
3720                     end[i] = start[i] + end[i];
3721                 }
3722             }
3723
3724             this.runtimeAttributes[attr].start = start;
3725             this.runtimeAttributes[attr].end = end;
3726         }
3727     };
3728 })();
3729
3730 /*
3731  * Portions of this file are based on pieces of Yahoo User Interface Library
3732  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3733  * YUI licensed under the BSD License:
3734  * http://developer.yahoo.net/yui/license.txt
3735  * <script type="text/javascript">
3736  *
3737  */
3738 Roo.lib.Easing = {
3739
3740
3741     easeNone: function (t, b, c, d) {
3742         return c * t / d + b;
3743     },
3744
3745
3746     easeIn: function (t, b, c, d) {
3747         return c * (t /= d) * t + b;
3748     },
3749
3750
3751     easeOut: function (t, b, c, d) {
3752         return -c * (t /= d) * (t - 2) + b;
3753     },
3754
3755
3756     easeBoth: function (t, b, c, d) {
3757         if ((t /= d / 2) < 1) {
3758             return c / 2 * t * t + b;
3759         }
3760
3761         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3762     },
3763
3764
3765     easeInStrong: function (t, b, c, d) {
3766         return c * (t /= d) * t * t * t + b;
3767     },
3768
3769
3770     easeOutStrong: function (t, b, c, d) {
3771         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3772     },
3773
3774
3775     easeBothStrong: function (t, b, c, d) {
3776         if ((t /= d / 2) < 1) {
3777             return c / 2 * t * t * t * t + b;
3778         }
3779
3780         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781     },
3782
3783
3784
3785     elasticIn: function (t, b, c, d, a, p) {
3786         if (t == 0) {
3787             return b;
3788         }
3789         if ((t /= d) == 1) {
3790             return b + c;
3791         }
3792         if (!p) {
3793             p = d * .3;
3794         }
3795
3796         if (!a || a < Math.abs(c)) {
3797             a = c;
3798             var s = p / 4;
3799         }
3800         else {
3801             var s = p / (2 * Math.PI) * Math.asin(c / a);
3802         }
3803
3804         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3805     },
3806
3807
3808     elasticOut: function (t, b, c, d, a, p) {
3809         if (t == 0) {
3810             return b;
3811         }
3812         if ((t /= d) == 1) {
3813             return b + c;
3814         }
3815         if (!p) {
3816             p = d * .3;
3817         }
3818
3819         if (!a || a < Math.abs(c)) {
3820             a = c;
3821             var s = p / 4;
3822         }
3823         else {
3824             var s = p / (2 * Math.PI) * Math.asin(c / a);
3825         }
3826
3827         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3828     },
3829
3830
3831     elasticBoth: function (t, b, c, d, a, p) {
3832         if (t == 0) {
3833             return b;
3834         }
3835
3836         if ((t /= d / 2) == 2) {
3837             return b + c;
3838         }
3839
3840         if (!p) {
3841             p = d * (.3 * 1.5);
3842         }
3843
3844         if (!a || a < Math.abs(c)) {
3845             a = c;
3846             var s = p / 4;
3847         }
3848         else {
3849             var s = p / (2 * Math.PI) * Math.asin(c / a);
3850         }
3851
3852         if (t < 1) {
3853             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3854                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3855         }
3856         return a * Math.pow(2, -10 * (t -= 1)) *
3857                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858     },
3859
3860
3861
3862     backIn: function (t, b, c, d, s) {
3863         if (typeof s == 'undefined') {
3864             s = 1.70158;
3865         }
3866         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3867     },
3868
3869
3870     backOut: function (t, b, c, d, s) {
3871         if (typeof s == 'undefined') {
3872             s = 1.70158;
3873         }
3874         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3875     },
3876
3877
3878     backBoth: function (t, b, c, d, s) {
3879         if (typeof s == 'undefined') {
3880             s = 1.70158;
3881         }
3882
3883         if ((t /= d / 2 ) < 1) {
3884             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3885         }
3886         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3887     },
3888
3889
3890     bounceIn: function (t, b, c, d) {
3891         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3892     },
3893
3894
3895     bounceOut: function (t, b, c, d) {
3896         if ((t /= d) < (1 / 2.75)) {
3897             return c * (7.5625 * t * t) + b;
3898         } else if (t < (2 / 2.75)) {
3899             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3900         } else if (t < (2.5 / 2.75)) {
3901             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3902         }
3903         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3904     },
3905
3906
3907     bounceBoth: function (t, b, c, d) {
3908         if (t < d / 2) {
3909             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3910         }
3911         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3912     }
3913 };/*
3914  * Portions of this file are based on pieces of Yahoo User Interface Library
3915  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3916  * YUI licensed under the BSD License:
3917  * http://developer.yahoo.net/yui/license.txt
3918  * <script type="text/javascript">
3919  *
3920  */
3921     (function() {
3922         Roo.lib.Motion = function(el, attributes, duration, method) {
3923             if (el) {
3924                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3925             }
3926         };
3927
3928         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3929
3930
3931         var Y = Roo.lib;
3932         var superclass = Y.Motion.superclass;
3933         var proto = Y.Motion.prototype;
3934
3935         proto.toString = function() {
3936             var el = this.getEl();
3937             var id = el.id || el.tagName;
3938             return ("Motion " + id);
3939         };
3940
3941         proto.patterns.points = /^points$/i;
3942
3943         proto.setAttribute = function(attr, val, unit) {
3944             if (this.patterns.points.test(attr)) {
3945                 unit = unit || 'px';
3946                 superclass.setAttribute.call(this, 'left', val[0], unit);
3947                 superclass.setAttribute.call(this, 'top', val[1], unit);
3948             } else {
3949                 superclass.setAttribute.call(this, attr, val, unit);
3950             }
3951         };
3952
3953         proto.getAttribute = function(attr) {
3954             if (this.patterns.points.test(attr)) {
3955                 var val = [
3956                         superclass.getAttribute.call(this, 'left'),
3957                         superclass.getAttribute.call(this, 'top')
3958                         ];
3959             } else {
3960                 val = superclass.getAttribute.call(this, attr);
3961             }
3962
3963             return val;
3964         };
3965
3966         proto.doMethod = function(attr, start, end) {
3967             var val = null;
3968
3969             if (this.patterns.points.test(attr)) {
3970                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3971                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3972             } else {
3973                 val = superclass.doMethod.call(this, attr, start, end);
3974             }
3975             return val;
3976         };
3977
3978         proto.setRuntimeAttribute = function(attr) {
3979             if (this.patterns.points.test(attr)) {
3980                 var el = this.getEl();
3981                 var attributes = this.attributes;
3982                 var start;
3983                 var control = attributes['points']['control'] || [];
3984                 var end;
3985                 var i, len;
3986
3987                 if (control.length > 0 && !(control[0] instanceof Array)) {
3988                     control = [control];
3989                 } else {
3990                     var tmp = [];
3991                     for (i = 0,len = control.length; i < len; ++i) {
3992                         tmp[i] = control[i];
3993                     }
3994                     control = tmp;
3995                 }
3996
3997                 Roo.fly(el).position();
3998
3999                 if (isset(attributes['points']['from'])) {
4000                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4001                 }
4002                 else {
4003                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4004                 }
4005
4006                 start = this.getAttribute('points');
4007
4008
4009                 if (isset(attributes['points']['to'])) {
4010                     end = translateValues.call(this, attributes['points']['to'], start);
4011
4012                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4013                     for (i = 0,len = control.length; i < len; ++i) {
4014                         control[i] = translateValues.call(this, control[i], start);
4015                     }
4016
4017
4018                 } else if (isset(attributes['points']['by'])) {
4019                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4020
4021                     for (i = 0,len = control.length; i < len; ++i) {
4022                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4023                     }
4024                 }
4025
4026                 this.runtimeAttributes[attr] = [start];
4027
4028                 if (control.length > 0) {
4029                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4030                 }
4031
4032                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4033             }
4034             else {
4035                 superclass.setRuntimeAttribute.call(this, attr);
4036             }
4037         };
4038
4039         var translateValues = function(val, start) {
4040             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4041             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042
4043             return val;
4044         };
4045
4046         var isset = function(prop) {
4047             return (typeof prop !== 'undefined');
4048         };
4049     })();
4050 /*
4051  * Portions of this file are based on pieces of Yahoo User Interface Library
4052  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4053  * YUI licensed under the BSD License:
4054  * http://developer.yahoo.net/yui/license.txt
4055  * <script type="text/javascript">
4056  *
4057  */
4058     (function() {
4059         Roo.lib.Scroll = function(el, attributes, duration, method) {
4060             if (el) {
4061                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4062             }
4063         };
4064
4065         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4066
4067
4068         var Y = Roo.lib;
4069         var superclass = Y.Scroll.superclass;
4070         var proto = Y.Scroll.prototype;
4071
4072         proto.toString = function() {
4073             var el = this.getEl();
4074             var id = el.id || el.tagName;
4075             return ("Scroll " + id);
4076         };
4077
4078         proto.doMethod = function(attr, start, end) {
4079             var val = null;
4080
4081             if (attr == 'scroll') {
4082                 val = [
4083                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4084                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4085                         ];
4086
4087             } else {
4088                 val = superclass.doMethod.call(this, attr, start, end);
4089             }
4090             return val;
4091         };
4092
4093         proto.getAttribute = function(attr) {
4094             var val = null;
4095             var el = this.getEl();
4096
4097             if (attr == 'scroll') {
4098                 val = [ el.scrollLeft, el.scrollTop ];
4099             } else {
4100                 val = superclass.getAttribute.call(this, attr);
4101             }
4102
4103             return val;
4104         };
4105
4106         proto.setAttribute = function(attr, val, unit) {
4107             var el = this.getEl();
4108
4109             if (attr == 'scroll') {
4110                 el.scrollLeft = val[0];
4111                 el.scrollTop = val[1];
4112             } else {
4113                 superclass.setAttribute.call(this, attr, val, unit);
4114             }
4115         };
4116     })();
4117 /*
4118  * Based on:
4119  * Ext JS Library 1.1.1
4120  * Copyright(c) 2006-2007, Ext JS, LLC.
4121  *
4122  * Originally Released Under LGPL - original licence link has changed is not relivant.
4123  *
4124  * Fork - LGPL
4125  * <script type="text/javascript">
4126  */
4127
4128
4129 // nasty IE9 hack - what a pile of crap that is..
4130
4131  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4132     Range.prototype.createContextualFragment = function (html) {
4133         var doc = window.document;
4134         var container = doc.createElement("div");
4135         container.innerHTML = html;
4136         var frag = doc.createDocumentFragment(), n;
4137         while ((n = container.firstChild)) {
4138             frag.appendChild(n);
4139         }
4140         return frag;
4141     };
4142 }
4143
4144 /**
4145  * @class Roo.DomHelper
4146  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4147  * 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>.
4148  * @singleton
4149  */
4150 Roo.DomHelper = function(){
4151     var tempTableEl = null;
4152     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4153     var tableRe = /^table|tbody|tr|td$/i;
4154     var xmlns = {};
4155     // build as innerHTML where available
4156     /** @ignore */
4157     var createHtml = function(o){
4158         if(typeof o == 'string'){
4159             return o;
4160         }
4161         var b = "";
4162         if(!o.tag){
4163             o.tag = "div";
4164         }
4165         b += "<" + o.tag;
4166         for(var attr in o){
4167             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4168             if(attr == "style"){
4169                 var s = o["style"];
4170                 if(typeof s == "function"){
4171                     s = s.call();
4172                 }
4173                 if(typeof s == "string"){
4174                     b += ' style="' + s + '"';
4175                 }else if(typeof s == "object"){
4176                     b += ' style="';
4177                     for(var key in s){
4178                         if(typeof s[key] != "function"){
4179                             b += key + ":" + s[key] + ";";
4180                         }
4181                     }
4182                     b += '"';
4183                 }
4184             }else{
4185                 if(attr == "cls"){
4186                     b += ' class="' + o["cls"] + '"';
4187                 }else if(attr == "htmlFor"){
4188                     b += ' for="' + o["htmlFor"] + '"';
4189                 }else{
4190                     b += " " + attr + '="' + o[attr] + '"';
4191                 }
4192             }
4193         }
4194         if(emptyTags.test(o.tag)){
4195             b += "/>";
4196         }else{
4197             b += ">";
4198             var cn = o.children || o.cn;
4199             if(cn){
4200                 //http://bugs.kde.org/show_bug.cgi?id=71506
4201                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4202                     for(var i = 0, len = cn.length; i < len; i++) {
4203                         b += createHtml(cn[i], b);
4204                     }
4205                 }else{
4206                     b += createHtml(cn, b);
4207                 }
4208             }
4209             if(o.html){
4210                 b += o.html;
4211             }
4212             b += "</" + o.tag + ">";
4213         }
4214         return b;
4215     };
4216
4217     // build as dom
4218     /** @ignore */
4219     var createDom = function(o, parentNode){
4220          
4221         // defininition craeted..
4222         var ns = false;
4223         if (o.ns && o.ns != 'html') {
4224                
4225             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4226                 xmlns[o.ns] = o.xmlns;
4227                 ns = o.xmlns;
4228             }
4229             if (typeof(xmlns[o.ns]) == 'undefined') {
4230                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4231             }
4232             ns = xmlns[o.ns];
4233         }
4234         
4235         
4236         if (typeof(o) == 'string') {
4237             return parentNode.appendChild(document.createTextNode(o));
4238         }
4239         o.tag = o.tag || div;
4240         if (o.ns && Roo.isIE) {
4241             ns = false;
4242             o.tag = o.ns + ':' + o.tag;
4243             
4244         }
4245         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4246         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4247         for(var attr in o){
4248             
4249             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4250                     attr == "style" || typeof o[attr] == "function") { continue; }
4251                     
4252             if(attr=="cls" && Roo.isIE){
4253                 el.className = o["cls"];
4254             }else{
4255                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4256                 else { 
4257                     el[attr] = o[attr];
4258                 }
4259             }
4260         }
4261         Roo.DomHelper.applyStyles(el, o.style);
4262         var cn = o.children || o.cn;
4263         if(cn){
4264             //http://bugs.kde.org/show_bug.cgi?id=71506
4265              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4266                 for(var i = 0, len = cn.length; i < len; i++) {
4267                     createDom(cn[i], el);
4268                 }
4269             }else{
4270                 createDom(cn, el);
4271             }
4272         }
4273         if(o.html){
4274             el.innerHTML = o.html;
4275         }
4276         if(parentNode){
4277            parentNode.appendChild(el);
4278         }
4279         return el;
4280     };
4281
4282     var ieTable = function(depth, s, h, e){
4283         tempTableEl.innerHTML = [s, h, e].join('');
4284         var i = -1, el = tempTableEl;
4285         while(++i < depth){
4286             el = el.firstChild;
4287         }
4288         return el;
4289     };
4290
4291     // kill repeat to save bytes
4292     var ts = '<table>',
4293         te = '</table>',
4294         tbs = ts+'<tbody>',
4295         tbe = '</tbody>'+te,
4296         trs = tbs + '<tr>',
4297         tre = '</tr>'+tbe;
4298
4299     /**
4300      * @ignore
4301      * Nasty code for IE's broken table implementation
4302      */
4303     var insertIntoTable = function(tag, where, el, html){
4304         if(!tempTableEl){
4305             tempTableEl = document.createElement('div');
4306         }
4307         var node;
4308         var before = null;
4309         if(tag == 'td'){
4310             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4311                 return;
4312             }
4313             if(where == 'beforebegin'){
4314                 before = el;
4315                 el = el.parentNode;
4316             } else{
4317                 before = el.nextSibling;
4318                 el = el.parentNode;
4319             }
4320             node = ieTable(4, trs, html, tre);
4321         }
4322         else if(tag == 'tr'){
4323             if(where == 'beforebegin'){
4324                 before = el;
4325                 el = el.parentNode;
4326                 node = ieTable(3, tbs, html, tbe);
4327             } else if(where == 'afterend'){
4328                 before = el.nextSibling;
4329                 el = el.parentNode;
4330                 node = ieTable(3, tbs, html, tbe);
4331             } else{ // INTO a TR
4332                 if(where == 'afterbegin'){
4333                     before = el.firstChild;
4334                 }
4335                 node = ieTable(4, trs, html, tre);
4336             }
4337         } else if(tag == 'tbody'){
4338             if(where == 'beforebegin'){
4339                 before = el;
4340                 el = el.parentNode;
4341                 node = ieTable(2, ts, html, te);
4342             } else if(where == 'afterend'){
4343                 before = el.nextSibling;
4344                 el = el.parentNode;
4345                 node = ieTable(2, ts, html, te);
4346             } else{
4347                 if(where == 'afterbegin'){
4348                     before = el.firstChild;
4349                 }
4350                 node = ieTable(3, tbs, html, tbe);
4351             }
4352         } else{ // TABLE
4353             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4354                 return;
4355             }
4356             if(where == 'afterbegin'){
4357                 before = el.firstChild;
4358             }
4359             node = ieTable(2, ts, html, te);
4360         }
4361         el.insertBefore(node, before);
4362         return node;
4363     };
4364
4365     return {
4366     /** True to force the use of DOM instead of html fragments @type Boolean */
4367     useDom : false,
4368
4369     /**
4370      * Returns the markup for the passed Element(s) config
4371      * @param {Object} o The Dom object spec (and children)
4372      * @return {String}
4373      */
4374     markup : function(o){
4375         return createHtml(o);
4376     },
4377
4378     /**
4379      * Applies a style specification to an element
4380      * @param {String/HTMLElement} el The element to apply styles to
4381      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4382      * a function which returns such a specification.
4383      */
4384     applyStyles : function(el, styles){
4385         if(styles){
4386            el = Roo.fly(el);
4387            if(typeof styles == "string"){
4388                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4389                var matches;
4390                while ((matches = re.exec(styles)) != null){
4391                    el.setStyle(matches[1], matches[2]);
4392                }
4393            }else if (typeof styles == "object"){
4394                for (var style in styles){
4395                   el.setStyle(style, styles[style]);
4396                }
4397            }else if (typeof styles == "function"){
4398                 Roo.DomHelper.applyStyles(el, styles.call());
4399            }
4400         }
4401     },
4402
4403     /**
4404      * Inserts an HTML fragment into the Dom
4405      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4406      * @param {HTMLElement} el The context element
4407      * @param {String} html The HTML fragmenet
4408      * @return {HTMLElement} The new node
4409      */
4410     insertHtml : function(where, el, html){
4411         where = where.toLowerCase();
4412         if(el.insertAdjacentHTML){
4413             if(tableRe.test(el.tagName)){
4414                 var rs;
4415                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4416                     return rs;
4417                 }
4418             }
4419             switch(where){
4420                 case "beforebegin":
4421                     el.insertAdjacentHTML('BeforeBegin', html);
4422                     return el.previousSibling;
4423                 case "afterbegin":
4424                     el.insertAdjacentHTML('AfterBegin', html);
4425                     return el.firstChild;
4426                 case "beforeend":
4427                     el.insertAdjacentHTML('BeforeEnd', html);
4428                     return el.lastChild;
4429                 case "afterend":
4430                     el.insertAdjacentHTML('AfterEnd', html);
4431                     return el.nextSibling;
4432             }
4433             throw 'Illegal insertion point -> "' + where + '"';
4434         }
4435         var range = el.ownerDocument.createRange();
4436         var frag;
4437         switch(where){
4438              case "beforebegin":
4439                 range.setStartBefore(el);
4440                 frag = range.createContextualFragment(html);
4441                 el.parentNode.insertBefore(frag, el);
4442                 return el.previousSibling;
4443              case "afterbegin":
4444                 if(el.firstChild){
4445                     range.setStartBefore(el.firstChild);
4446                     frag = range.createContextualFragment(html);
4447                     el.insertBefore(frag, el.firstChild);
4448                     return el.firstChild;
4449                 }else{
4450                     el.innerHTML = html;
4451                     return el.firstChild;
4452                 }
4453             case "beforeend":
4454                 if(el.lastChild){
4455                     range.setStartAfter(el.lastChild);
4456                     frag = range.createContextualFragment(html);
4457                     el.appendChild(frag);
4458                     return el.lastChild;
4459                 }else{
4460                     el.innerHTML = html;
4461                     return el.lastChild;
4462                 }
4463             case "afterend":
4464                 range.setStartAfter(el);
4465                 frag = range.createContextualFragment(html);
4466                 el.parentNode.insertBefore(frag, el.nextSibling);
4467                 return el.nextSibling;
4468             }
4469             throw 'Illegal insertion point -> "' + where + '"';
4470     },
4471
4472     /**
4473      * Creates new Dom element(s) and inserts them before el
4474      * @param {String/HTMLElement/Element} el The context element
4475      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4476      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4477      * @return {HTMLElement/Roo.Element} The new node
4478      */
4479     insertBefore : function(el, o, returnElement){
4480         return this.doInsert(el, o, returnElement, "beforeBegin");
4481     },
4482
4483     /**
4484      * Creates new Dom element(s) and inserts them after el
4485      * @param {String/HTMLElement/Element} el The context element
4486      * @param {Object} o The Dom object spec (and children)
4487      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488      * @return {HTMLElement/Roo.Element} The new node
4489      */
4490     insertAfter : function(el, o, returnElement){
4491         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4492     },
4493
4494     /**
4495      * Creates new Dom element(s) and inserts them as the first child of el
4496      * @param {String/HTMLElement/Element} el The context element
4497      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4498      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4499      * @return {HTMLElement/Roo.Element} The new node
4500      */
4501     insertFirst : function(el, o, returnElement){
4502         return this.doInsert(el, o, returnElement, "afterBegin");
4503     },
4504
4505     // private
4506     doInsert : function(el, o, returnElement, pos, sibling){
4507         el = Roo.getDom(el);
4508         var newNode;
4509         if(this.useDom || o.ns){
4510             newNode = createDom(o, null);
4511             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4512         }else{
4513             var html = createHtml(o);
4514             newNode = this.insertHtml(pos, el, html);
4515         }
4516         return returnElement ? Roo.get(newNode, true) : newNode;
4517     },
4518
4519     /**
4520      * Creates new Dom element(s) and appends them to el
4521      * @param {String/HTMLElement/Element} el The context element
4522      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4523      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4524      * @return {HTMLElement/Roo.Element} The new node
4525      */
4526     append : function(el, o, returnElement){
4527         el = Roo.getDom(el);
4528         var newNode;
4529         if(this.useDom || o.ns){
4530             newNode = createDom(o, null);
4531             el.appendChild(newNode);
4532         }else{
4533             var html = createHtml(o);
4534             newNode = this.insertHtml("beforeEnd", el, html);
4535         }
4536         return returnElement ? Roo.get(newNode, true) : newNode;
4537     },
4538
4539     /**
4540      * Creates new Dom element(s) and overwrites the contents of el with them
4541      * @param {String/HTMLElement/Element} el The context element
4542      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4543      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4544      * @return {HTMLElement/Roo.Element} The new node
4545      */
4546     overwrite : function(el, o, returnElement){
4547         el = Roo.getDom(el);
4548         if (o.ns) {
4549           
4550             while (el.childNodes.length) {
4551                 el.removeChild(el.firstChild);
4552             }
4553             createDom(o, el);
4554         } else {
4555             el.innerHTML = createHtml(o);   
4556         }
4557         
4558         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4559     },
4560
4561     /**
4562      * Creates a new Roo.DomHelper.Template from the Dom object spec
4563      * @param {Object} o The Dom object spec (and children)
4564      * @return {Roo.DomHelper.Template} The new template
4565      */
4566     createTemplate : function(o){
4567         var html = createHtml(o);
4568         return new Roo.Template(html);
4569     }
4570     };
4571 }();
4572 /*
4573  * Based on:
4574  * Ext JS Library 1.1.1
4575  * Copyright(c) 2006-2007, Ext JS, LLC.
4576  *
4577  * Originally Released Under LGPL - original licence link has changed is not relivant.
4578  *
4579  * Fork - LGPL
4580  * <script type="text/javascript">
4581  */
4582  
4583 /**
4584 * @class Roo.Template
4585 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4586 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4587 * Usage:
4588 <pre><code>
4589 var t = new Roo.Template({
4590     html :  '&lt;div name="{id}"&gt;' + 
4591         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4592         '&lt;/div&gt;',
4593     myformat: function (value, allValues) {
4594         return 'XX' + value;
4595     }
4596 });
4597 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4598 </code></pre>
4599 * For more information see this blog post with examples:
4600 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4601      - Create Elements using DOM, HTML fragments and Templates</a>. 
4602 * @constructor
4603 * @param {Object} cfg - Configuration object.
4604 */
4605 Roo.Template = function(cfg){
4606     // BC!
4607     if(cfg instanceof Array){
4608         cfg = cfg.join("");
4609     }else if(arguments.length > 1){
4610         cfg = Array.prototype.join.call(arguments, "");
4611     }
4612     
4613     
4614     if (typeof(cfg) == 'object') {
4615         Roo.apply(this,cfg)
4616     } else {
4617         // bc
4618         this.html = cfg;
4619     }
4620     if (this.url) {
4621         this.load();
4622     }
4623     
4624 };
4625 Roo.Template.prototype = {
4626     
4627     /**
4628      * @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..
4629      *                    it should be fixed so that template is observable...
4630      */
4631     url : false,
4632     /**
4633      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4634      */
4635     html : '',
4636     /**
4637      * Returns an HTML fragment of this template with the specified values applied.
4638      * @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'})
4639      * @return {String} The HTML fragment
4640      */
4641     applyTemplate : function(values){
4642         try {
4643            
4644             if(this.compiled){
4645                 return this.compiled(values);
4646             }
4647             var useF = this.disableFormats !== true;
4648             var fm = Roo.util.Format, tpl = this;
4649             var fn = function(m, name, format, args){
4650                 if(format && useF){
4651                     if(format.substr(0, 5) == "this."){
4652                         return tpl.call(format.substr(5), values[name], values);
4653                     }else{
4654                         if(args){
4655                             // quoted values are required for strings in compiled templates, 
4656                             // but for non compiled we need to strip them
4657                             // quoted reversed for jsmin
4658                             var re = /^\s*['"](.*)["']\s*$/;
4659                             args = args.split(',');
4660                             for(var i = 0, len = args.length; i < len; i++){
4661                                 args[i] = args[i].replace(re, "$1");
4662                             }
4663                             args = [values[name]].concat(args);
4664                         }else{
4665                             args = [values[name]];
4666                         }
4667                         return fm[format].apply(fm, args);
4668                     }
4669                 }else{
4670                     return values[name] !== undefined ? values[name] : "";
4671                 }
4672             };
4673             return this.html.replace(this.re, fn);
4674         } catch (e) {
4675             Roo.log(e);
4676             throw e;
4677         }
4678          
4679     },
4680     
4681     loading : false,
4682       
4683     load : function ()
4684     {
4685          
4686         if (this.loading) {
4687             return;
4688         }
4689         var _t = this;
4690         
4691         this.loading = true;
4692         this.compiled = false;
4693         
4694         var cx = new Roo.data.Connection();
4695         cx.request({
4696             url : this.url,
4697             method : 'GET',
4698             success : function (response) {
4699                 _t.loading = false;
4700                 _t.html = response.responseText;
4701                 _t.url = false;
4702                 _t.compile();
4703              },
4704             failure : function(response) {
4705                 Roo.log("Template failed to load from " + _t.url);
4706                 _t.loading = false;
4707             }
4708         });
4709     },
4710
4711     /**
4712      * Sets the HTML used as the template and optionally compiles it.
4713      * @param {String} html
4714      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4715      * @return {Roo.Template} this
4716      */
4717     set : function(html, compile){
4718         this.html = html;
4719         this.compiled = null;
4720         if(compile){
4721             this.compile();
4722         }
4723         return this;
4724     },
4725     
4726     /**
4727      * True to disable format functions (defaults to false)
4728      * @type Boolean
4729      */
4730     disableFormats : false,
4731     
4732     /**
4733     * The regular expression used to match template variables 
4734     * @type RegExp
4735     * @property 
4736     */
4737     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4738     
4739     /**
4740      * Compiles the template into an internal function, eliminating the RegEx overhead.
4741      * @return {Roo.Template} this
4742      */
4743     compile : function(){
4744         var fm = Roo.util.Format;
4745         var useF = this.disableFormats !== true;
4746         var sep = Roo.isGecko ? "+" : ",";
4747         var fn = function(m, name, format, args){
4748             if(format && useF){
4749                 args = args ? ',' + args : "";
4750                 if(format.substr(0, 5) != "this."){
4751                     format = "fm." + format + '(';
4752                 }else{
4753                     format = 'this.call("'+ format.substr(5) + '", ';
4754                     args = ", values";
4755                 }
4756             }else{
4757                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4758             }
4759             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4760         };
4761         var body;
4762         // branched to use + in gecko and [].join() in others
4763         if(Roo.isGecko){
4764             body = "this.compiled = function(values){ return '" +
4765                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4766                     "';};";
4767         }else{
4768             body = ["this.compiled = function(values){ return ['"];
4769             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4770             body.push("'].join('');};");
4771             body = body.join('');
4772         }
4773         /**
4774          * eval:var:values
4775          * eval:var:fm
4776          */
4777         eval(body);
4778         return this;
4779     },
4780     
4781     // private function used to call members
4782     call : function(fnName, value, allValues){
4783         return this[fnName](value, allValues);
4784     },
4785     
4786     /**
4787      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4788      * @param {String/HTMLElement/Roo.Element} el The context element
4789      * @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'})
4790      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4791      * @return {HTMLElement/Roo.Element} The new node or Element
4792      */
4793     insertFirst: function(el, values, returnElement){
4794         return this.doInsert('afterBegin', el, values, returnElement);
4795     },
4796
4797     /**
4798      * Applies the supplied values to the template and inserts the new node(s) before el.
4799      * @param {String/HTMLElement/Roo.Element} el The context element
4800      * @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'})
4801      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4802      * @return {HTMLElement/Roo.Element} The new node or Element
4803      */
4804     insertBefore: function(el, values, returnElement){
4805         return this.doInsert('beforeBegin', el, values, returnElement);
4806     },
4807
4808     /**
4809      * Applies the supplied values to the template and inserts the new node(s) after el.
4810      * @param {String/HTMLElement/Roo.Element} el The context element
4811      * @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'})
4812      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4813      * @return {HTMLElement/Roo.Element} The new node or Element
4814      */
4815     insertAfter : function(el, values, returnElement){
4816         return this.doInsert('afterEnd', el, values, returnElement);
4817     },
4818     
4819     /**
4820      * Applies the supplied values to the template and appends the new node(s) to el.
4821      * @param {String/HTMLElement/Roo.Element} el The context element
4822      * @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'})
4823      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4824      * @return {HTMLElement/Roo.Element} The new node or Element
4825      */
4826     append : function(el, values, returnElement){
4827         return this.doInsert('beforeEnd', el, values, returnElement);
4828     },
4829
4830     doInsert : function(where, el, values, returnEl){
4831         el = Roo.getDom(el);
4832         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4833         return returnEl ? Roo.get(newNode, true) : newNode;
4834     },
4835
4836     /**
4837      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4838      * @param {String/HTMLElement/Roo.Element} el The context element
4839      * @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'})
4840      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4841      * @return {HTMLElement/Roo.Element} The new node or Element
4842      */
4843     overwrite : function(el, values, returnElement){
4844         el = Roo.getDom(el);
4845         el.innerHTML = this.applyTemplate(values);
4846         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4847     }
4848 };
4849 /**
4850  * Alias for {@link #applyTemplate}
4851  * @method
4852  */
4853 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4854
4855 // backwards compat
4856 Roo.DomHelper.Template = Roo.Template;
4857
4858 /**
4859  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4860  * @param {String/HTMLElement} el A DOM element or its id
4861  * @returns {Roo.Template} The created template
4862  * @static
4863  */
4864 Roo.Template.from = function(el){
4865     el = Roo.getDom(el);
4866     return new Roo.Template(el.value || el.innerHTML);
4867 };/*
4868  * Based on:
4869  * Ext JS Library 1.1.1
4870  * Copyright(c) 2006-2007, Ext JS, LLC.
4871  *
4872  * Originally Released Under LGPL - original licence link has changed is not relivant.
4873  *
4874  * Fork - LGPL
4875  * <script type="text/javascript">
4876  */
4877  
4878
4879 /*
4880  * This is code is also distributed under MIT license for use
4881  * with jQuery and prototype JavaScript libraries.
4882  */
4883 /**
4884  * @class Roo.DomQuery
4885 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).
4886 <p>
4887 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>
4888
4889 <p>
4890 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.
4891 </p>
4892 <h4>Element Selectors:</h4>
4893 <ul class="list">
4894     <li> <b>*</b> any element</li>
4895     <li> <b>E</b> an element with the tag E</li>
4896     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4897     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4898     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4899     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4900 </ul>
4901 <h4>Attribute Selectors:</h4>
4902 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4903 <ul class="list">
4904     <li> <b>E[foo]</b> has an attribute "foo"</li>
4905     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4906     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4907     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4908     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4909     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4910     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4911 </ul>
4912 <h4>Pseudo Classes:</h4>
4913 <ul class="list">
4914     <li> <b>E:first-child</b> E is the first child of its parent</li>
4915     <li> <b>E:last-child</b> E is the last child of its parent</li>
4916     <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>
4917     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4918     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4919     <li> <b>E:only-child</b> E is the only child of its parent</li>
4920     <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>
4921     <li> <b>E:first</b> the first E in the resultset</li>
4922     <li> <b>E:last</b> the last E in the resultset</li>
4923     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4924     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4925     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4926     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4927     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4928     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4929     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4930     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4931     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4932 </ul>
4933 <h4>CSS Value Selectors:</h4>
4934 <ul class="list">
4935     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4936     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4937     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4938     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4939     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4940     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4941 </ul>
4942  * @singleton
4943  */
4944 Roo.DomQuery = function(){
4945     var cache = {}, simpleCache = {}, valueCache = {};
4946     var nonSpace = /\S/;
4947     var trimRe = /^\s+|\s+$/g;
4948     var tplRe = /\{(\d+)\}/g;
4949     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4950     var tagTokenRe = /^(#)?([\w-\*]+)/;
4951     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4952
4953     function child(p, index){
4954         var i = 0;
4955         var n = p.firstChild;
4956         while(n){
4957             if(n.nodeType == 1){
4958                if(++i == index){
4959                    return n;
4960                }
4961             }
4962             n = n.nextSibling;
4963         }
4964         return null;
4965     };
4966
4967     function next(n){
4968         while((n = n.nextSibling) && n.nodeType != 1);
4969         return n;
4970     };
4971
4972     function prev(n){
4973         while((n = n.previousSibling) && n.nodeType != 1);
4974         return n;
4975     };
4976
4977     function children(d){
4978         var n = d.firstChild, ni = -1;
4979             while(n){
4980                 var nx = n.nextSibling;
4981                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4982                     d.removeChild(n);
4983                 }else{
4984                     n.nodeIndex = ++ni;
4985                 }
4986                 n = nx;
4987             }
4988             return this;
4989         };
4990
4991     function byClassName(c, a, v){
4992         if(!v){
4993             return c;
4994         }
4995         var r = [], ri = -1, cn;
4996         for(var i = 0, ci; ci = c[i]; i++){
4997             if((' '+ci.className+' ').indexOf(v) != -1){
4998                 r[++ri] = ci;
4999             }
5000         }
5001         return r;
5002     };
5003
5004     function attrValue(n, attr){
5005         if(!n.tagName && typeof n.length != "undefined"){
5006             n = n[0];
5007         }
5008         if(!n){
5009             return null;
5010         }
5011         if(attr == "for"){
5012             return n.htmlFor;
5013         }
5014         if(attr == "class" || attr == "className"){
5015             return n.className;
5016         }
5017         return n.getAttribute(attr) || n[attr];
5018
5019     };
5020
5021     function getNodes(ns, mode, tagName){
5022         var result = [], ri = -1, cs;
5023         if(!ns){
5024             return result;
5025         }
5026         tagName = tagName || "*";
5027         if(typeof ns.getElementsByTagName != "undefined"){
5028             ns = [ns];
5029         }
5030         if(!mode){
5031             for(var i = 0, ni; ni = ns[i]; i++){
5032                 cs = ni.getElementsByTagName(tagName);
5033                 for(var j = 0, ci; ci = cs[j]; j++){
5034                     result[++ri] = ci;
5035                 }
5036             }
5037         }else if(mode == "/" || mode == ">"){
5038             var utag = tagName.toUpperCase();
5039             for(var i = 0, ni, cn; ni = ns[i]; i++){
5040                 cn = ni.children || ni.childNodes;
5041                 for(var j = 0, cj; cj = cn[j]; j++){
5042                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5043                         result[++ri] = cj;
5044                     }
5045                 }
5046             }
5047         }else if(mode == "+"){
5048             var utag = tagName.toUpperCase();
5049             for(var i = 0, n; n = ns[i]; i++){
5050                 while((n = n.nextSibling) && n.nodeType != 1);
5051                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5052                     result[++ri] = n;
5053                 }
5054             }
5055         }else if(mode == "~"){
5056             for(var i = 0, n; n = ns[i]; i++){
5057                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5058                 if(n){
5059                     result[++ri] = n;
5060                 }
5061             }
5062         }
5063         return result;
5064     };
5065
5066     function concat(a, b){
5067         if(b.slice){
5068             return a.concat(b);
5069         }
5070         for(var i = 0, l = b.length; i < l; i++){
5071             a[a.length] = b[i];
5072         }
5073         return a;
5074     }
5075
5076     function byTag(cs, tagName){
5077         if(cs.tagName || cs == document){
5078             cs = [cs];
5079         }
5080         if(!tagName){
5081             return cs;
5082         }
5083         var r = [], ri = -1;
5084         tagName = tagName.toLowerCase();
5085         for(var i = 0, ci; ci = cs[i]; i++){
5086             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5087                 r[++ri] = ci;
5088             }
5089         }
5090         return r;
5091     };
5092
5093     function byId(cs, attr, id){
5094         if(cs.tagName || cs == document){
5095             cs = [cs];
5096         }
5097         if(!id){
5098             return cs;
5099         }
5100         var r = [], ri = -1;
5101         for(var i = 0,ci; ci = cs[i]; i++){
5102             if(ci && ci.id == id){
5103                 r[++ri] = ci;
5104                 return r;
5105             }
5106         }
5107         return r;
5108     };
5109
5110     function byAttribute(cs, attr, value, op, custom){
5111         var r = [], ri = -1, st = custom=="{";
5112         var f = Roo.DomQuery.operators[op];
5113         for(var i = 0, ci; ci = cs[i]; i++){
5114             var a;
5115             if(st){
5116                 a = Roo.DomQuery.getStyle(ci, attr);
5117             }
5118             else if(attr == "class" || attr == "className"){
5119                 a = ci.className;
5120             }else if(attr == "for"){
5121                 a = ci.htmlFor;
5122             }else if(attr == "href"){
5123                 a = ci.getAttribute("href", 2);
5124             }else{
5125                 a = ci.getAttribute(attr);
5126             }
5127             if((f && f(a, value)) || (!f && a)){
5128                 r[++ri] = ci;
5129             }
5130         }
5131         return r;
5132     };
5133
5134     function byPseudo(cs, name, value){
5135         return Roo.DomQuery.pseudos[name](cs, value);
5136     };
5137
5138     // This is for IE MSXML which does not support expandos.
5139     // IE runs the same speed using setAttribute, however FF slows way down
5140     // and Safari completely fails so they need to continue to use expandos.
5141     var isIE = window.ActiveXObject ? true : false;
5142
5143     // this eval is stop the compressor from
5144     // renaming the variable to something shorter
5145     
5146     /** eval:var:batch */
5147     var batch = 30803; 
5148
5149     var key = 30803;
5150
5151     function nodupIEXml(cs){
5152         var d = ++key;
5153         cs[0].setAttribute("_nodup", d);
5154         var r = [cs[0]];
5155         for(var i = 1, len = cs.length; i < len; i++){
5156             var c = cs[i];
5157             if(!c.getAttribute("_nodup") != d){
5158                 c.setAttribute("_nodup", d);
5159                 r[r.length] = c;
5160             }
5161         }
5162         for(var i = 0, len = cs.length; i < len; i++){
5163             cs[i].removeAttribute("_nodup");
5164         }
5165         return r;
5166     }
5167
5168     function nodup(cs){
5169         if(!cs){
5170             return [];
5171         }
5172         var len = cs.length, c, i, r = cs, cj, ri = -1;
5173         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5174             return cs;
5175         }
5176         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5177             return nodupIEXml(cs);
5178         }
5179         var d = ++key;
5180         cs[0]._nodup = d;
5181         for(i = 1; c = cs[i]; i++){
5182             if(c._nodup != d){
5183                 c._nodup = d;
5184             }else{
5185                 r = [];
5186                 for(var j = 0; j < i; j++){
5187                     r[++ri] = cs[j];
5188                 }
5189                 for(j = i+1; cj = cs[j]; j++){
5190                     if(cj._nodup != d){
5191                         cj._nodup = d;
5192                         r[++ri] = cj;
5193                     }
5194                 }
5195                 return r;
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickDiffIEXml(c1, c2){
5202         var d = ++key;
5203         for(var i = 0, len = c1.length; i < len; i++){
5204             c1[i].setAttribute("_qdiff", d);
5205         }
5206         var r = [];
5207         for(var i = 0, len = c2.length; i < len; i++){
5208             if(c2[i].getAttribute("_qdiff") != d){
5209                 r[r.length] = c2[i];
5210             }
5211         }
5212         for(var i = 0, len = c1.length; i < len; i++){
5213            c1[i].removeAttribute("_qdiff");
5214         }
5215         return r;
5216     }
5217
5218     function quickDiff(c1, c2){
5219         var len1 = c1.length;
5220         if(!len1){
5221             return c2;
5222         }
5223         if(isIE && c1[0].selectSingleNode){
5224             return quickDiffIEXml(c1, c2);
5225         }
5226         var d = ++key;
5227         for(var i = 0; i < len1; i++){
5228             c1[i]._qdiff = d;
5229         }
5230         var r = [];
5231         for(var i = 0, len = c2.length; i < len; i++){
5232             if(c2[i]._qdiff != d){
5233                 r[r.length] = c2[i];
5234             }
5235         }
5236         return r;
5237     }
5238
5239     function quickId(ns, mode, root, id){
5240         if(ns == root){
5241            var d = root.ownerDocument || root;
5242            return d.getElementById(id);
5243         }
5244         ns = getNodes(ns, mode, "*");
5245         return byId(ns, null, id);
5246     }
5247
5248     return {
5249         getStyle : function(el, name){
5250             return Roo.fly(el).getStyle(name);
5251         },
5252         /**
5253          * Compiles a selector/xpath query into a reusable function. The returned function
5254          * takes one parameter "root" (optional), which is the context node from where the query should start.
5255          * @param {String} selector The selector/xpath query
5256          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5257          * @return {Function}
5258          */
5259         compile : function(path, type){
5260             type = type || "select";
5261             
5262             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5263             var q = path, mode, lq;
5264             var tk = Roo.DomQuery.matchers;
5265             var tklen = tk.length;
5266             var mm;
5267
5268             // accept leading mode switch
5269             var lmode = q.match(modeRe);
5270             if(lmode && lmode[1]){
5271                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5272                 q = q.replace(lmode[1], "");
5273             }
5274             // strip leading slashes
5275             while(path.substr(0, 1)=="/"){
5276                 path = path.substr(1);
5277             }
5278
5279             while(q && lq != q){
5280                 lq = q;
5281                 var tm = q.match(tagTokenRe);
5282                 if(type == "select"){
5283                     if(tm){
5284                         if(tm[1] == "#"){
5285                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5286                         }else{
5287                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5288                         }
5289                         q = q.replace(tm[0], "");
5290                     }else if(q.substr(0, 1) != '@'){
5291                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292                     }
5293                 }else{
5294                     if(tm){
5295                         if(tm[1] == "#"){
5296                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5297                         }else{
5298                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5299                         }
5300                         q = q.replace(tm[0], "");
5301                     }
5302                 }
5303                 while(!(mm = q.match(modeRe))){
5304                     var matched = false;
5305                     for(var j = 0; j < tklen; j++){
5306                         var t = tk[j];
5307                         var m = q.match(t.re);
5308                         if(m){
5309                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5310                                                     return m[i];
5311                                                 });
5312                             q = q.replace(m[0], "");
5313                             matched = true;
5314                             break;
5315                         }
5316                     }
5317                     // prevent infinite loop on bad selector
5318                     if(!matched){
5319                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5320                     }
5321                 }
5322                 if(mm[1]){
5323                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5324                     q = q.replace(mm[1], "");
5325                 }
5326             }
5327             fn[fn.length] = "return nodup(n);\n}";
5328             
5329              /** 
5330               * list of variables that need from compression as they are used by eval.
5331              *  eval:var:batch 
5332              *  eval:var:nodup
5333              *  eval:var:byTag
5334              *  eval:var:ById
5335              *  eval:var:getNodes
5336              *  eval:var:quickId
5337              *  eval:var:mode
5338              *  eval:var:root
5339              *  eval:var:n
5340              *  eval:var:byClassName
5341              *  eval:var:byPseudo
5342              *  eval:var:byAttribute
5343              *  eval:var:attrValue
5344              * 
5345              **/ 
5346             eval(fn.join(""));
5347             return f;
5348         },
5349
5350         /**
5351          * Selects a group of elements.
5352          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5353          * @param {Node} root (optional) The start of the query (defaults to document).
5354          * @return {Array}
5355          */
5356         select : function(path, root, type){
5357             if(!root || root == document){
5358                 root = document;
5359             }
5360             if(typeof root == "string"){
5361                 root = document.getElementById(root);
5362             }
5363             var paths = path.split(",");
5364             var results = [];
5365             for(var i = 0, len = paths.length; i < len; i++){
5366                 var p = paths[i].replace(trimRe, "");
5367                 if(!cache[p]){
5368                     cache[p] = Roo.DomQuery.compile(p);
5369                     if(!cache[p]){
5370                         throw p + " is not a valid selector";
5371                     }
5372                 }
5373                 var result = cache[p](root);
5374                 if(result && result != document){
5375                     results = results.concat(result);
5376                 }
5377             }
5378             if(paths.length > 1){
5379                 return nodup(results);
5380             }
5381             return results;
5382         },
5383
5384         /**
5385          * Selects a single element.
5386          * @param {String} selector The selector/xpath query
5387          * @param {Node} root (optional) The start of the query (defaults to document).
5388          * @return {Element}
5389          */
5390         selectNode : function(path, root){
5391             return Roo.DomQuery.select(path, root)[0];
5392         },
5393
5394         /**
5395          * Selects the value of a node, optionally replacing null with the defaultValue.
5396          * @param {String} selector The selector/xpath query
5397          * @param {Node} root (optional) The start of the query (defaults to document).
5398          * @param {String} defaultValue
5399          */
5400         selectValue : function(path, root, defaultValue){
5401             path = path.replace(trimRe, "");
5402             if(!valueCache[path]){
5403                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5404             }
5405             var n = valueCache[path](root);
5406             n = n[0] ? n[0] : n;
5407             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5408             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5409         },
5410
5411         /**
5412          * Selects the value of a node, parsing integers and floats.
5413          * @param {String} selector The selector/xpath query
5414          * @param {Node} root (optional) The start of the query (defaults to document).
5415          * @param {Number} defaultValue
5416          * @return {Number}
5417          */
5418         selectNumber : function(path, root, defaultValue){
5419             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5420             return parseFloat(v);
5421         },
5422
5423         /**
5424          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5425          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5426          * @param {String} selector The simple selector to test
5427          * @return {Boolean}
5428          */
5429         is : function(el, ss){
5430             if(typeof el == "string"){
5431                 el = document.getElementById(el);
5432             }
5433             var isArray = (el instanceof Array);
5434             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5435             return isArray ? (result.length == el.length) : (result.length > 0);
5436         },
5437
5438         /**
5439          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5440          * @param {Array} el An array of elements to filter
5441          * @param {String} selector The simple selector to test
5442          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5443          * the selector instead of the ones that match
5444          * @return {Array}
5445          */
5446         filter : function(els, ss, nonMatches){
5447             ss = ss.replace(trimRe, "");
5448             if(!simpleCache[ss]){
5449                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5450             }
5451             var result = simpleCache[ss](els);
5452             return nonMatches ? quickDiff(result, els) : result;
5453         },
5454
5455         /**
5456          * Collection of matching regular expressions and code snippets.
5457          */
5458         matchers : [{
5459                 re: /^\.([\w-]+)/,
5460                 select: 'n = byClassName(n, null, " {1} ");'
5461             }, {
5462                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5463                 select: 'n = byPseudo(n, "{1}", "{2}");'
5464             },{
5465                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5466                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5467             }, {
5468                 re: /^#([\w-]+)/,
5469                 select: 'n = byId(n, null, "{1}");'
5470             },{
5471                 re: /^@([\w-]+)/,
5472                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473             }
5474         ],
5475
5476         /**
5477          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5478          * 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;.
5479          */
5480         operators : {
5481             "=" : function(a, v){
5482                 return a == v;
5483             },
5484             "!=" : function(a, v){
5485                 return a != v;
5486             },
5487             "^=" : function(a, v){
5488                 return a && a.substr(0, v.length) == v;
5489             },
5490             "$=" : function(a, v){
5491                 return a && a.substr(a.length-v.length) == v;
5492             },
5493             "*=" : function(a, v){
5494                 return a && a.indexOf(v) !== -1;
5495             },
5496             "%=" : function(a, v){
5497                 return (a % v) == 0;
5498             },
5499             "|=" : function(a, v){
5500                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5501             },
5502             "~=" : function(a, v){
5503                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504             }
5505         },
5506
5507         /**
5508          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5509          * and the argument (if any) supplied in the selector.
5510          */
5511         pseudos : {
5512             "first-child" : function(c){
5513                 var r = [], ri = -1, n;
5514                 for(var i = 0, ci; ci = n = c[i]; i++){
5515                     while((n = n.previousSibling) && n.nodeType != 1);
5516                     if(!n){
5517                         r[++ri] = ci;
5518                     }
5519                 }
5520                 return r;
5521             },
5522
5523             "last-child" : function(c){
5524                 var r = [], ri = -1, n;
5525                 for(var i = 0, ci; ci = n = c[i]; i++){
5526                     while((n = n.nextSibling) && n.nodeType != 1);
5527                     if(!n){
5528                         r[++ri] = ci;
5529                     }
5530                 }
5531                 return r;
5532             },
5533
5534             "nth-child" : function(c, a) {
5535                 var r = [], ri = -1;
5536                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5537                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5538                 for(var i = 0, n; n = c[i]; i++){
5539                     var pn = n.parentNode;
5540                     if (batch != pn._batch) {
5541                         var j = 0;
5542                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5543                             if(cn.nodeType == 1){
5544                                cn.nodeIndex = ++j;
5545                             }
5546                         }
5547                         pn._batch = batch;
5548                     }
5549                     if (f == 1) {
5550                         if (l == 0 || n.nodeIndex == l){
5551                             r[++ri] = n;
5552                         }
5553                     } else if ((n.nodeIndex + l) % f == 0){
5554                         r[++ri] = n;
5555                     }
5556                 }
5557
5558                 return r;
5559             },
5560
5561             "only-child" : function(c){
5562                 var r = [], ri = -1;;
5563                 for(var i = 0, ci; ci = c[i]; i++){
5564                     if(!prev(ci) && !next(ci)){
5565                         r[++ri] = ci;
5566                     }
5567                 }
5568                 return r;
5569             },
5570
5571             "empty" : function(c){
5572                 var r = [], ri = -1;
5573                 for(var i = 0, ci; ci = c[i]; i++){
5574                     var cns = ci.childNodes, j = 0, cn, empty = true;
5575                     while(cn = cns[j]){
5576                         ++j;
5577                         if(cn.nodeType == 1 || cn.nodeType == 3){
5578                             empty = false;
5579                             break;
5580                         }
5581                     }
5582                     if(empty){
5583                         r[++ri] = ci;
5584                     }
5585                 }
5586                 return r;
5587             },
5588
5589             "contains" : function(c, v){
5590                 var r = [], ri = -1;
5591                 for(var i = 0, ci; ci = c[i]; i++){
5592                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5593                         r[++ri] = ci;
5594                     }
5595                 }
5596                 return r;
5597             },
5598
5599             "nodeValue" : function(c, v){
5600                 var r = [], ri = -1;
5601                 for(var i = 0, ci; ci = c[i]; i++){
5602                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5603                         r[++ri] = ci;
5604                     }
5605                 }
5606                 return r;
5607             },
5608
5609             "checked" : function(c){
5610                 var r = [], ri = -1;
5611                 for(var i = 0, ci; ci = c[i]; i++){
5612                     if(ci.checked == true){
5613                         r[++ri] = ci;
5614                     }
5615                 }
5616                 return r;
5617             },
5618
5619             "not" : function(c, ss){
5620                 return Roo.DomQuery.filter(c, ss, true);
5621             },
5622
5623             "odd" : function(c){
5624                 return this["nth-child"](c, "odd");
5625             },
5626
5627             "even" : function(c){
5628                 return this["nth-child"](c, "even");
5629             },
5630
5631             "nth" : function(c, a){
5632                 return c[a-1] || [];
5633             },
5634
5635             "first" : function(c){
5636                 return c[0] || [];
5637             },
5638
5639             "last" : function(c){
5640                 return c[c.length-1] || [];
5641             },
5642
5643             "has" : function(c, ss){
5644                 var s = Roo.DomQuery.select;
5645                 var r = [], ri = -1;
5646                 for(var i = 0, ci; ci = c[i]; i++){
5647                     if(s(ss, ci).length > 0){
5648                         r[++ri] = ci;
5649                     }
5650                 }
5651                 return r;
5652             },
5653
5654             "next" : function(c, ss){
5655                 var is = Roo.DomQuery.is;
5656                 var r = [], ri = -1;
5657                 for(var i = 0, ci; ci = c[i]; i++){
5658                     var n = next(ci);
5659                     if(n && is(n, ss)){
5660                         r[++ri] = ci;
5661                     }
5662                 }
5663                 return r;
5664             },
5665
5666             "prev" : function(c, ss){
5667                 var is = Roo.DomQuery.is;
5668                 var r = [], ri = -1;
5669                 for(var i = 0, ci; ci = c[i]; i++){
5670                     var n = prev(ci);
5671                     if(n && is(n, ss)){
5672                         r[++ri] = ci;
5673                     }
5674                 }
5675                 return r;
5676             }
5677         }
5678     };
5679 }();
5680
5681 /**
5682  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5683  * @param {String} path The selector/xpath query
5684  * @param {Node} root (optional) The start of the query (defaults to document).
5685  * @return {Array}
5686  * @member Roo
5687  * @method query
5688  */
5689 Roo.query = Roo.DomQuery.select;
5690 /*
5691  * Based on:
5692  * Ext JS Library 1.1.1
5693  * Copyright(c) 2006-2007, Ext JS, LLC.
5694  *
5695  * Originally Released Under LGPL - original licence link has changed is not relivant.
5696  *
5697  * Fork - LGPL
5698  * <script type="text/javascript">
5699  */
5700
5701 /**
5702  * @class Roo.util.Observable
5703  * Base class that provides a common interface for publishing events. Subclasses are expected to
5704  * to have a property "events" with all the events defined.<br>
5705  * For example:
5706  * <pre><code>
5707  Employee = function(name){
5708     this.name = name;
5709     this.addEvents({
5710         "fired" : true,
5711         "quit" : true
5712     });
5713  }
5714  Roo.extend(Employee, Roo.util.Observable);
5715 </code></pre>
5716  * @param {Object} config properties to use (incuding events / listeners)
5717  */
5718
5719 Roo.util.Observable = function(cfg){
5720     
5721     cfg = cfg|| {};
5722     this.addEvents(cfg.events || {});
5723     if (cfg.events) {
5724         delete cfg.events; // make sure
5725     }
5726      
5727     Roo.apply(this, cfg);
5728     
5729     if(this.listeners){
5730         this.on(this.listeners);
5731         delete this.listeners;
5732     }
5733 };
5734 Roo.util.Observable.prototype = {
5735     /** 
5736  * @cfg {Object} listeners  list of events and functions to call for this object, 
5737  * For example :
5738  * <pre><code>
5739     listeners :  { 
5740        'click' : function(e) {
5741            ..... 
5742         } ,
5743         .... 
5744     } 
5745   </code></pre>
5746  */
5747     
5748     
5749     /**
5750      * Fires the specified event with the passed parameters (minus the event name).
5751      * @param {String} eventName
5752      * @param {Object...} args Variable number of parameters are passed to handlers
5753      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5754      */
5755     fireEvent : function(){
5756         var ce = this.events[arguments[0].toLowerCase()];
5757         if(typeof ce == "object"){
5758             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5759         }else{
5760             return true;
5761         }
5762     },
5763
5764     // private
5765     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5766
5767     /**
5768      * Appends an event handler to this component
5769      * @param {String}   eventName The type of event to listen for
5770      * @param {Function} handler The method the event invokes
5771      * @param {Object}   scope (optional) The scope in which to execute the handler
5772      * function. The handler function's "this" context.
5773      * @param {Object}   options (optional) An object containing handler configuration
5774      * properties. This may contain any of the following properties:<ul>
5775      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5776      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5777      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5778      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5779      * by the specified number of milliseconds. If the event fires again within that time, the original
5780      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5781      * </ul><br>
5782      * <p>
5783      * <b>Combining Options</b><br>
5784      * Using the options argument, it is possible to combine different types of listeners:<br>
5785      * <br>
5786      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5787                 <pre><code>
5788                 el.on('click', this.onClick, this, {
5789                         single: true,
5790                 delay: 100,
5791                 forumId: 4
5792                 });
5793                 </code></pre>
5794      * <p>
5795      * <b>Attaching multiple handlers in 1 call</b><br>
5796      * The method also allows for a single argument to be passed which is a config object containing properties
5797      * which specify multiple handlers.
5798      * <pre><code>
5799                 el.on({
5800                         'click': {
5801                         fn: this.onClick,
5802                         scope: this,
5803                         delay: 100
5804                 }, 
5805                 'mouseover': {
5806                         fn: this.onMouseOver,
5807                         scope: this
5808                 },
5809                 'mouseout': {
5810                         fn: this.onMouseOut,
5811                         scope: this
5812                 }
5813                 });
5814                 </code></pre>
5815      * <p>
5816      * Or a shorthand syntax which passes the same scope object to all handlers:
5817         <pre><code>
5818                 el.on({
5819                         'click': this.onClick,
5820                 'mouseover': this.onMouseOver,
5821                 'mouseout': this.onMouseOut,
5822                 scope: this
5823                 });
5824                 </code></pre>
5825      */
5826     addListener : function(eventName, fn, scope, o){
5827         if(typeof eventName == "object"){
5828             o = eventName;
5829             for(var e in o){
5830                 if(this.filterOptRe.test(e)){
5831                     continue;
5832                 }
5833                 if(typeof o[e] == "function"){
5834                     // shared options
5835                     this.addListener(e, o[e], o.scope,  o);
5836                 }else{
5837                     // individual options
5838                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839                 }
5840             }
5841             return;
5842         }
5843         o = (!o || typeof o == "boolean") ? {} : o;
5844         eventName = eventName.toLowerCase();
5845         var ce = this.events[eventName] || true;
5846         if(typeof ce == "boolean"){
5847             ce = new Roo.util.Event(this, eventName);
5848             this.events[eventName] = ce;
5849         }
5850         ce.addListener(fn, scope, o);
5851     },
5852
5853     /**
5854      * Removes a listener
5855      * @param {String}   eventName     The type of event to listen for
5856      * @param {Function} handler        The handler to remove
5857      * @param {Object}   scope  (optional) The scope (this object) for the handler
5858      */
5859     removeListener : function(eventName, fn, scope){
5860         var ce = this.events[eventName.toLowerCase()];
5861         if(typeof ce == "object"){
5862             ce.removeListener(fn, scope);
5863         }
5864     },
5865
5866     /**
5867      * Removes all listeners for this object
5868      */
5869     purgeListeners : function(){
5870         for(var evt in this.events){
5871             if(typeof this.events[evt] == "object"){
5872                  this.events[evt].clearListeners();
5873             }
5874         }
5875     },
5876
5877     relayEvents : function(o, events){
5878         var createHandler = function(ename){
5879             return function(){
5880                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5881             };
5882         };
5883         for(var i = 0, len = events.length; i < len; i++){
5884             var ename = events[i];
5885             if(!this.events[ename]){ this.events[ename] = true; };
5886             o.on(ename, createHandler(ename), this);
5887         }
5888     },
5889
5890     /**
5891      * Used to define events on this Observable
5892      * @param {Object} object The object with the events defined
5893      */
5894     addEvents : function(o){
5895         if(!this.events){
5896             this.events = {};
5897         }
5898         Roo.applyIf(this.events, o);
5899     },
5900
5901     /**
5902      * Checks to see if this object has any listeners for a specified event
5903      * @param {String} eventName The name of the event to check for
5904      * @return {Boolean} True if the event is being listened for, else false
5905      */
5906     hasListener : function(eventName){
5907         var e = this.events[eventName];
5908         return typeof e == "object" && e.listeners.length > 0;
5909     }
5910 };
5911 /**
5912  * Appends an event handler to this element (shorthand for addListener)
5913  * @param {String}   eventName     The type of event to listen for
5914  * @param {Function} handler        The method the event invokes
5915  * @param {Object}   scope (optional) The scope in which to execute the handler
5916  * function. The handler function's "this" context.
5917  * @param {Object}   options  (optional)
5918  * @method
5919  */
5920 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5921 /**
5922  * Removes a listener (shorthand for removeListener)
5923  * @param {String}   eventName     The type of event to listen for
5924  * @param {Function} handler        The handler to remove
5925  * @param {Object}   scope  (optional) The scope (this object) for the handler
5926  * @method
5927  */
5928 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5929
5930 /**
5931  * Starts capture on the specified Observable. All events will be passed
5932  * to the supplied function with the event name + standard signature of the event
5933  * <b>before</b> the event is fired. If the supplied function returns false,
5934  * the event will not fire.
5935  * @param {Observable} o The Observable to capture
5936  * @param {Function} fn The function to call
5937  * @param {Object} scope (optional) The scope (this object) for the fn
5938  * @static
5939  */
5940 Roo.util.Observable.capture = function(o, fn, scope){
5941     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5942 };
5943
5944 /**
5945  * Removes <b>all</b> added captures from the Observable.
5946  * @param {Observable} o The Observable to release
5947  * @static
5948  */
5949 Roo.util.Observable.releaseCapture = function(o){
5950     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 };
5952
5953 (function(){
5954
5955     var createBuffered = function(h, o, scope){
5956         var task = new Roo.util.DelayedTask();
5957         return function(){
5958             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5959         };
5960     };
5961
5962     var createSingle = function(h, e, fn, scope){
5963         return function(){
5964             e.removeListener(fn, scope);
5965             return h.apply(scope, arguments);
5966         };
5967     };
5968
5969     var createDelayed = function(h, o, scope){
5970         return function(){
5971             var args = Array.prototype.slice.call(arguments, 0);
5972             setTimeout(function(){
5973                 h.apply(scope, args);
5974             }, o.delay || 10);
5975         };
5976     };
5977
5978     Roo.util.Event = function(obj, name){
5979         this.name = name;
5980         this.obj = obj;
5981         this.listeners = [];
5982     };
5983
5984     Roo.util.Event.prototype = {
5985         addListener : function(fn, scope, options){
5986             var o = options || {};
5987             scope = scope || this.obj;
5988             if(!this.isListening(fn, scope)){
5989                 var l = {fn: fn, scope: scope, options: o};
5990                 var h = fn;
5991                 if(o.delay){
5992                     h = createDelayed(h, o, scope);
5993                 }
5994                 if(o.single){
5995                     h = createSingle(h, this, fn, scope);
5996                 }
5997                 if(o.buffer){
5998                     h = createBuffered(h, o, scope);
5999                 }
6000                 l.fireFn = h;
6001                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6002                     this.listeners.push(l);
6003                 }else{
6004                     this.listeners = this.listeners.slice(0);
6005                     this.listeners.push(l);
6006                 }
6007             }
6008         },
6009
6010         findListener : function(fn, scope){
6011             scope = scope || this.obj;
6012             var ls = this.listeners;
6013             for(var i = 0, len = ls.length; i < len; i++){
6014                 var l = ls[i];
6015                 if(l.fn == fn && l.scope == scope){
6016                     return i;
6017                 }
6018             }
6019             return -1;
6020         },
6021
6022         isListening : function(fn, scope){
6023             return this.findListener(fn, scope) != -1;
6024         },
6025
6026         removeListener : function(fn, scope){
6027             var index;
6028             if((index = this.findListener(fn, scope)) != -1){
6029                 if(!this.firing){
6030                     this.listeners.splice(index, 1);
6031                 }else{
6032                     this.listeners = this.listeners.slice(0);
6033                     this.listeners.splice(index, 1);
6034                 }
6035                 return true;
6036             }
6037             return false;
6038         },
6039
6040         clearListeners : function(){
6041             this.listeners = [];
6042         },
6043
6044         fire : function(){
6045             var ls = this.listeners, scope, len = ls.length;
6046             if(len > 0){
6047                 this.firing = true;
6048                 var args = Array.prototype.slice.call(arguments, 0);
6049                 for(var i = 0; i < len; i++){
6050                     var l = ls[i];
6051                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6052                         this.firing = false;
6053                         return false;
6054                     }
6055                 }
6056                 this.firing = false;
6057             }
6058             return true;
6059         }
6060     };
6061 })();/*
6062  * RooJS Library 
6063  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6064  *
6065  * Licence LGPL 
6066  *
6067  */
6068  
6069 /**
6070  * @class Roo.Document
6071  * @extends Roo.util.Observable
6072  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6073  * 
6074  * @param {Object} config the methods and properties of the 'base' class for the application.
6075  * 
6076  *  Generic Page handler - implement this to start your app..
6077  * 
6078  * eg.
6079  *  MyProject = new Roo.Document({
6080         events : {
6081             'load' : true // your events..
6082         },
6083         listeners : {
6084             'ready' : function() {
6085                 // fired on Roo.onReady()
6086             }
6087         }
6088  * 
6089  */
6090 Roo.Document = function(cfg) {
6091      
6092     this.addEvents({ 
6093         'ready' : true
6094     });
6095     Roo.util.Observable.call(this,cfg);
6096     
6097     var _this = this;
6098     
6099     Roo.onReady(function() {
6100         _this.fireEvent('ready');
6101     },null,false);
6102     
6103     
6104 }
6105
6106 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6107  * Based on:
6108  * Ext JS Library 1.1.1
6109  * Copyright(c) 2006-2007, Ext JS, LLC.
6110  *
6111  * Originally Released Under LGPL - original licence link has changed is not relivant.
6112  *
6113  * Fork - LGPL
6114  * <script type="text/javascript">
6115  */
6116
6117 /**
6118  * @class Roo.EventManager
6119  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6120  * several useful events directly.
6121  * See {@link Roo.EventObject} for more details on normalized event objects.
6122  * @singleton
6123  */
6124 Roo.EventManager = function(){
6125     var docReadyEvent, docReadyProcId, docReadyState = false;
6126     var resizeEvent, resizeTask, textEvent, textSize;
6127     var E = Roo.lib.Event;
6128     var D = Roo.lib.Dom;
6129
6130     
6131     
6132
6133     var fireDocReady = function(){
6134         if(!docReadyState){
6135             docReadyState = true;
6136             Roo.isReady = true;
6137             if(docReadyProcId){
6138                 clearInterval(docReadyProcId);
6139             }
6140             if(Roo.isGecko || Roo.isOpera) {
6141                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6142             }
6143             if(Roo.isIE){
6144                 var defer = document.getElementById("ie-deferred-loader");
6145                 if(defer){
6146                     defer.onreadystatechange = null;
6147                     defer.parentNode.removeChild(defer);
6148                 }
6149             }
6150             if(docReadyEvent){
6151                 docReadyEvent.fire();
6152                 docReadyEvent.clearListeners();
6153             }
6154         }
6155     };
6156     
6157     var initDocReady = function(){
6158         docReadyEvent = new Roo.util.Event();
6159         if(Roo.isGecko || Roo.isOpera) {
6160             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6161         }else if(Roo.isIE){
6162             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6163             var defer = document.getElementById("ie-deferred-loader");
6164             defer.onreadystatechange = function(){
6165                 if(this.readyState == "complete"){
6166                     fireDocReady();
6167                 }
6168             };
6169         }else if(Roo.isSafari){ 
6170             docReadyProcId = setInterval(function(){
6171                 var rs = document.readyState;
6172                 if(rs == "complete") {
6173                     fireDocReady();     
6174                  }
6175             }, 10);
6176         }
6177         // no matter what, make sure it fires on load
6178         E.on(window, "load", fireDocReady);
6179     };
6180
6181     var createBuffered = function(h, o){
6182         var task = new Roo.util.DelayedTask(h);
6183         return function(e){
6184             // create new event object impl so new events don't wipe out properties
6185             e = new Roo.EventObjectImpl(e);
6186             task.delay(o.buffer, h, null, [e]);
6187         };
6188     };
6189
6190     var createSingle = function(h, el, ename, fn){
6191         return function(e){
6192             Roo.EventManager.removeListener(el, ename, fn);
6193             h(e);
6194         };
6195     };
6196
6197     var createDelayed = function(h, o){
6198         return function(e){
6199             // create new event object impl so new events don't wipe out properties
6200             e = new Roo.EventObjectImpl(e);
6201             setTimeout(function(){
6202                 h(e);
6203             }, o.delay || 10);
6204         };
6205     };
6206     var transitionEndVal = false;
6207     
6208     var transitionEnd = function()
6209     {
6210         if (transitionEndVal) {
6211             return transitionEndVal;
6212         }
6213         var el = document.createElement('div');
6214
6215         var transEndEventNames = {
6216             WebkitTransition : 'webkitTransitionEnd',
6217             MozTransition    : 'transitionend',
6218             OTransition      : 'oTransitionEnd otransitionend',
6219             transition       : 'transitionend'
6220         };
6221     
6222         for (var name in transEndEventNames) {
6223             if (el.style[name] !== undefined) {
6224                 transitionEndVal = transEndEventNames[name];
6225                 return  transitionEndVal ;
6226             }
6227         }
6228     }
6229     
6230
6231     var listen = function(element, ename, opt, fn, scope){
6232         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6233         fn = fn || o.fn; scope = scope || o.scope;
6234         var el = Roo.getDom(element);
6235         
6236         
6237         if(!el){
6238             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6239         }
6240         
6241         if (ename == 'transitionend') {
6242             ename = transitionEnd();
6243         }
6244         var h = function(e){
6245             e = Roo.EventObject.setEvent(e);
6246             var t;
6247             if(o.delegate){
6248                 t = e.getTarget(o.delegate, el);
6249                 if(!t){
6250                     return;
6251                 }
6252             }else{
6253                 t = e.target;
6254             }
6255             if(o.stopEvent === true){
6256                 e.stopEvent();
6257             }
6258             if(o.preventDefault === true){
6259                e.preventDefault();
6260             }
6261             if(o.stopPropagation === true){
6262                 e.stopPropagation();
6263             }
6264
6265             if(o.normalized === false){
6266                 e = e.browserEvent;
6267             }
6268
6269             fn.call(scope || el, e, t, o);
6270         };
6271         if(o.delay){
6272             h = createDelayed(h, o);
6273         }
6274         if(o.single){
6275             h = createSingle(h, el, ename, fn);
6276         }
6277         if(o.buffer){
6278             h = createBuffered(h, o);
6279         }
6280         fn._handlers = fn._handlers || [];
6281         
6282         
6283         fn._handlers.push([Roo.id(el), ename, h]);
6284         
6285         
6286          
6287         E.on(el, ename, h);
6288         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6289             el.addEventListener("DOMMouseScroll", h, false);
6290             E.on(window, 'unload', function(){
6291                 el.removeEventListener("DOMMouseScroll", h, false);
6292             });
6293         }
6294         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6295             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6296         }
6297         return h;
6298     };
6299
6300     var stopListening = function(el, ename, fn){
6301         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6302         if(hds){
6303             for(var i = 0, len = hds.length; i < len; i++){
6304                 var h = hds[i];
6305                 if(h[0] == id && h[1] == ename){
6306                     hd = h[2];
6307                     hds.splice(i, 1);
6308                     break;
6309                 }
6310             }
6311         }
6312         E.un(el, ename, hd);
6313         el = Roo.getDom(el);
6314         if(ename == "mousewheel" && el.addEventListener){
6315             el.removeEventListener("DOMMouseScroll", hd, false);
6316         }
6317         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6318             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6319         }
6320     };
6321
6322     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6323     
6324     var pub = {
6325         
6326         
6327         /** 
6328          * Fix for doc tools
6329          * @scope Roo.EventManager
6330          */
6331         
6332         
6333         /** 
6334          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6335          * object with a Roo.EventObject
6336          * @param {Function} fn        The method the event invokes
6337          * @param {Object}   scope    An object that becomes the scope of the handler
6338          * @param {boolean}  override If true, the obj passed in becomes
6339          *                             the execution scope of the listener
6340          * @return {Function} The wrapped function
6341          * @deprecated
6342          */
6343         wrap : function(fn, scope, override){
6344             return function(e){
6345                 Roo.EventObject.setEvent(e);
6346                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6347             };
6348         },
6349         
6350         /**
6351      * Appends an event handler to an element (shorthand for addListener)
6352      * @param {String/HTMLElement}   element        The html element or id to assign the
6353      * @param {String}   eventName The type of event to listen for
6354      * @param {Function} handler The method the event invokes
6355      * @param {Object}   scope (optional) The scope in which to execute the handler
6356      * function. The handler function's "this" context.
6357      * @param {Object}   options (optional) An object containing handler configuration
6358      * properties. This may contain any of the following properties:<ul>
6359      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6360      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6361      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6362      * <li>preventDefault {Boolean} True to prevent the default action</li>
6363      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6364      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6365      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6366      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6367      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6368      * by the specified number of milliseconds. If the event fires again within that time, the original
6369      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6370      * </ul><br>
6371      * <p>
6372      * <b>Combining Options</b><br>
6373      * Using the options argument, it is possible to combine different types of listeners:<br>
6374      * <br>
6375      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6376      * Code:<pre><code>
6377 el.on('click', this.onClick, this, {
6378     single: true,
6379     delay: 100,
6380     stopEvent : true,
6381     forumId: 4
6382 });</code></pre>
6383      * <p>
6384      * <b>Attaching multiple handlers in 1 call</b><br>
6385       * The method also allows for a single argument to be passed which is a config object containing properties
6386      * which specify multiple handlers.
6387      * <p>
6388      * Code:<pre><code>
6389 el.on({
6390     'click' : {
6391         fn: this.onClick
6392         scope: this,
6393         delay: 100
6394     },
6395     'mouseover' : {
6396         fn: this.onMouseOver
6397         scope: this
6398     },
6399     'mouseout' : {
6400         fn: this.onMouseOut
6401         scope: this
6402     }
6403 });</code></pre>
6404      * <p>
6405      * Or a shorthand syntax:<br>
6406      * Code:<pre><code>
6407 el.on({
6408     'click' : this.onClick,
6409     'mouseover' : this.onMouseOver,
6410     'mouseout' : this.onMouseOut
6411     scope: this
6412 });</code></pre>
6413      */
6414         addListener : function(element, eventName, fn, scope, options){
6415             if(typeof eventName == "object"){
6416                 var o = eventName;
6417                 for(var e in o){
6418                     if(propRe.test(e)){
6419                         continue;
6420                     }
6421                     if(typeof o[e] == "function"){
6422                         // shared options
6423                         listen(element, e, o, o[e], o.scope);
6424                     }else{
6425                         // individual options
6426                         listen(element, e, o[e]);
6427                     }
6428                 }
6429                 return;
6430             }
6431             return listen(element, eventName, options, fn, scope);
6432         },
6433         
6434         /**
6435          * Removes an event handler
6436          *
6437          * @param {String/HTMLElement}   element        The id or html element to remove the 
6438          *                             event from
6439          * @param {String}   eventName     The type of event
6440          * @param {Function} fn
6441          * @return {Boolean} True if a listener was actually removed
6442          */
6443         removeListener : function(element, eventName, fn){
6444             return stopListening(element, eventName, fn);
6445         },
6446         
6447         /**
6448          * Fires when the document is ready (before onload and before images are loaded). Can be 
6449          * accessed shorthanded Roo.onReady().
6450          * @param {Function} fn        The method the event invokes
6451          * @param {Object}   scope    An  object that becomes the scope of the handler
6452          * @param {boolean}  options
6453          */
6454         onDocumentReady : function(fn, scope, options){
6455             if(docReadyState){ // if it already fired
6456                 docReadyEvent.addListener(fn, scope, options);
6457                 docReadyEvent.fire();
6458                 docReadyEvent.clearListeners();
6459                 return;
6460             }
6461             if(!docReadyEvent){
6462                 initDocReady();
6463             }
6464             docReadyEvent.addListener(fn, scope, options);
6465         },
6466         
6467         /**
6468          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6469          * @param {Function} fn        The method the event invokes
6470          * @param {Object}   scope    An object that becomes the scope of the handler
6471          * @param {boolean}  options
6472          */
6473         onWindowResize : function(fn, scope, options){
6474             if(!resizeEvent){
6475                 resizeEvent = new Roo.util.Event();
6476                 resizeTask = new Roo.util.DelayedTask(function(){
6477                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6478                 });
6479                 E.on(window, "resize", function(){
6480                     if(Roo.isIE){
6481                         resizeTask.delay(50);
6482                     }else{
6483                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6484                     }
6485                 });
6486             }
6487             resizeEvent.addListener(fn, scope, options);
6488         },
6489
6490         /**
6491          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6492          * @param {Function} fn        The method the event invokes
6493          * @param {Object}   scope    An object that becomes the scope of the handler
6494          * @param {boolean}  options
6495          */
6496         onTextResize : function(fn, scope, options){
6497             if(!textEvent){
6498                 textEvent = new Roo.util.Event();
6499                 var textEl = new Roo.Element(document.createElement('div'));
6500                 textEl.dom.className = 'x-text-resize';
6501                 textEl.dom.innerHTML = 'X';
6502                 textEl.appendTo(document.body);
6503                 textSize = textEl.dom.offsetHeight;
6504                 setInterval(function(){
6505                     if(textEl.dom.offsetHeight != textSize){
6506                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6507                     }
6508                 }, this.textResizeInterval);
6509             }
6510             textEvent.addListener(fn, scope, options);
6511         },
6512
6513         /**
6514          * Removes the passed window resize listener.
6515          * @param {Function} fn        The method the event invokes
6516          * @param {Object}   scope    The scope of handler
6517          */
6518         removeResizeListener : function(fn, scope){
6519             if(resizeEvent){
6520                 resizeEvent.removeListener(fn, scope);
6521             }
6522         },
6523
6524         // private
6525         fireResize : function(){
6526             if(resizeEvent){
6527                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6528             }   
6529         },
6530         /**
6531          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6532          */
6533         ieDeferSrc : false,
6534         /**
6535          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6536          */
6537         textResizeInterval : 50
6538     };
6539     
6540     /**
6541      * Fix for doc tools
6542      * @scopeAlias pub=Roo.EventManager
6543      */
6544     
6545      /**
6546      * Appends an event handler to an element (shorthand for addListener)
6547      * @param {String/HTMLElement}   element        The html element or id to assign the
6548      * @param {String}   eventName The type of event to listen for
6549      * @param {Function} handler The method the event invokes
6550      * @param {Object}   scope (optional) The scope in which to execute the handler
6551      * function. The handler function's "this" context.
6552      * @param {Object}   options (optional) An object containing handler configuration
6553      * properties. This may contain any of the following properties:<ul>
6554      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6555      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6556      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6557      * <li>preventDefault {Boolean} True to prevent the default action</li>
6558      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6559      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6560      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6561      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6562      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6563      * by the specified number of milliseconds. If the event fires again within that time, the original
6564      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6565      * </ul><br>
6566      * <p>
6567      * <b>Combining Options</b><br>
6568      * Using the options argument, it is possible to combine different types of listeners:<br>
6569      * <br>
6570      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6571      * Code:<pre><code>
6572 el.on('click', this.onClick, this, {
6573     single: true,
6574     delay: 100,
6575     stopEvent : true,
6576     forumId: 4
6577 });</code></pre>
6578      * <p>
6579      * <b>Attaching multiple handlers in 1 call</b><br>
6580       * The method also allows for a single argument to be passed which is a config object containing properties
6581      * which specify multiple handlers.
6582      * <p>
6583      * Code:<pre><code>
6584 el.on({
6585     'click' : {
6586         fn: this.onClick
6587         scope: this,
6588         delay: 100
6589     },
6590     'mouseover' : {
6591         fn: this.onMouseOver
6592         scope: this
6593     },
6594     'mouseout' : {
6595         fn: this.onMouseOut
6596         scope: this
6597     }
6598 });</code></pre>
6599      * <p>
6600      * Or a shorthand syntax:<br>
6601      * Code:<pre><code>
6602 el.on({
6603     'click' : this.onClick,
6604     'mouseover' : this.onMouseOver,
6605     'mouseout' : this.onMouseOut
6606     scope: this
6607 });</code></pre>
6608      */
6609     pub.on = pub.addListener;
6610     pub.un = pub.removeListener;
6611
6612     pub.stoppedMouseDownEvent = new Roo.util.Event();
6613     return pub;
6614 }();
6615 /**
6616   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6617   * @param {Function} fn        The method the event invokes
6618   * @param {Object}   scope    An  object that becomes the scope of the handler
6619   * @param {boolean}  override If true, the obj passed in becomes
6620   *                             the execution scope of the listener
6621   * @member Roo
6622   * @method onReady
6623  */
6624 Roo.onReady = Roo.EventManager.onDocumentReady;
6625
6626 Roo.onReady(function(){
6627     var bd = Roo.get(document.body);
6628     if(!bd){ return; }
6629
6630     Roo.log('--------doc ready------');
6631
6632     var cls = [
6633             Roo.isIE ? "roo-ie"
6634             : Roo.isIE11 ? "roo-ie11"
6635             : Roo.isEdge ? "roo-edge"
6636             : Roo.isGecko ? "roo-gecko"
6637             : Roo.isOpera ? "roo-opera"
6638             : Roo.isSafari ? "roo-safari" : ""];
6639
6640     if(Roo.isMac){
6641         cls.push("roo-mac");
6642     }
6643     if(Roo.isLinux){
6644         cls.push("roo-linux");
6645     }
6646     if(Roo.isIOS){
6647         cls.push("roo-ios");
6648     }
6649     if(Roo.isTouch){
6650         cls.push("roo-touch");
6651     }
6652     if(Roo.isBorderBox){
6653         cls.push('roo-border-box');
6654     }
6655     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6656         var p = bd.dom.parentNode;
6657         if(p){
6658             p.className += ' roo-strict';
6659         }
6660     }
6661     bd.addClass(cls.join(' '));
6662 });
6663
6664 /**
6665  * @class Roo.EventObject
6666  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6667  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6668  * Example:
6669  * <pre><code>
6670  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6671     e.preventDefault();
6672     var target = e.getTarget();
6673     ...
6674  }
6675  var myDiv = Roo.get("myDiv");
6676  myDiv.on("click", handleClick);
6677  //or
6678  Roo.EventManager.on("myDiv", 'click', handleClick);
6679  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6680  </code></pre>
6681  * @singleton
6682  */
6683 Roo.EventObject = function(){
6684     
6685     var E = Roo.lib.Event;
6686     
6687     // safari keypress events for special keys return bad keycodes
6688     var safariKeys = {
6689         63234 : 37, // left
6690         63235 : 39, // right
6691         63232 : 38, // up
6692         63233 : 40, // down
6693         63276 : 33, // page up
6694         63277 : 34, // page down
6695         63272 : 46, // delete
6696         63273 : 36, // home
6697         63275 : 35  // end
6698     };
6699
6700     // normalize button clicks
6701     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6702                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6703
6704     Roo.EventObjectImpl = function(e){
6705         if(e){
6706             this.setEvent(e.browserEvent || e);
6707         }
6708     };
6709     Roo.EventObjectImpl.prototype = {
6710         /**
6711          * Used to fix doc tools.
6712          * @scope Roo.EventObject.prototype
6713          */
6714             
6715
6716         
6717         
6718         /** The normal browser event */
6719         browserEvent : null,
6720         /** The button pressed in a mouse event */
6721         button : -1,
6722         /** True if the shift key was down during the event */
6723         shiftKey : false,
6724         /** True if the control key was down during the event */
6725         ctrlKey : false,
6726         /** True if the alt key was down during the event */
6727         altKey : false,
6728
6729         /** Key constant 
6730         * @type Number */
6731         BACKSPACE : 8,
6732         /** Key constant 
6733         * @type Number */
6734         TAB : 9,
6735         /** Key constant 
6736         * @type Number */
6737         RETURN : 13,
6738         /** Key constant 
6739         * @type Number */
6740         ENTER : 13,
6741         /** Key constant 
6742         * @type Number */
6743         SHIFT : 16,
6744         /** Key constant 
6745         * @type Number */
6746         CONTROL : 17,
6747         /** Key constant 
6748         * @type Number */
6749         ESC : 27,
6750         /** Key constant 
6751         * @type Number */
6752         SPACE : 32,
6753         /** Key constant 
6754         * @type Number */
6755         PAGEUP : 33,
6756         /** Key constant 
6757         * @type Number */
6758         PAGEDOWN : 34,
6759         /** Key constant 
6760         * @type Number */
6761         END : 35,
6762         /** Key constant 
6763         * @type Number */
6764         HOME : 36,
6765         /** Key constant 
6766         * @type Number */
6767         LEFT : 37,
6768         /** Key constant 
6769         * @type Number */
6770         UP : 38,
6771         /** Key constant 
6772         * @type Number */
6773         RIGHT : 39,
6774         /** Key constant 
6775         * @type Number */
6776         DOWN : 40,
6777         /** Key constant 
6778         * @type Number */
6779         DELETE : 46,
6780         /** Key constant 
6781         * @type Number */
6782         F5 : 116,
6783
6784            /** @private */
6785         setEvent : function(e){
6786             if(e == this || (e && e.browserEvent)){ // already wrapped
6787                 return e;
6788             }
6789             this.browserEvent = e;
6790             if(e){
6791                 // normalize buttons
6792                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6793                 if(e.type == 'click' && this.button == -1){
6794                     this.button = 0;
6795                 }
6796                 this.type = e.type;
6797                 this.shiftKey = e.shiftKey;
6798                 // mac metaKey behaves like ctrlKey
6799                 this.ctrlKey = e.ctrlKey || e.metaKey;
6800                 this.altKey = e.altKey;
6801                 // in getKey these will be normalized for the mac
6802                 this.keyCode = e.keyCode;
6803                 // keyup warnings on firefox.
6804                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6805                 // cache the target for the delayed and or buffered events
6806                 this.target = E.getTarget(e);
6807                 // same for XY
6808                 this.xy = E.getXY(e);
6809             }else{
6810                 this.button = -1;
6811                 this.shiftKey = false;
6812                 this.ctrlKey = false;
6813                 this.altKey = false;
6814                 this.keyCode = 0;
6815                 this.charCode =0;
6816                 this.target = null;
6817                 this.xy = [0, 0];
6818             }
6819             return this;
6820         },
6821
6822         /**
6823          * Stop the event (preventDefault and stopPropagation)
6824          */
6825         stopEvent : function(){
6826             if(this.browserEvent){
6827                 if(this.browserEvent.type == 'mousedown'){
6828                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6829                 }
6830                 E.stopEvent(this.browserEvent);
6831             }
6832         },
6833
6834         /**
6835          * Prevents the browsers default handling of the event.
6836          */
6837         preventDefault : function(){
6838             if(this.browserEvent){
6839                 E.preventDefault(this.browserEvent);
6840             }
6841         },
6842
6843         /** @private */
6844         isNavKeyPress : function(){
6845             var k = this.keyCode;
6846             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6847             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6848         },
6849
6850         isSpecialKey : function(){
6851             var k = this.keyCode;
6852             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6853             (k == 16) || (k == 17) ||
6854             (k >= 18 && k <= 20) ||
6855             (k >= 33 && k <= 35) ||
6856             (k >= 36 && k <= 39) ||
6857             (k >= 44 && k <= 45);
6858         },
6859         /**
6860          * Cancels bubbling of the event.
6861          */
6862         stopPropagation : function(){
6863             if(this.browserEvent){
6864                 if(this.type == 'mousedown'){
6865                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6866                 }
6867                 E.stopPropagation(this.browserEvent);
6868             }
6869         },
6870
6871         /**
6872          * Gets the key code for the event.
6873          * @return {Number}
6874          */
6875         getCharCode : function(){
6876             return this.charCode || this.keyCode;
6877         },
6878
6879         /**
6880          * Returns a normalized keyCode for the event.
6881          * @return {Number} The key code
6882          */
6883         getKey : function(){
6884             var k = this.keyCode || this.charCode;
6885             return Roo.isSafari ? (safariKeys[k] || k) : k;
6886         },
6887
6888         /**
6889          * Gets the x coordinate of the event.
6890          * @return {Number}
6891          */
6892         getPageX : function(){
6893             return this.xy[0];
6894         },
6895
6896         /**
6897          * Gets the y coordinate of the event.
6898          * @return {Number}
6899          */
6900         getPageY : function(){
6901             return this.xy[1];
6902         },
6903
6904         /**
6905          * Gets the time of the event.
6906          * @return {Number}
6907          */
6908         getTime : function(){
6909             if(this.browserEvent){
6910                 return E.getTime(this.browserEvent);
6911             }
6912             return null;
6913         },
6914
6915         /**
6916          * Gets the page coordinates of the event.
6917          * @return {Array} The xy values like [x, y]
6918          */
6919         getXY : function(){
6920             return this.xy;
6921         },
6922
6923         /**
6924          * Gets the target for the event.
6925          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6926          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6927                 search as a number or element (defaults to 10 || document.body)
6928          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6929          * @return {HTMLelement}
6930          */
6931         getTarget : function(selector, maxDepth, returnEl){
6932             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6933         },
6934         /**
6935          * Gets the related target.
6936          * @return {HTMLElement}
6937          */
6938         getRelatedTarget : function(){
6939             if(this.browserEvent){
6940                 return E.getRelatedTarget(this.browserEvent);
6941             }
6942             return null;
6943         },
6944
6945         /**
6946          * Normalizes mouse wheel delta across browsers
6947          * @return {Number} The delta
6948          */
6949         getWheelDelta : function(){
6950             var e = this.browserEvent;
6951             var delta = 0;
6952             if(e.wheelDelta){ /* IE/Opera. */
6953                 delta = e.wheelDelta/120;
6954             }else if(e.detail){ /* Mozilla case. */
6955                 delta = -e.detail/3;
6956             }
6957             return delta;
6958         },
6959
6960         /**
6961          * Returns true if the control, meta, shift or alt key was pressed during this event.
6962          * @return {Boolean}
6963          */
6964         hasModifier : function(){
6965             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6966         },
6967
6968         /**
6969          * Returns true if the target of this event equals el or is a child of el
6970          * @param {String/HTMLElement/Element} el
6971          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6972          * @return {Boolean}
6973          */
6974         within : function(el, related){
6975             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6976             return t && Roo.fly(el).contains(t);
6977         },
6978
6979         getPoint : function(){
6980             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6981         }
6982     };
6983
6984     return new Roo.EventObjectImpl();
6985 }();
6986             
6987     /*
6988  * Based on:
6989  * Ext JS Library 1.1.1
6990  * Copyright(c) 2006-2007, Ext JS, LLC.
6991  *
6992  * Originally Released Under LGPL - original licence link has changed is not relivant.
6993  *
6994  * Fork - LGPL
6995  * <script type="text/javascript">
6996  */
6997
6998  
6999 // was in Composite Element!??!?!
7000  
7001 (function(){
7002     var D = Roo.lib.Dom;
7003     var E = Roo.lib.Event;
7004     var A = Roo.lib.Anim;
7005
7006     // local style camelizing for speed
7007     var propCache = {};
7008     var camelRe = /(-[a-z])/gi;
7009     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7010     var view = document.defaultView;
7011
7012 /**
7013  * @class Roo.Element
7014  * Represents an Element in the DOM.<br><br>
7015  * Usage:<br>
7016 <pre><code>
7017 var el = Roo.get("my-div");
7018
7019 // or with getEl
7020 var el = getEl("my-div");
7021
7022 // or with a DOM element
7023 var el = Roo.get(myDivElement);
7024 </code></pre>
7025  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7026  * each call instead of constructing a new one.<br><br>
7027  * <b>Animations</b><br />
7028  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7029  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7030 <pre>
7031 Option    Default   Description
7032 --------- --------  ---------------------------------------------
7033 duration  .35       The duration of the animation in seconds
7034 easing    easeOut   The YUI easing method
7035 callback  none      A function to execute when the anim completes
7036 scope     this      The scope (this) of the callback function
7037 </pre>
7038 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7039 * manipulate the animation. Here's an example:
7040 <pre><code>
7041 var el = Roo.get("my-div");
7042
7043 // no animation
7044 el.setWidth(100);
7045
7046 // default animation
7047 el.setWidth(100, true);
7048
7049 // animation with some options set
7050 el.setWidth(100, {
7051     duration: 1,
7052     callback: this.foo,
7053     scope: this
7054 });
7055
7056 // using the "anim" property to get the Anim object
7057 var opt = {
7058     duration: 1,
7059     callback: this.foo,
7060     scope: this
7061 };
7062 el.setWidth(100, opt);
7063 ...
7064 if(opt.anim.isAnimated()){
7065     opt.anim.stop();
7066 }
7067 </code></pre>
7068 * <b> Composite (Collections of) Elements</b><br />
7069  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7070  * @constructor Create a new Element directly.
7071  * @param {String/HTMLElement} element
7072  * @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).
7073  */
7074     Roo.Element = function(element, forceNew){
7075         var dom = typeof element == "string" ?
7076                 document.getElementById(element) : element;
7077         if(!dom){ // invalid id/element
7078             return null;
7079         }
7080         var id = dom.id;
7081         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7082             return Roo.Element.cache[id];
7083         }
7084
7085         /**
7086          * The DOM element
7087          * @type HTMLElement
7088          */
7089         this.dom = dom;
7090
7091         /**
7092          * The DOM element ID
7093          * @type String
7094          */
7095         this.id = id || Roo.id(dom);
7096     };
7097
7098     var El = Roo.Element;
7099
7100     El.prototype = {
7101         /**
7102          * The element's default display mode  (defaults to "")
7103          * @type String
7104          */
7105         originalDisplay : "",
7106
7107         visibilityMode : 1,
7108         /**
7109          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7110          * @type String
7111          */
7112         defaultUnit : "px",
7113         
7114         /**
7115          * Sets the element's visibility mode. When setVisible() is called it
7116          * will use this to determine whether to set the visibility or the display property.
7117          * @param visMode Element.VISIBILITY or Element.DISPLAY
7118          * @return {Roo.Element} this
7119          */
7120         setVisibilityMode : function(visMode){
7121             this.visibilityMode = visMode;
7122             return this;
7123         },
7124         /**
7125          * Convenience method for setVisibilityMode(Element.DISPLAY)
7126          * @param {String} display (optional) What to set display to when visible
7127          * @return {Roo.Element} this
7128          */
7129         enableDisplayMode : function(display){
7130             this.setVisibilityMode(El.DISPLAY);
7131             if(typeof display != "undefined") { this.originalDisplay = display; }
7132             return this;
7133         },
7134
7135         /**
7136          * 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)
7137          * @param {String} selector The simple selector to test
7138          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7139                 search as a number or element (defaults to 10 || document.body)
7140          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7141          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7142          */
7143         findParent : function(simpleSelector, maxDepth, returnEl){
7144             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7145             maxDepth = maxDepth || 50;
7146             if(typeof maxDepth != "number"){
7147                 stopEl = Roo.getDom(maxDepth);
7148                 maxDepth = 10;
7149             }
7150             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7151                 if(dq.is(p, simpleSelector)){
7152                     return returnEl ? Roo.get(p) : p;
7153                 }
7154                 depth++;
7155                 p = p.parentNode;
7156             }
7157             return null;
7158         },
7159
7160
7161         /**
7162          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7163          * @param {String} selector The simple selector to test
7164          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7165                 search as a number or element (defaults to 10 || document.body)
7166          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7167          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7168          */
7169         findParentNode : function(simpleSelector, maxDepth, returnEl){
7170             var p = Roo.fly(this.dom.parentNode, '_internal');
7171             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7172         },
7173         
7174         /**
7175          * Looks at  the scrollable parent element
7176          */
7177         findScrollableParent : function()
7178         {
7179             var overflowRegex = /(auto|scroll)/;
7180             
7181             if(this.getStyle('position') === 'fixed'){
7182                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7183             }
7184             
7185             var excludeStaticParent = this.getStyle('position') === "absolute";
7186             
7187             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7188                 
7189                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7190                     continue;
7191                 }
7192                 
7193                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7194                     return parent;
7195                 }
7196                 
7197                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7198                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7199                 }
7200             }
7201             
7202             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7203         },
7204
7205         /**
7206          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7207          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7208          * @param {String} selector The simple selector to test
7209          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7210                 search as a number or element (defaults to 10 || document.body)
7211          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7212          */
7213         up : function(simpleSelector, maxDepth){
7214             return this.findParentNode(simpleSelector, maxDepth, true);
7215         },
7216
7217
7218
7219         /**
7220          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7221          * @param {String} selector The simple selector to test
7222          * @return {Boolean} True if this element matches the selector, else false
7223          */
7224         is : function(simpleSelector){
7225             return Roo.DomQuery.is(this.dom, simpleSelector);
7226         },
7227
7228         /**
7229          * Perform animation on this element.
7230          * @param {Object} args The YUI animation control args
7231          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7232          * @param {Function} onComplete (optional) Function to call when animation completes
7233          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7234          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7235          * @return {Roo.Element} this
7236          */
7237         animate : function(args, duration, onComplete, easing, animType){
7238             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7239             return this;
7240         },
7241
7242         /*
7243          * @private Internal animation call
7244          */
7245         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7246             animType = animType || 'run';
7247             opt = opt || {};
7248             var anim = Roo.lib.Anim[animType](
7249                 this.dom, args,
7250                 (opt.duration || defaultDur) || .35,
7251                 (opt.easing || defaultEase) || 'easeOut',
7252                 function(){
7253                     Roo.callback(cb, this);
7254                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7255                 },
7256                 this
7257             );
7258             opt.anim = anim;
7259             return anim;
7260         },
7261
7262         // private legacy anim prep
7263         preanim : function(a, i){
7264             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7265         },
7266
7267         /**
7268          * Removes worthless text nodes
7269          * @param {Boolean} forceReclean (optional) By default the element
7270          * keeps track if it has been cleaned already so
7271          * you can call this over and over. However, if you update the element and
7272          * need to force a reclean, you can pass true.
7273          */
7274         clean : function(forceReclean){
7275             if(this.isCleaned && forceReclean !== true){
7276                 return this;
7277             }
7278             var ns = /\S/;
7279             var d = this.dom, n = d.firstChild, ni = -1;
7280             while(n){
7281                 var nx = n.nextSibling;
7282                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7283                     d.removeChild(n);
7284                 }else{
7285                     n.nodeIndex = ++ni;
7286                 }
7287                 n = nx;
7288             }
7289             this.isCleaned = true;
7290             return this;
7291         },
7292
7293         // private
7294         calcOffsetsTo : function(el){
7295             el = Roo.get(el);
7296             var d = el.dom;
7297             var restorePos = false;
7298             if(el.getStyle('position') == 'static'){
7299                 el.position('relative');
7300                 restorePos = true;
7301             }
7302             var x = 0, y =0;
7303             var op = this.dom;
7304             while(op && op != d && op.tagName != 'HTML'){
7305                 x+= op.offsetLeft;
7306                 y+= op.offsetTop;
7307                 op = op.offsetParent;
7308             }
7309             if(restorePos){
7310                 el.position('static');
7311             }
7312             return [x, y];
7313         },
7314
7315         /**
7316          * Scrolls this element into view within the passed container.
7317          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7318          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7319          * @return {Roo.Element} this
7320          */
7321         scrollIntoView : function(container, hscroll){
7322             var c = Roo.getDom(container) || document.body;
7323             var el = this.dom;
7324
7325             var o = this.calcOffsetsTo(c),
7326                 l = o[0],
7327                 t = o[1],
7328                 b = t+el.offsetHeight,
7329                 r = l+el.offsetWidth;
7330
7331             var ch = c.clientHeight;
7332             var ct = parseInt(c.scrollTop, 10);
7333             var cl = parseInt(c.scrollLeft, 10);
7334             var cb = ct + ch;
7335             var cr = cl + c.clientWidth;
7336
7337             if(t < ct){
7338                 c.scrollTop = t;
7339             }else if(b > cb){
7340                 c.scrollTop = b-ch;
7341             }
7342
7343             if(hscroll !== false){
7344                 if(l < cl){
7345                     c.scrollLeft = l;
7346                 }else if(r > cr){
7347                     c.scrollLeft = r-c.clientWidth;
7348                 }
7349             }
7350             return this;
7351         },
7352
7353         // private
7354         scrollChildIntoView : function(child, hscroll){
7355             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7356         },
7357
7358         /**
7359          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7360          * the new height may not be available immediately.
7361          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7362          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7363          * @param {Function} onComplete (optional) Function to call when animation completes
7364          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7365          * @return {Roo.Element} this
7366          */
7367         autoHeight : function(animate, duration, onComplete, easing){
7368             var oldHeight = this.getHeight();
7369             this.clip();
7370             this.setHeight(1); // force clipping
7371             setTimeout(function(){
7372                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7373                 if(!animate){
7374                     this.setHeight(height);
7375                     this.unclip();
7376                     if(typeof onComplete == "function"){
7377                         onComplete();
7378                     }
7379                 }else{
7380                     this.setHeight(oldHeight); // restore original height
7381                     this.setHeight(height, animate, duration, function(){
7382                         this.unclip();
7383                         if(typeof onComplete == "function") { onComplete(); }
7384                     }.createDelegate(this), easing);
7385                 }
7386             }.createDelegate(this), 0);
7387             return this;
7388         },
7389
7390         /**
7391          * Returns true if this element is an ancestor of the passed element
7392          * @param {HTMLElement/String} el The element to check
7393          * @return {Boolean} True if this element is an ancestor of el, else false
7394          */
7395         contains : function(el){
7396             if(!el){return false;}
7397             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7398         },
7399
7400         /**
7401          * Checks whether the element is currently visible using both visibility and display properties.
7402          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7403          * @return {Boolean} True if the element is currently visible, else false
7404          */
7405         isVisible : function(deep) {
7406             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7407             if(deep !== true || !vis){
7408                 return vis;
7409             }
7410             var p = this.dom.parentNode;
7411             while(p && p.tagName.toLowerCase() != "body"){
7412                 if(!Roo.fly(p, '_isVisible').isVisible()){
7413                     return false;
7414                 }
7415                 p = p.parentNode;
7416             }
7417             return true;
7418         },
7419
7420         /**
7421          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7422          * @param {String} selector The CSS selector
7423          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7424          * @return {CompositeElement/CompositeElementLite} The composite element
7425          */
7426         select : function(selector, unique){
7427             return El.select(selector, unique, this.dom);
7428         },
7429
7430         /**
7431          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7432          * @param {String} selector The CSS selector
7433          * @return {Array} An array of the matched nodes
7434          */
7435         query : function(selector, unique){
7436             return Roo.DomQuery.select(selector, this.dom);
7437         },
7438
7439         /**
7440          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7441          * @param {String} selector The CSS selector
7442          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7443          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7444          */
7445         child : function(selector, returnDom){
7446             var n = Roo.DomQuery.selectNode(selector, this.dom);
7447             return returnDom ? n : Roo.get(n);
7448         },
7449
7450         /**
7451          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7452          * @param {String} selector The CSS selector
7453          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7454          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7455          */
7456         down : function(selector, returnDom){
7457             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7458             return returnDom ? n : Roo.get(n);
7459         },
7460
7461         /**
7462          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7463          * @param {String} group The group the DD object is member of
7464          * @param {Object} config The DD config object
7465          * @param {Object} overrides An object containing methods to override/implement on the DD object
7466          * @return {Roo.dd.DD} The DD object
7467          */
7468         initDD : function(group, config, overrides){
7469             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7470             return Roo.apply(dd, overrides);
7471         },
7472
7473         /**
7474          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7475          * @param {String} group The group the DDProxy object is member of
7476          * @param {Object} config The DDProxy config object
7477          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7478          * @return {Roo.dd.DDProxy} The DDProxy object
7479          */
7480         initDDProxy : function(group, config, overrides){
7481             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7482             return Roo.apply(dd, overrides);
7483         },
7484
7485         /**
7486          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7487          * @param {String} group The group the DDTarget object is member of
7488          * @param {Object} config The DDTarget config object
7489          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7490          * @return {Roo.dd.DDTarget} The DDTarget object
7491          */
7492         initDDTarget : function(group, config, overrides){
7493             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7494             return Roo.apply(dd, overrides);
7495         },
7496
7497         /**
7498          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7499          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7500          * @param {Boolean} visible Whether the element is visible
7501          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7502          * @return {Roo.Element} this
7503          */
7504          setVisible : function(visible, animate){
7505             if(!animate || !A){
7506                 if(this.visibilityMode == El.DISPLAY){
7507                     this.setDisplayed(visible);
7508                 }else{
7509                     this.fixDisplay();
7510                     this.dom.style.visibility = visible ? "visible" : "hidden";
7511                 }
7512             }else{
7513                 // closure for composites
7514                 var dom = this.dom;
7515                 var visMode = this.visibilityMode;
7516                 if(visible){
7517                     this.setOpacity(.01);
7518                     this.setVisible(true);
7519                 }
7520                 this.anim({opacity: { to: (visible?1:0) }},
7521                       this.preanim(arguments, 1),
7522                       null, .35, 'easeIn', function(){
7523                          if(!visible){
7524                              if(visMode == El.DISPLAY){
7525                                  dom.style.display = "none";
7526                              }else{
7527                                  dom.style.visibility = "hidden";
7528                              }
7529                              Roo.get(dom).setOpacity(1);
7530                          }
7531                      });
7532             }
7533             return this;
7534         },
7535
7536         /**
7537          * Returns true if display is not "none"
7538          * @return {Boolean}
7539          */
7540         isDisplayed : function() {
7541             return this.getStyle("display") != "none";
7542         },
7543
7544         /**
7545          * Toggles the element's visibility or display, depending on visibility mode.
7546          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7547          * @return {Roo.Element} this
7548          */
7549         toggle : function(animate){
7550             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7551             return this;
7552         },
7553
7554         /**
7555          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7556          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7557          * @return {Roo.Element} this
7558          */
7559         setDisplayed : function(value) {
7560             if(typeof value == "boolean"){
7561                value = value ? this.originalDisplay : "none";
7562             }
7563             this.setStyle("display", value);
7564             return this;
7565         },
7566
7567         /**
7568          * Tries to focus the element. Any exceptions are caught and ignored.
7569          * @return {Roo.Element} this
7570          */
7571         focus : function() {
7572             try{
7573                 this.dom.focus();
7574             }catch(e){}
7575             return this;
7576         },
7577
7578         /**
7579          * Tries to blur the element. Any exceptions are caught and ignored.
7580          * @return {Roo.Element} this
7581          */
7582         blur : function() {
7583             try{
7584                 this.dom.blur();
7585             }catch(e){}
7586             return this;
7587         },
7588
7589         /**
7590          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7591          * @param {String/Array} className The CSS class to add, or an array of classes
7592          * @return {Roo.Element} this
7593          */
7594         addClass : function(className){
7595             if(className instanceof Array){
7596                 for(var i = 0, len = className.length; i < len; i++) {
7597                     this.addClass(className[i]);
7598                 }
7599             }else{
7600                 if(className && !this.hasClass(className)){
7601                     this.dom.className = this.dom.className + " " + className;
7602                 }
7603             }
7604             return this;
7605         },
7606
7607         /**
7608          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7609          * @param {String/Array} className The CSS class to add, or an array of classes
7610          * @return {Roo.Element} this
7611          */
7612         radioClass : function(className){
7613             var siblings = this.dom.parentNode.childNodes;
7614             for(var i = 0; i < siblings.length; i++) {
7615                 var s = siblings[i];
7616                 if(s.nodeType == 1){
7617                     Roo.get(s).removeClass(className);
7618                 }
7619             }
7620             this.addClass(className);
7621             return this;
7622         },
7623
7624         /**
7625          * Removes one or more CSS classes from the element.
7626          * @param {String/Array} className The CSS class to remove, or an array of classes
7627          * @return {Roo.Element} this
7628          */
7629         removeClass : function(className){
7630             if(!className || !this.dom.className){
7631                 return this;
7632             }
7633             if(className instanceof Array){
7634                 for(var i = 0, len = className.length; i < len; i++) {
7635                     this.removeClass(className[i]);
7636                 }
7637             }else{
7638                 if(this.hasClass(className)){
7639                     var re = this.classReCache[className];
7640                     if (!re) {
7641                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7642                        this.classReCache[className] = re;
7643                     }
7644                     this.dom.className =
7645                         this.dom.className.replace(re, " ");
7646                 }
7647             }
7648             return this;
7649         },
7650
7651         // private
7652         classReCache: {},
7653
7654         /**
7655          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7656          * @param {String} className The CSS class to toggle
7657          * @return {Roo.Element} this
7658          */
7659         toggleClass : function(className){
7660             if(this.hasClass(className)){
7661                 this.removeClass(className);
7662             }else{
7663                 this.addClass(className);
7664             }
7665             return this;
7666         },
7667
7668         /**
7669          * Checks if the specified CSS class exists on this element's DOM node.
7670          * @param {String} className The CSS class to check for
7671          * @return {Boolean} True if the class exists, else false
7672          */
7673         hasClass : function(className){
7674             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7675         },
7676
7677         /**
7678          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7679          * @param {String} oldClassName The CSS class to replace
7680          * @param {String} newClassName The replacement CSS class
7681          * @return {Roo.Element} this
7682          */
7683         replaceClass : function(oldClassName, newClassName){
7684             this.removeClass(oldClassName);
7685             this.addClass(newClassName);
7686             return this;
7687         },
7688
7689         /**
7690          * Returns an object with properties matching the styles requested.
7691          * For example, el.getStyles('color', 'font-size', 'width') might return
7692          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7693          * @param {String} style1 A style name
7694          * @param {String} style2 A style name
7695          * @param {String} etc.
7696          * @return {Object} The style object
7697          */
7698         getStyles : function(){
7699             var a = arguments, len = a.length, r = {};
7700             for(var i = 0; i < len; i++){
7701                 r[a[i]] = this.getStyle(a[i]);
7702             }
7703             return r;
7704         },
7705
7706         /**
7707          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7708          * @param {String} property The style property whose value is returned.
7709          * @return {String} The current value of the style property for this element.
7710          */
7711         getStyle : function(){
7712             return view && view.getComputedStyle ?
7713                 function(prop){
7714                     var el = this.dom, v, cs, camel;
7715                     if(prop == 'float'){
7716                         prop = "cssFloat";
7717                     }
7718                     if(el.style && (v = el.style[prop])){
7719                         return v;
7720                     }
7721                     if(cs = view.getComputedStyle(el, "")){
7722                         if(!(camel = propCache[prop])){
7723                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7724                         }
7725                         return cs[camel];
7726                     }
7727                     return null;
7728                 } :
7729                 function(prop){
7730                     var el = this.dom, v, cs, camel;
7731                     if(prop == 'opacity'){
7732                         if(typeof el.style.filter == 'string'){
7733                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7734                             if(m){
7735                                 var fv = parseFloat(m[1]);
7736                                 if(!isNaN(fv)){
7737                                     return fv ? fv / 100 : 0;
7738                                 }
7739                             }
7740                         }
7741                         return 1;
7742                     }else if(prop == 'float'){
7743                         prop = "styleFloat";
7744                     }
7745                     if(!(camel = propCache[prop])){
7746                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7747                     }
7748                     if(v = el.style[camel]){
7749                         return v;
7750                     }
7751                     if(cs = el.currentStyle){
7752                         return cs[camel];
7753                     }
7754                     return null;
7755                 };
7756         }(),
7757
7758         /**
7759          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7760          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7761          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7762          * @return {Roo.Element} this
7763          */
7764         setStyle : function(prop, value){
7765             if(typeof prop == "string"){
7766                 
7767                 if (prop == 'float') {
7768                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7769                     return this;
7770                 }
7771                 
7772                 var camel;
7773                 if(!(camel = propCache[prop])){
7774                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7775                 }
7776                 
7777                 if(camel == 'opacity') {
7778                     this.setOpacity(value);
7779                 }else{
7780                     this.dom.style[camel] = value;
7781                 }
7782             }else{
7783                 for(var style in prop){
7784                     if(typeof prop[style] != "function"){
7785                        this.setStyle(style, prop[style]);
7786                     }
7787                 }
7788             }
7789             return this;
7790         },
7791
7792         /**
7793          * More flexible version of {@link #setStyle} for setting style properties.
7794          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7795          * a function which returns such a specification.
7796          * @return {Roo.Element} this
7797          */
7798         applyStyles : function(style){
7799             Roo.DomHelper.applyStyles(this.dom, style);
7800             return this;
7801         },
7802
7803         /**
7804           * 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).
7805           * @return {Number} The X position of the element
7806           */
7807         getX : function(){
7808             return D.getX(this.dom);
7809         },
7810
7811         /**
7812           * 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).
7813           * @return {Number} The Y position of the element
7814           */
7815         getY : function(){
7816             return D.getY(this.dom);
7817         },
7818
7819         /**
7820           * 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).
7821           * @return {Array} The XY position of the element
7822           */
7823         getXY : function(){
7824             return D.getXY(this.dom);
7825         },
7826
7827         /**
7828          * 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).
7829          * @param {Number} The X position of the element
7830          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7831          * @return {Roo.Element} this
7832          */
7833         setX : function(x, animate){
7834             if(!animate || !A){
7835                 D.setX(this.dom, x);
7836             }else{
7837                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7838             }
7839             return this;
7840         },
7841
7842         /**
7843          * 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).
7844          * @param {Number} The Y position of the element
7845          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7846          * @return {Roo.Element} this
7847          */
7848         setY : function(y, animate){
7849             if(!animate || !A){
7850                 D.setY(this.dom, y);
7851             }else{
7852                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7853             }
7854             return this;
7855         },
7856
7857         /**
7858          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7859          * @param {String} left The left CSS property value
7860          * @return {Roo.Element} this
7861          */
7862         setLeft : function(left){
7863             this.setStyle("left", this.addUnits(left));
7864             return this;
7865         },
7866
7867         /**
7868          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7869          * @param {String} top The top CSS property value
7870          * @return {Roo.Element} this
7871          */
7872         setTop : function(top){
7873             this.setStyle("top", this.addUnits(top));
7874             return this;
7875         },
7876
7877         /**
7878          * Sets the element's CSS right style.
7879          * @param {String} right The right CSS property value
7880          * @return {Roo.Element} this
7881          */
7882         setRight : function(right){
7883             this.setStyle("right", this.addUnits(right));
7884             return this;
7885         },
7886
7887         /**
7888          * Sets the element's CSS bottom style.
7889          * @param {String} bottom The bottom CSS property value
7890          * @return {Roo.Element} this
7891          */
7892         setBottom : function(bottom){
7893             this.setStyle("bottom", this.addUnits(bottom));
7894             return this;
7895         },
7896
7897         /**
7898          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7899          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7900          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7901          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7902          * @return {Roo.Element} this
7903          */
7904         setXY : function(pos, animate){
7905             if(!animate || !A){
7906                 D.setXY(this.dom, pos);
7907             }else{
7908                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7909             }
7910             return this;
7911         },
7912
7913         /**
7914          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7915          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7916          * @param {Number} x X value for new position (coordinates are page-based)
7917          * @param {Number} y Y value for new position (coordinates are page-based)
7918          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7919          * @return {Roo.Element} this
7920          */
7921         setLocation : function(x, y, animate){
7922             this.setXY([x, y], this.preanim(arguments, 2));
7923             return this;
7924         },
7925
7926         /**
7927          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7928          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7929          * @param {Number} x X value for new position (coordinates are page-based)
7930          * @param {Number} y Y value for new position (coordinates are page-based)
7931          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7932          * @return {Roo.Element} this
7933          */
7934         moveTo : function(x, y, animate){
7935             this.setXY([x, y], this.preanim(arguments, 2));
7936             return this;
7937         },
7938
7939         /**
7940          * Returns the region of the given element.
7941          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7942          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7943          */
7944         getRegion : function(){
7945             return D.getRegion(this.dom);
7946         },
7947
7948         /**
7949          * Returns the offset height of the element
7950          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7951          * @return {Number} The element's height
7952          */
7953         getHeight : function(contentHeight){
7954             var h = this.dom.offsetHeight || 0;
7955             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7956         },
7957
7958         /**
7959          * Returns the offset width of the element
7960          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7961          * @return {Number} The element's width
7962          */
7963         getWidth : function(contentWidth){
7964             var w = this.dom.offsetWidth || 0;
7965             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7966         },
7967
7968         /**
7969          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7970          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7971          * if a height has not been set using CSS.
7972          * @return {Number}
7973          */
7974         getComputedHeight : function(){
7975             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7976             if(!h){
7977                 h = parseInt(this.getStyle('height'), 10) || 0;
7978                 if(!this.isBorderBox()){
7979                     h += this.getFrameWidth('tb');
7980                 }
7981             }
7982             return h;
7983         },
7984
7985         /**
7986          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7987          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7988          * if a width has not been set using CSS.
7989          * @return {Number}
7990          */
7991         getComputedWidth : function(){
7992             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7993             if(!w){
7994                 w = parseInt(this.getStyle('width'), 10) || 0;
7995                 if(!this.isBorderBox()){
7996                     w += this.getFrameWidth('lr');
7997                 }
7998             }
7999             return w;
8000         },
8001
8002         /**
8003          * Returns the size of the element.
8004          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8005          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8006          */
8007         getSize : function(contentSize){
8008             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8009         },
8010
8011         /**
8012          * Returns the width and height of the viewport.
8013          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8014          */
8015         getViewSize : function(){
8016             var d = this.dom, doc = document, aw = 0, ah = 0;
8017             if(d == doc || d == doc.body){
8018                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8019             }else{
8020                 return {
8021                     width : d.clientWidth,
8022                     height: d.clientHeight
8023                 };
8024             }
8025         },
8026
8027         /**
8028          * Returns the value of the "value" attribute
8029          * @param {Boolean} asNumber true to parse the value as a number
8030          * @return {String/Number}
8031          */
8032         getValue : function(asNumber){
8033             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8034         },
8035
8036         // private
8037         adjustWidth : function(width){
8038             if(typeof width == "number"){
8039                 if(this.autoBoxAdjust && !this.isBorderBox()){
8040                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8041                 }
8042                 if(width < 0){
8043                     width = 0;
8044                 }
8045             }
8046             return width;
8047         },
8048
8049         // private
8050         adjustHeight : function(height){
8051             if(typeof height == "number"){
8052                if(this.autoBoxAdjust && !this.isBorderBox()){
8053                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8054                }
8055                if(height < 0){
8056                    height = 0;
8057                }
8058             }
8059             return height;
8060         },
8061
8062         /**
8063          * Set the width of the element
8064          * @param {Number} width The new width
8065          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8066          * @return {Roo.Element} this
8067          */
8068         setWidth : function(width, animate){
8069             width = this.adjustWidth(width);
8070             if(!animate || !A){
8071                 this.dom.style.width = this.addUnits(width);
8072             }else{
8073                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8074             }
8075             return this;
8076         },
8077
8078         /**
8079          * Set the height of the element
8080          * @param {Number} height The new height
8081          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8082          * @return {Roo.Element} this
8083          */
8084          setHeight : function(height, animate){
8085             height = this.adjustHeight(height);
8086             if(!animate || !A){
8087                 this.dom.style.height = this.addUnits(height);
8088             }else{
8089                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8090             }
8091             return this;
8092         },
8093
8094         /**
8095          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8096          * @param {Number} width The new width
8097          * @param {Number} height The new height
8098          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8099          * @return {Roo.Element} this
8100          */
8101          setSize : function(width, height, animate){
8102             if(typeof width == "object"){ // in case of object from getSize()
8103                 height = width.height; width = width.width;
8104             }
8105             width = this.adjustWidth(width); height = this.adjustHeight(height);
8106             if(!animate || !A){
8107                 this.dom.style.width = this.addUnits(width);
8108                 this.dom.style.height = this.addUnits(height);
8109             }else{
8110                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8111             }
8112             return this;
8113         },
8114
8115         /**
8116          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8117          * @param {Number} x X value for new position (coordinates are page-based)
8118          * @param {Number} y Y value for new position (coordinates are page-based)
8119          * @param {Number} width The new width
8120          * @param {Number} height The new height
8121          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8122          * @return {Roo.Element} this
8123          */
8124         setBounds : function(x, y, width, height, animate){
8125             if(!animate || !A){
8126                 this.setSize(width, height);
8127                 this.setLocation(x, y);
8128             }else{
8129                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8130                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8131                               this.preanim(arguments, 4), 'motion');
8132             }
8133             return this;
8134         },
8135
8136         /**
8137          * 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.
8138          * @param {Roo.lib.Region} region The region to fill
8139          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8140          * @return {Roo.Element} this
8141          */
8142         setRegion : function(region, animate){
8143             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8144             return this;
8145         },
8146
8147         /**
8148          * Appends an event handler
8149          *
8150          * @param {String}   eventName     The type of event to append
8151          * @param {Function} fn        The method the event invokes
8152          * @param {Object} scope       (optional) The scope (this object) of the fn
8153          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8154          */
8155         addListener : function(eventName, fn, scope, options){
8156             if (this.dom) {
8157                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8158             }
8159         },
8160
8161         /**
8162          * Removes an event handler from this element
8163          * @param {String} eventName the type of event to remove
8164          * @param {Function} fn the method the event invokes
8165          * @return {Roo.Element} this
8166          */
8167         removeListener : function(eventName, fn){
8168             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8169             return this;
8170         },
8171
8172         /**
8173          * Removes all previous added listeners from this element
8174          * @return {Roo.Element} this
8175          */
8176         removeAllListeners : function(){
8177             E.purgeElement(this.dom);
8178             return this;
8179         },
8180
8181         relayEvent : function(eventName, observable){
8182             this.on(eventName, function(e){
8183                 observable.fireEvent(eventName, e);
8184             });
8185         },
8186
8187         /**
8188          * Set the opacity of the element
8189          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8190          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8191          * @return {Roo.Element} this
8192          */
8193          setOpacity : function(opacity, animate){
8194             if(!animate || !A){
8195                 var s = this.dom.style;
8196                 if(Roo.isIE){
8197                     s.zoom = 1;
8198                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8199                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8200                 }else{
8201                     s.opacity = opacity;
8202                 }
8203             }else{
8204                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8205             }
8206             return this;
8207         },
8208
8209         /**
8210          * Gets the left X coordinate
8211          * @param {Boolean} local True to get the local css position instead of page coordinate
8212          * @return {Number}
8213          */
8214         getLeft : function(local){
8215             if(!local){
8216                 return this.getX();
8217             }else{
8218                 return parseInt(this.getStyle("left"), 10) || 0;
8219             }
8220         },
8221
8222         /**
8223          * Gets the right X coordinate of the element (element X position + element width)
8224          * @param {Boolean} local True to get the local css position instead of page coordinate
8225          * @return {Number}
8226          */
8227         getRight : function(local){
8228             if(!local){
8229                 return this.getX() + this.getWidth();
8230             }else{
8231                 return (this.getLeft(true) + this.getWidth()) || 0;
8232             }
8233         },
8234
8235         /**
8236          * Gets the top Y coordinate
8237          * @param {Boolean} local True to get the local css position instead of page coordinate
8238          * @return {Number}
8239          */
8240         getTop : function(local) {
8241             if(!local){
8242                 return this.getY();
8243             }else{
8244                 return parseInt(this.getStyle("top"), 10) || 0;
8245             }
8246         },
8247
8248         /**
8249          * Gets the bottom Y coordinate of the element (element Y position + element height)
8250          * @param {Boolean} local True to get the local css position instead of page coordinate
8251          * @return {Number}
8252          */
8253         getBottom : function(local){
8254             if(!local){
8255                 return this.getY() + this.getHeight();
8256             }else{
8257                 return (this.getTop(true) + this.getHeight()) || 0;
8258             }
8259         },
8260
8261         /**
8262         * Initializes positioning on this element. If a desired position is not passed, it will make the
8263         * the element positioned relative IF it is not already positioned.
8264         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8265         * @param {Number} zIndex (optional) The zIndex to apply
8266         * @param {Number} x (optional) Set the page X position
8267         * @param {Number} y (optional) Set the page Y position
8268         */
8269         position : function(pos, zIndex, x, y){
8270             if(!pos){
8271                if(this.getStyle('position') == 'static'){
8272                    this.setStyle('position', 'relative');
8273                }
8274             }else{
8275                 this.setStyle("position", pos);
8276             }
8277             if(zIndex){
8278                 this.setStyle("z-index", zIndex);
8279             }
8280             if(x !== undefined && y !== undefined){
8281                 this.setXY([x, y]);
8282             }else if(x !== undefined){
8283                 this.setX(x);
8284             }else if(y !== undefined){
8285                 this.setY(y);
8286             }
8287         },
8288
8289         /**
8290         * Clear positioning back to the default when the document was loaded
8291         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8292         * @return {Roo.Element} this
8293          */
8294         clearPositioning : function(value){
8295             value = value ||'';
8296             this.setStyle({
8297                 "left": value,
8298                 "right": value,
8299                 "top": value,
8300                 "bottom": value,
8301                 "z-index": "",
8302                 "position" : "static"
8303             });
8304             return this;
8305         },
8306
8307         /**
8308         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8309         * snapshot before performing an update and then restoring the element.
8310         * @return {Object}
8311         */
8312         getPositioning : function(){
8313             var l = this.getStyle("left");
8314             var t = this.getStyle("top");
8315             return {
8316                 "position" : this.getStyle("position"),
8317                 "left" : l,
8318                 "right" : l ? "" : this.getStyle("right"),
8319                 "top" : t,
8320                 "bottom" : t ? "" : this.getStyle("bottom"),
8321                 "z-index" : this.getStyle("z-index")
8322             };
8323         },
8324
8325         /**
8326          * Gets the width of the border(s) for the specified side(s)
8327          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8328          * passing lr would get the border (l)eft width + the border (r)ight width.
8329          * @return {Number} The width of the sides passed added together
8330          */
8331         getBorderWidth : function(side){
8332             return this.addStyles(side, El.borders);
8333         },
8334
8335         /**
8336          * Gets the width of the padding(s) for the specified side(s)
8337          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8338          * passing lr would get the padding (l)eft + the padding (r)ight.
8339          * @return {Number} The padding of the sides passed added together
8340          */
8341         getPadding : function(side){
8342             return this.addStyles(side, El.paddings);
8343         },
8344
8345         /**
8346         * Set positioning with an object returned by getPositioning().
8347         * @param {Object} posCfg
8348         * @return {Roo.Element} this
8349          */
8350         setPositioning : function(pc){
8351             this.applyStyles(pc);
8352             if(pc.right == "auto"){
8353                 this.dom.style.right = "";
8354             }
8355             if(pc.bottom == "auto"){
8356                 this.dom.style.bottom = "";
8357             }
8358             return this;
8359         },
8360
8361         // private
8362         fixDisplay : function(){
8363             if(this.getStyle("display") == "none"){
8364                 this.setStyle("visibility", "hidden");
8365                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8366                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8367                     this.setStyle("display", "block");
8368                 }
8369             }
8370         },
8371
8372         /**
8373          * Quick set left and top adding default units
8374          * @param {String} left The left CSS property value
8375          * @param {String} top The top CSS property value
8376          * @return {Roo.Element} this
8377          */
8378          setLeftTop : function(left, top){
8379             this.dom.style.left = this.addUnits(left);
8380             this.dom.style.top = this.addUnits(top);
8381             return this;
8382         },
8383
8384         /**
8385          * Move this element relative to its current position.
8386          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8387          * @param {Number} distance How far to move the element in pixels
8388          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8389          * @return {Roo.Element} this
8390          */
8391          move : function(direction, distance, animate){
8392             var xy = this.getXY();
8393             direction = direction.toLowerCase();
8394             switch(direction){
8395                 case "l":
8396                 case "left":
8397                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8398                     break;
8399                case "r":
8400                case "right":
8401                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8402                     break;
8403                case "t":
8404                case "top":
8405                case "up":
8406                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8407                     break;
8408                case "b":
8409                case "bottom":
8410                case "down":
8411                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8412                     break;
8413             }
8414             return this;
8415         },
8416
8417         /**
8418          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8419          * @return {Roo.Element} this
8420          */
8421         clip : function(){
8422             if(!this.isClipped){
8423                this.isClipped = true;
8424                this.originalClip = {
8425                    "o": this.getStyle("overflow"),
8426                    "x": this.getStyle("overflow-x"),
8427                    "y": this.getStyle("overflow-y")
8428                };
8429                this.setStyle("overflow", "hidden");
8430                this.setStyle("overflow-x", "hidden");
8431                this.setStyle("overflow-y", "hidden");
8432             }
8433             return this;
8434         },
8435
8436         /**
8437          *  Return clipping (overflow) to original clipping before clip() was called
8438          * @return {Roo.Element} this
8439          */
8440         unclip : function(){
8441             if(this.isClipped){
8442                 this.isClipped = false;
8443                 var o = this.originalClip;
8444                 if(o.o){this.setStyle("overflow", o.o);}
8445                 if(o.x){this.setStyle("overflow-x", o.x);}
8446                 if(o.y){this.setStyle("overflow-y", o.y);}
8447             }
8448             return this;
8449         },
8450
8451
8452         /**
8453          * Gets the x,y coordinates specified by the anchor position on the element.
8454          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8455          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8456          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8457          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8458          * @return {Array} [x, y] An array containing the element's x and y coordinates
8459          */
8460         getAnchorXY : function(anchor, local, s){
8461             //Passing a different size is useful for pre-calculating anchors,
8462             //especially for anchored animations that change the el size.
8463
8464             var w, h, vp = false;
8465             if(!s){
8466                 var d = this.dom;
8467                 if(d == document.body || d == document){
8468                     vp = true;
8469                     w = D.getViewWidth(); h = D.getViewHeight();
8470                 }else{
8471                     w = this.getWidth(); h = this.getHeight();
8472                 }
8473             }else{
8474                 w = s.width;  h = s.height;
8475             }
8476             var x = 0, y = 0, r = Math.round;
8477             switch((anchor || "tl").toLowerCase()){
8478                 case "c":
8479                     x = r(w*.5);
8480                     y = r(h*.5);
8481                 break;
8482                 case "t":
8483                     x = r(w*.5);
8484                     y = 0;
8485                 break;
8486                 case "l":
8487                     x = 0;
8488                     y = r(h*.5);
8489                 break;
8490                 case "r":
8491                     x = w;
8492                     y = r(h*.5);
8493                 break;
8494                 case "b":
8495                     x = r(w*.5);
8496                     y = h;
8497                 break;
8498                 case "tl":
8499                     x = 0;
8500                     y = 0;
8501                 break;
8502                 case "bl":
8503                     x = 0;
8504                     y = h;
8505                 break;
8506                 case "br":
8507                     x = w;
8508                     y = h;
8509                 break;
8510                 case "tr":
8511                     x = w;
8512                     y = 0;
8513                 break;
8514             }
8515             if(local === true){
8516                 return [x, y];
8517             }
8518             if(vp){
8519                 var sc = this.getScroll();
8520                 return [x + sc.left, y + sc.top];
8521             }
8522             //Add the element's offset xy
8523             var o = this.getXY();
8524             return [x+o[0], y+o[1]];
8525         },
8526
8527         /**
8528          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8529          * supported position values.
8530          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8531          * @param {String} position The position to align to.
8532          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8533          * @return {Array} [x, y]
8534          */
8535         getAlignToXY : function(el, p, o){
8536             el = Roo.get(el);
8537             var d = this.dom;
8538             if(!el.dom){
8539                 throw "Element.alignTo with an element that doesn't exist";
8540             }
8541             var c = false; //constrain to viewport
8542             var p1 = "", p2 = "";
8543             o = o || [0,0];
8544
8545             if(!p){
8546                 p = "tl-bl";
8547             }else if(p == "?"){
8548                 p = "tl-bl?";
8549             }else if(p.indexOf("-") == -1){
8550                 p = "tl-" + p;
8551             }
8552             p = p.toLowerCase();
8553             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8554             if(!m){
8555                throw "Element.alignTo with an invalid alignment " + p;
8556             }
8557             p1 = m[1]; p2 = m[2]; c = !!m[3];
8558
8559             //Subtract the aligned el's internal xy from the target's offset xy
8560             //plus custom offset to get the aligned el's new offset xy
8561             var a1 = this.getAnchorXY(p1, true);
8562             var a2 = el.getAnchorXY(p2, false);
8563             var x = a2[0] - a1[0] + o[0];
8564             var y = a2[1] - a1[1] + o[1];
8565             if(c){
8566                 //constrain the aligned el to viewport if necessary
8567                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8568                 // 5px of margin for ie
8569                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8570
8571                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8572                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8573                 //otherwise swap the aligned el to the opposite border of the target.
8574                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8575                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8576                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8577                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8578
8579                var doc = document;
8580                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8581                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8582
8583                if((x+w) > dw + scrollX){
8584                     x = swapX ? r.left-w : dw+scrollX-w;
8585                 }
8586                if(x < scrollX){
8587                    x = swapX ? r.right : scrollX;
8588                }
8589                if((y+h) > dh + scrollY){
8590                     y = swapY ? r.top-h : dh+scrollY-h;
8591                 }
8592                if (y < scrollY){
8593                    y = swapY ? r.bottom : scrollY;
8594                }
8595             }
8596             return [x,y];
8597         },
8598
8599         // private
8600         getConstrainToXY : function(){
8601             var os = {top:0, left:0, bottom:0, right: 0};
8602
8603             return function(el, local, offsets, proposedXY){
8604                 el = Roo.get(el);
8605                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8606
8607                 var vw, vh, vx = 0, vy = 0;
8608                 if(el.dom == document.body || el.dom == document){
8609                     vw = Roo.lib.Dom.getViewWidth();
8610                     vh = Roo.lib.Dom.getViewHeight();
8611                 }else{
8612                     vw = el.dom.clientWidth;
8613                     vh = el.dom.clientHeight;
8614                     if(!local){
8615                         var vxy = el.getXY();
8616                         vx = vxy[0];
8617                         vy = vxy[1];
8618                     }
8619                 }
8620
8621                 var s = el.getScroll();
8622
8623                 vx += offsets.left + s.left;
8624                 vy += offsets.top + s.top;
8625
8626                 vw -= offsets.right;
8627                 vh -= offsets.bottom;
8628
8629                 var vr = vx+vw;
8630                 var vb = vy+vh;
8631
8632                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8633                 var x = xy[0], y = xy[1];
8634                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8635
8636                 // only move it if it needs it
8637                 var moved = false;
8638
8639                 // first validate right/bottom
8640                 if((x + w) > vr){
8641                     x = vr - w;
8642                     moved = true;
8643                 }
8644                 if((y + h) > vb){
8645                     y = vb - h;
8646                     moved = true;
8647                 }
8648                 // then make sure top/left isn't negative
8649                 if(x < vx){
8650                     x = vx;
8651                     moved = true;
8652                 }
8653                 if(y < vy){
8654                     y = vy;
8655                     moved = true;
8656                 }
8657                 return moved ? [x, y] : false;
8658             };
8659         }(),
8660
8661         // private
8662         adjustForConstraints : function(xy, parent, offsets){
8663             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8664         },
8665
8666         /**
8667          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8668          * document it aligns it to the viewport.
8669          * The position parameter is optional, and can be specified in any one of the following formats:
8670          * <ul>
8671          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8672          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8673          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8674          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8675          *   <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
8676          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8677          * </ul>
8678          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8679          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8680          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8681          * that specified in order to enforce the viewport constraints.
8682          * Following are all of the supported anchor positions:
8683     <pre>
8684     Value  Description
8685     -----  -----------------------------
8686     tl     The top left corner (default)
8687     t      The center of the top edge
8688     tr     The top right corner
8689     l      The center of the left edge
8690     c      In the center of the element
8691     r      The center of the right edge
8692     bl     The bottom left corner
8693     b      The center of the bottom edge
8694     br     The bottom right corner
8695     </pre>
8696     Example Usage:
8697     <pre><code>
8698     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8699     el.alignTo("other-el");
8700
8701     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8702     el.alignTo("other-el", "tr?");
8703
8704     // align the bottom right corner of el with the center left edge of other-el
8705     el.alignTo("other-el", "br-l?");
8706
8707     // align the center of el with the bottom left corner of other-el and
8708     // adjust the x position by -6 pixels (and the y position by 0)
8709     el.alignTo("other-el", "c-bl", [-6, 0]);
8710     </code></pre>
8711          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8712          * @param {String} position The position to align to.
8713          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8714          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8715          * @return {Roo.Element} this
8716          */
8717         alignTo : function(element, position, offsets, animate){
8718             var xy = this.getAlignToXY(element, position, offsets);
8719             this.setXY(xy, this.preanim(arguments, 3));
8720             return this;
8721         },
8722
8723         /**
8724          * Anchors an element to another element and realigns it when the window is resized.
8725          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8726          * @param {String} position The position to align to.
8727          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8728          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8729          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8730          * is a number, it is used as the buffer delay (defaults to 50ms).
8731          * @param {Function} callback The function to call after the animation finishes
8732          * @return {Roo.Element} this
8733          */
8734         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8735             var action = function(){
8736                 this.alignTo(el, alignment, offsets, animate);
8737                 Roo.callback(callback, this);
8738             };
8739             Roo.EventManager.onWindowResize(action, this);
8740             var tm = typeof monitorScroll;
8741             if(tm != 'undefined'){
8742                 Roo.EventManager.on(window, 'scroll', action, this,
8743                     {buffer: tm == 'number' ? monitorScroll : 50});
8744             }
8745             action.call(this); // align immediately
8746             return this;
8747         },
8748         /**
8749          * Clears any opacity settings from this element. Required in some cases for IE.
8750          * @return {Roo.Element} this
8751          */
8752         clearOpacity : function(){
8753             if (window.ActiveXObject) {
8754                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8755                     this.dom.style.filter = "";
8756                 }
8757             } else {
8758                 this.dom.style.opacity = "";
8759                 this.dom.style["-moz-opacity"] = "";
8760                 this.dom.style["-khtml-opacity"] = "";
8761             }
8762             return this;
8763         },
8764
8765         /**
8766          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8767          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8768          * @return {Roo.Element} this
8769          */
8770         hide : function(animate){
8771             this.setVisible(false, this.preanim(arguments, 0));
8772             return this;
8773         },
8774
8775         /**
8776         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8777         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8778          * @return {Roo.Element} this
8779          */
8780         show : function(animate){
8781             this.setVisible(true, this.preanim(arguments, 0));
8782             return this;
8783         },
8784
8785         /**
8786          * @private Test if size has a unit, otherwise appends the default
8787          */
8788         addUnits : function(size){
8789             return Roo.Element.addUnits(size, this.defaultUnit);
8790         },
8791
8792         /**
8793          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8794          * @return {Roo.Element} this
8795          */
8796         beginMeasure : function(){
8797             var el = this.dom;
8798             if(el.offsetWidth || el.offsetHeight){
8799                 return this; // offsets work already
8800             }
8801             var changed = [];
8802             var p = this.dom, b = document.body; // start with this element
8803             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8804                 var pe = Roo.get(p);
8805                 if(pe.getStyle('display') == 'none'){
8806                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8807                     p.style.visibility = "hidden";
8808                     p.style.display = "block";
8809                 }
8810                 p = p.parentNode;
8811             }
8812             this._measureChanged = changed;
8813             return this;
8814
8815         },
8816
8817         /**
8818          * Restores displays to before beginMeasure was called
8819          * @return {Roo.Element} this
8820          */
8821         endMeasure : function(){
8822             var changed = this._measureChanged;
8823             if(changed){
8824                 for(var i = 0, len = changed.length; i < len; i++) {
8825                     var r = changed[i];
8826                     r.el.style.visibility = r.visibility;
8827                     r.el.style.display = "none";
8828                 }
8829                 this._measureChanged = null;
8830             }
8831             return this;
8832         },
8833
8834         /**
8835         * Update the innerHTML of this element, optionally searching for and processing scripts
8836         * @param {String} html The new HTML
8837         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8838         * @param {Function} callback For async script loading you can be noticed when the update completes
8839         * @return {Roo.Element} this
8840          */
8841         update : function(html, loadScripts, callback){
8842             if(typeof html == "undefined"){
8843                 html = "";
8844             }
8845             if(loadScripts !== true){
8846                 this.dom.innerHTML = html;
8847                 if(typeof callback == "function"){
8848                     callback();
8849                 }
8850                 return this;
8851             }
8852             var id = Roo.id();
8853             var dom = this.dom;
8854
8855             html += '<span id="' + id + '"></span>';
8856
8857             E.onAvailable(id, function(){
8858                 var hd = document.getElementsByTagName("head")[0];
8859                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8860                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8861                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8862
8863                 var match;
8864                 while(match = re.exec(html)){
8865                     var attrs = match[1];
8866                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8867                     if(srcMatch && srcMatch[2]){
8868                        var s = document.createElement("script");
8869                        s.src = srcMatch[2];
8870                        var typeMatch = attrs.match(typeRe);
8871                        if(typeMatch && typeMatch[2]){
8872                            s.type = typeMatch[2];
8873                        }
8874                        hd.appendChild(s);
8875                     }else if(match[2] && match[2].length > 0){
8876                         if(window.execScript) {
8877                            window.execScript(match[2]);
8878                         } else {
8879                             /**
8880                              * eval:var:id
8881                              * eval:var:dom
8882                              * eval:var:html
8883                              * 
8884                              */
8885                            window.eval(match[2]);
8886                         }
8887                     }
8888                 }
8889                 var el = document.getElementById(id);
8890                 if(el){el.parentNode.removeChild(el);}
8891                 if(typeof callback == "function"){
8892                     callback();
8893                 }
8894             });
8895             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8896             return this;
8897         },
8898
8899         /**
8900          * Direct access to the UpdateManager update() method (takes the same parameters).
8901          * @param {String/Function} url The url for this request or a function to call to get the url
8902          * @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}
8903          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8904          * @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.
8905          * @return {Roo.Element} this
8906          */
8907         load : function(){
8908             var um = this.getUpdateManager();
8909             um.update.apply(um, arguments);
8910             return this;
8911         },
8912
8913         /**
8914         * Gets this element's UpdateManager
8915         * @return {Roo.UpdateManager} The UpdateManager
8916         */
8917         getUpdateManager : function(){
8918             if(!this.updateManager){
8919                 this.updateManager = new Roo.UpdateManager(this);
8920             }
8921             return this.updateManager;
8922         },
8923
8924         /**
8925          * Disables text selection for this element (normalized across browsers)
8926          * @return {Roo.Element} this
8927          */
8928         unselectable : function(){
8929             this.dom.unselectable = "on";
8930             this.swallowEvent("selectstart", true);
8931             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8932             this.addClass("x-unselectable");
8933             return this;
8934         },
8935
8936         /**
8937         * Calculates the x, y to center this element on the screen
8938         * @return {Array} The x, y values [x, y]
8939         */
8940         getCenterXY : function(){
8941             return this.getAlignToXY(document, 'c-c');
8942         },
8943
8944         /**
8945         * Centers the Element in either the viewport, or another Element.
8946         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8947         */
8948         center : function(centerIn){
8949             this.alignTo(centerIn || document, 'c-c');
8950             return this;
8951         },
8952
8953         /**
8954          * Tests various css rules/browsers to determine if this element uses a border box
8955          * @return {Boolean}
8956          */
8957         isBorderBox : function(){
8958             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8959         },
8960
8961         /**
8962          * Return a box {x, y, width, height} that can be used to set another elements
8963          * size/location to match this element.
8964          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8965          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8966          * @return {Object} box An object in the format {x, y, width, height}
8967          */
8968         getBox : function(contentBox, local){
8969             var xy;
8970             if(!local){
8971                 xy = this.getXY();
8972             }else{
8973                 var left = parseInt(this.getStyle("left"), 10) || 0;
8974                 var top = parseInt(this.getStyle("top"), 10) || 0;
8975                 xy = [left, top];
8976             }
8977             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8978             if(!contentBox){
8979                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8980             }else{
8981                 var l = this.getBorderWidth("l")+this.getPadding("l");
8982                 var r = this.getBorderWidth("r")+this.getPadding("r");
8983                 var t = this.getBorderWidth("t")+this.getPadding("t");
8984                 var b = this.getBorderWidth("b")+this.getPadding("b");
8985                 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)};
8986             }
8987             bx.right = bx.x + bx.width;
8988             bx.bottom = bx.y + bx.height;
8989             return bx;
8990         },
8991
8992         /**
8993          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8994          for more information about the sides.
8995          * @param {String} sides
8996          * @return {Number}
8997          */
8998         getFrameWidth : function(sides, onlyContentBox){
8999             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9000         },
9001
9002         /**
9003          * 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.
9004          * @param {Object} box The box to fill {x, y, width, height}
9005          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9006          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9007          * @return {Roo.Element} this
9008          */
9009         setBox : function(box, adjust, animate){
9010             var w = box.width, h = box.height;
9011             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9012                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9013                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9014             }
9015             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9016             return this;
9017         },
9018
9019         /**
9020          * Forces the browser to repaint this element
9021          * @return {Roo.Element} this
9022          */
9023          repaint : function(){
9024             var dom = this.dom;
9025             this.addClass("x-repaint");
9026             setTimeout(function(){
9027                 Roo.get(dom).removeClass("x-repaint");
9028             }, 1);
9029             return this;
9030         },
9031
9032         /**
9033          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9034          * then it returns the calculated width of the sides (see getPadding)
9035          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9036          * @return {Object/Number}
9037          */
9038         getMargins : function(side){
9039             if(!side){
9040                 return {
9041                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9042                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9043                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9044                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9045                 };
9046             }else{
9047                 return this.addStyles(side, El.margins);
9048              }
9049         },
9050
9051         // private
9052         addStyles : function(sides, styles){
9053             var val = 0, v, w;
9054             for(var i = 0, len = sides.length; i < len; i++){
9055                 v = this.getStyle(styles[sides.charAt(i)]);
9056                 if(v){
9057                      w = parseInt(v, 10);
9058                      if(w){ val += w; }
9059                 }
9060             }
9061             return val;
9062         },
9063
9064         /**
9065          * Creates a proxy element of this element
9066          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9067          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9068          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9069          * @return {Roo.Element} The new proxy element
9070          */
9071         createProxy : function(config, renderTo, matchBox){
9072             if(renderTo){
9073                 renderTo = Roo.getDom(renderTo);
9074             }else{
9075                 renderTo = document.body;
9076             }
9077             config = typeof config == "object" ?
9078                 config : {tag : "div", cls: config};
9079             var proxy = Roo.DomHelper.append(renderTo, config, true);
9080             if(matchBox){
9081                proxy.setBox(this.getBox());
9082             }
9083             return proxy;
9084         },
9085
9086         /**
9087          * Puts a mask over this element to disable user interaction. Requires core.css.
9088          * This method can only be applied to elements which accept child nodes.
9089          * @param {String} msg (optional) A message to display in the mask
9090          * @param {String} msgCls (optional) A css class to apply to the msg element
9091          * @return {Element} The mask  element
9092          */
9093         mask : function(msg, msgCls)
9094         {
9095             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9096                 this.setStyle("position", "relative");
9097             }
9098             if(!this._mask){
9099                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9100             }
9101             this.addClass("x-masked");
9102             this._mask.setDisplayed(true);
9103             
9104             // we wander
9105             var z = 0;
9106             var dom = this.dom;
9107             while (dom && dom.style) {
9108                 if (!isNaN(parseInt(dom.style.zIndex))) {
9109                     z = Math.max(z, parseInt(dom.style.zIndex));
9110                 }
9111                 dom = dom.parentNode;
9112             }
9113             // if we are masking the body - then it hides everything..
9114             if (this.dom == document.body) {
9115                 z = 1000000;
9116                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9117                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9118             }
9119            
9120             if(typeof msg == 'string'){
9121                 if(!this._maskMsg){
9122                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9123                 }
9124                 var mm = this._maskMsg;
9125                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9126                 if (mm.dom.firstChild) { // weird IE issue?
9127                     mm.dom.firstChild.innerHTML = msg;
9128                 }
9129                 mm.setDisplayed(true);
9130                 mm.center(this);
9131                 mm.setStyle('z-index', z + 102);
9132             }
9133             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9134                 this._mask.setHeight(this.getHeight());
9135             }
9136             this._mask.setStyle('z-index', z + 100);
9137             
9138             return this._mask;
9139         },
9140
9141         /**
9142          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9143          * it is cached for reuse.
9144          */
9145         unmask : function(removeEl){
9146             if(this._mask){
9147                 if(removeEl === true){
9148                     this._mask.remove();
9149                     delete this._mask;
9150                     if(this._maskMsg){
9151                         this._maskMsg.remove();
9152                         delete this._maskMsg;
9153                     }
9154                 }else{
9155                     this._mask.setDisplayed(false);
9156                     if(this._maskMsg){
9157                         this._maskMsg.setDisplayed(false);
9158                     }
9159                 }
9160             }
9161             this.removeClass("x-masked");
9162         },
9163
9164         /**
9165          * Returns true if this element is masked
9166          * @return {Boolean}
9167          */
9168         isMasked : function(){
9169             return this._mask && this._mask.isVisible();
9170         },
9171
9172         /**
9173          * Creates an iframe shim for this element to keep selects and other windowed objects from
9174          * showing through.
9175          * @return {Roo.Element} The new shim element
9176          */
9177         createShim : function(){
9178             var el = document.createElement('iframe');
9179             el.frameBorder = 'no';
9180             el.className = 'roo-shim';
9181             if(Roo.isIE && Roo.isSecure){
9182                 el.src = Roo.SSL_SECURE_URL;
9183             }
9184             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9185             shim.autoBoxAdjust = false;
9186             return shim;
9187         },
9188
9189         /**
9190          * Removes this element from the DOM and deletes it from the cache
9191          */
9192         remove : function(){
9193             if(this.dom.parentNode){
9194                 this.dom.parentNode.removeChild(this.dom);
9195             }
9196             delete El.cache[this.dom.id];
9197         },
9198
9199         /**
9200          * Sets up event handlers to add and remove a css class when the mouse is over this element
9201          * @param {String} className
9202          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9203          * mouseout events for children elements
9204          * @return {Roo.Element} this
9205          */
9206         addClassOnOver : function(className, preventFlicker){
9207             this.on("mouseover", function(){
9208                 Roo.fly(this, '_internal').addClass(className);
9209             }, this.dom);
9210             var removeFn = function(e){
9211                 if(preventFlicker !== true || !e.within(this, true)){
9212                     Roo.fly(this, '_internal').removeClass(className);
9213                 }
9214             };
9215             this.on("mouseout", removeFn, this.dom);
9216             return this;
9217         },
9218
9219         /**
9220          * Sets up event handlers to add and remove a css class when this element has the focus
9221          * @param {String} className
9222          * @return {Roo.Element} this
9223          */
9224         addClassOnFocus : function(className){
9225             this.on("focus", function(){
9226                 Roo.fly(this, '_internal').addClass(className);
9227             }, this.dom);
9228             this.on("blur", function(){
9229                 Roo.fly(this, '_internal').removeClass(className);
9230             }, this.dom);
9231             return this;
9232         },
9233         /**
9234          * 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)
9235          * @param {String} className
9236          * @return {Roo.Element} this
9237          */
9238         addClassOnClick : function(className){
9239             var dom = this.dom;
9240             this.on("mousedown", function(){
9241                 Roo.fly(dom, '_internal').addClass(className);
9242                 var d = Roo.get(document);
9243                 var fn = function(){
9244                     Roo.fly(dom, '_internal').removeClass(className);
9245                     d.removeListener("mouseup", fn);
9246                 };
9247                 d.on("mouseup", fn);
9248             });
9249             return this;
9250         },
9251
9252         /**
9253          * Stops the specified event from bubbling and optionally prevents the default action
9254          * @param {String} eventName
9255          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9256          * @return {Roo.Element} this
9257          */
9258         swallowEvent : function(eventName, preventDefault){
9259             var fn = function(e){
9260                 e.stopPropagation();
9261                 if(preventDefault){
9262                     e.preventDefault();
9263                 }
9264             };
9265             if(eventName instanceof Array){
9266                 for(var i = 0, len = eventName.length; i < len; i++){
9267                      this.on(eventName[i], fn);
9268                 }
9269                 return this;
9270             }
9271             this.on(eventName, fn);
9272             return this;
9273         },
9274
9275         /**
9276          * @private
9277          */
9278       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9279
9280         /**
9281          * Sizes this element to its parent element's dimensions performing
9282          * neccessary box adjustments.
9283          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9284          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9285          * @return {Roo.Element} this
9286          */
9287         fitToParent : function(monitorResize, targetParent) {
9288           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9289           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9290           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9291             return;
9292           }
9293           var p = Roo.get(targetParent || this.dom.parentNode);
9294           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9295           if (monitorResize === true) {
9296             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9297             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9298           }
9299           return this;
9300         },
9301
9302         /**
9303          * Gets the next sibling, skipping text nodes
9304          * @return {HTMLElement} The next sibling or null
9305          */
9306         getNextSibling : function(){
9307             var n = this.dom.nextSibling;
9308             while(n && n.nodeType != 1){
9309                 n = n.nextSibling;
9310             }
9311             return n;
9312         },
9313
9314         /**
9315          * Gets the previous sibling, skipping text nodes
9316          * @return {HTMLElement} The previous sibling or null
9317          */
9318         getPrevSibling : function(){
9319             var n = this.dom.previousSibling;
9320             while(n && n.nodeType != 1){
9321                 n = n.previousSibling;
9322             }
9323             return n;
9324         },
9325
9326
9327         /**
9328          * Appends the passed element(s) to this element
9329          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9330          * @return {Roo.Element} this
9331          */
9332         appendChild: function(el){
9333             el = Roo.get(el);
9334             el.appendTo(this);
9335             return this;
9336         },
9337
9338         /**
9339          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9340          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9341          * automatically generated with the specified attributes.
9342          * @param {HTMLElement} insertBefore (optional) a child element of this element
9343          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9344          * @return {Roo.Element} The new child element
9345          */
9346         createChild: function(config, insertBefore, returnDom){
9347             config = config || {tag:'div'};
9348             if(insertBefore){
9349                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9350             }
9351             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9352         },
9353
9354         /**
9355          * Appends this element to the passed element
9356          * @param {String/HTMLElement/Element} el The new parent element
9357          * @return {Roo.Element} this
9358          */
9359         appendTo: function(el){
9360             el = Roo.getDom(el);
9361             el.appendChild(this.dom);
9362             return this;
9363         },
9364
9365         /**
9366          * Inserts this element before the passed element in the DOM
9367          * @param {String/HTMLElement/Element} el The element to insert before
9368          * @return {Roo.Element} this
9369          */
9370         insertBefore: function(el){
9371             el = Roo.getDom(el);
9372             el.parentNode.insertBefore(this.dom, el);
9373             return this;
9374         },
9375
9376         /**
9377          * Inserts this element after the passed element in the DOM
9378          * @param {String/HTMLElement/Element} el The element to insert after
9379          * @return {Roo.Element} this
9380          */
9381         insertAfter: function(el){
9382             el = Roo.getDom(el);
9383             el.parentNode.insertBefore(this.dom, el.nextSibling);
9384             return this;
9385         },
9386
9387         /**
9388          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9389          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9390          * @return {Roo.Element} The new child
9391          */
9392         insertFirst: function(el, returnDom){
9393             el = el || {};
9394             if(typeof el == 'object' && !el.nodeType){ // dh config
9395                 return this.createChild(el, this.dom.firstChild, returnDom);
9396             }else{
9397                 el = Roo.getDom(el);
9398                 this.dom.insertBefore(el, this.dom.firstChild);
9399                 return !returnDom ? Roo.get(el) : el;
9400             }
9401         },
9402
9403         /**
9404          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9405          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9406          * @param {String} where (optional) 'before' or 'after' defaults to before
9407          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9408          * @return {Roo.Element} the inserted Element
9409          */
9410         insertSibling: function(el, where, returnDom){
9411             where = where ? where.toLowerCase() : 'before';
9412             el = el || {};
9413             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9414
9415             if(typeof el == 'object' && !el.nodeType){ // dh config
9416                 if(where == 'after' && !this.dom.nextSibling){
9417                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9418                 }else{
9419                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9420                 }
9421
9422             }else{
9423                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9424                             where == 'before' ? this.dom : this.dom.nextSibling);
9425                 if(!returnDom){
9426                     rt = Roo.get(rt);
9427                 }
9428             }
9429             return rt;
9430         },
9431
9432         /**
9433          * Creates and wraps this element with another element
9434          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9435          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9436          * @return {HTMLElement/Element} The newly created wrapper element
9437          */
9438         wrap: function(config, returnDom){
9439             if(!config){
9440                 config = {tag: "div"};
9441             }
9442             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9443             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9444             return newEl;
9445         },
9446
9447         /**
9448          * Replaces the passed element with this element
9449          * @param {String/HTMLElement/Element} el The element to replace
9450          * @return {Roo.Element} this
9451          */
9452         replace: function(el){
9453             el = Roo.get(el);
9454             this.insertBefore(el);
9455             el.remove();
9456             return this;
9457         },
9458
9459         /**
9460          * Inserts an html fragment into this element
9461          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9462          * @param {String} html The HTML fragment
9463          * @param {Boolean} returnEl True to return an Roo.Element
9464          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9465          */
9466         insertHtml : function(where, html, returnEl){
9467             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9468             return returnEl ? Roo.get(el) : el;
9469         },
9470
9471         /**
9472          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9473          * @param {Object} o The object with the attributes
9474          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9475          * @return {Roo.Element} this
9476          */
9477         set : function(o, useSet){
9478             var el = this.dom;
9479             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9480             for(var attr in o){
9481                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9482                 if(attr=="cls"){
9483                     el.className = o["cls"];
9484                 }else{
9485                     if(useSet) {
9486                         el.setAttribute(attr, o[attr]);
9487                     } else {
9488                         el[attr] = o[attr];
9489                     }
9490                 }
9491             }
9492             if(o.style){
9493                 Roo.DomHelper.applyStyles(el, o.style);
9494             }
9495             return this;
9496         },
9497
9498         /**
9499          * Convenience method for constructing a KeyMap
9500          * @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:
9501          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9502          * @param {Function} fn The function to call
9503          * @param {Object} scope (optional) The scope of the function
9504          * @return {Roo.KeyMap} The KeyMap created
9505          */
9506         addKeyListener : function(key, fn, scope){
9507             var config;
9508             if(typeof key != "object" || key instanceof Array){
9509                 config = {
9510                     key: key,
9511                     fn: fn,
9512                     scope: scope
9513                 };
9514             }else{
9515                 config = {
9516                     key : key.key,
9517                     shift : key.shift,
9518                     ctrl : key.ctrl,
9519                     alt : key.alt,
9520                     fn: fn,
9521                     scope: scope
9522                 };
9523             }
9524             return new Roo.KeyMap(this, config);
9525         },
9526
9527         /**
9528          * Creates a KeyMap for this element
9529          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9530          * @return {Roo.KeyMap} The KeyMap created
9531          */
9532         addKeyMap : function(config){
9533             return new Roo.KeyMap(this, config);
9534         },
9535
9536         /**
9537          * Returns true if this element is scrollable.
9538          * @return {Boolean}
9539          */
9540          isScrollable : function(){
9541             var dom = this.dom;
9542             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9543         },
9544
9545         /**
9546          * 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().
9547          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9548          * @param {Number} value The new scroll value
9549          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9550          * @return {Element} this
9551          */
9552
9553         scrollTo : function(side, value, animate){
9554             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9555             if(!animate || !A){
9556                 this.dom[prop] = value;
9557             }else{
9558                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9559                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9560             }
9561             return this;
9562         },
9563
9564         /**
9565          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9566          * within this element's scrollable range.
9567          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9568          * @param {Number} distance How far to scroll the element in pixels
9569          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9570          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9571          * was scrolled as far as it could go.
9572          */
9573          scroll : function(direction, distance, animate){
9574              if(!this.isScrollable()){
9575                  return;
9576              }
9577              var el = this.dom;
9578              var l = el.scrollLeft, t = el.scrollTop;
9579              var w = el.scrollWidth, h = el.scrollHeight;
9580              var cw = el.clientWidth, ch = el.clientHeight;
9581              direction = direction.toLowerCase();
9582              var scrolled = false;
9583              var a = this.preanim(arguments, 2);
9584              switch(direction){
9585                  case "l":
9586                  case "left":
9587                      if(w - l > cw){
9588                          var v = Math.min(l + distance, w-cw);
9589                          this.scrollTo("left", v, a);
9590                          scrolled = true;
9591                      }
9592                      break;
9593                 case "r":
9594                 case "right":
9595                      if(l > 0){
9596                          var v = Math.max(l - distance, 0);
9597                          this.scrollTo("left", v, a);
9598                          scrolled = true;
9599                      }
9600                      break;
9601                 case "t":
9602                 case "top":
9603                 case "up":
9604                      if(t > 0){
9605                          var v = Math.max(t - distance, 0);
9606                          this.scrollTo("top", v, a);
9607                          scrolled = true;
9608                      }
9609                      break;
9610                 case "b":
9611                 case "bottom":
9612                 case "down":
9613                      if(h - t > ch){
9614                          var v = Math.min(t + distance, h-ch);
9615                          this.scrollTo("top", v, a);
9616                          scrolled = true;
9617                      }
9618                      break;
9619              }
9620              return scrolled;
9621         },
9622
9623         /**
9624          * Translates the passed page coordinates into left/top css values for this element
9625          * @param {Number/Array} x The page x or an array containing [x, y]
9626          * @param {Number} y The page y
9627          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9628          */
9629         translatePoints : function(x, y){
9630             if(typeof x == 'object' || x instanceof Array){
9631                 y = x[1]; x = x[0];
9632             }
9633             var p = this.getStyle('position');
9634             var o = this.getXY();
9635
9636             var l = parseInt(this.getStyle('left'), 10);
9637             var t = parseInt(this.getStyle('top'), 10);
9638
9639             if(isNaN(l)){
9640                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9641             }
9642             if(isNaN(t)){
9643                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9644             }
9645
9646             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9647         },
9648
9649         /**
9650          * Returns the current scroll position of the element.
9651          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9652          */
9653         getScroll : function(){
9654             var d = this.dom, doc = document;
9655             if(d == doc || d == doc.body){
9656                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9657                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9658                 return {left: l, top: t};
9659             }else{
9660                 return {left: d.scrollLeft, top: d.scrollTop};
9661             }
9662         },
9663
9664         /**
9665          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9666          * are convert to standard 6 digit hex color.
9667          * @param {String} attr The css attribute
9668          * @param {String} defaultValue The default value to use when a valid color isn't found
9669          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9670          * YUI color anims.
9671          */
9672         getColor : function(attr, defaultValue, prefix){
9673             var v = this.getStyle(attr);
9674             if(!v || v == "transparent" || v == "inherit") {
9675                 return defaultValue;
9676             }
9677             var color = typeof prefix == "undefined" ? "#" : prefix;
9678             if(v.substr(0, 4) == "rgb("){
9679                 var rvs = v.slice(4, v.length -1).split(",");
9680                 for(var i = 0; i < 3; i++){
9681                     var h = parseInt(rvs[i]).toString(16);
9682                     if(h < 16){
9683                         h = "0" + h;
9684                     }
9685                     color += h;
9686                 }
9687             } else {
9688                 if(v.substr(0, 1) == "#"){
9689                     if(v.length == 4) {
9690                         for(var i = 1; i < 4; i++){
9691                             var c = v.charAt(i);
9692                             color +=  c + c;
9693                         }
9694                     }else if(v.length == 7){
9695                         color += v.substr(1);
9696                     }
9697                 }
9698             }
9699             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9700         },
9701
9702         /**
9703          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9704          * gradient background, rounded corners and a 4-way shadow.
9705          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9706          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9707          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9708          * @return {Roo.Element} this
9709          */
9710         boxWrap : function(cls){
9711             cls = cls || 'x-box';
9712             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9713             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9714             return el;
9715         },
9716
9717         /**
9718          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9719          * @param {String} namespace The namespace in which to look for the attribute
9720          * @param {String} name The attribute name
9721          * @return {String} The attribute value
9722          */
9723         getAttributeNS : Roo.isIE ? function(ns, name){
9724             var d = this.dom;
9725             var type = typeof d[ns+":"+name];
9726             if(type != 'undefined' && type != 'unknown'){
9727                 return d[ns+":"+name];
9728             }
9729             return d[name];
9730         } : function(ns, name){
9731             var d = this.dom;
9732             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9733         },
9734         
9735         
9736         /**
9737          * Sets or Returns the value the dom attribute value
9738          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9739          * @param {String} value (optional) The value to set the attribute to
9740          * @return {String} The attribute value
9741          */
9742         attr : function(name){
9743             if (arguments.length > 1) {
9744                 this.dom.setAttribute(name, arguments[1]);
9745                 return arguments[1];
9746             }
9747             if (typeof(name) == 'object') {
9748                 for(var i in name) {
9749                     this.attr(i, name[i]);
9750                 }
9751                 return name;
9752             }
9753             
9754             
9755             if (!this.dom.hasAttribute(name)) {
9756                 return undefined;
9757             }
9758             return this.dom.getAttribute(name);
9759         }
9760         
9761         
9762         
9763     };
9764
9765     var ep = El.prototype;
9766
9767     /**
9768      * Appends an event handler (Shorthand for addListener)
9769      * @param {String}   eventName     The type of event to append
9770      * @param {Function} fn        The method the event invokes
9771      * @param {Object} scope       (optional) The scope (this object) of the fn
9772      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9773      * @method
9774      */
9775     ep.on = ep.addListener;
9776         // backwards compat
9777     ep.mon = ep.addListener;
9778
9779     /**
9780      * Removes an event handler from this element (shorthand for removeListener)
9781      * @param {String} eventName the type of event to remove
9782      * @param {Function} fn the method the event invokes
9783      * @return {Roo.Element} this
9784      * @method
9785      */
9786     ep.un = ep.removeListener;
9787
9788     /**
9789      * true to automatically adjust width and height settings for box-model issues (default to true)
9790      */
9791     ep.autoBoxAdjust = true;
9792
9793     // private
9794     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9795
9796     // private
9797     El.addUnits = function(v, defaultUnit){
9798         if(v === "" || v == "auto"){
9799             return v;
9800         }
9801         if(v === undefined){
9802             return '';
9803         }
9804         if(typeof v == "number" || !El.unitPattern.test(v)){
9805             return v + (defaultUnit || 'px');
9806         }
9807         return v;
9808     };
9809
9810     // special markup used throughout Roo when box wrapping elements
9811     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>';
9812     /**
9813      * Visibility mode constant - Use visibility to hide element
9814      * @static
9815      * @type Number
9816      */
9817     El.VISIBILITY = 1;
9818     /**
9819      * Visibility mode constant - Use display to hide element
9820      * @static
9821      * @type Number
9822      */
9823     El.DISPLAY = 2;
9824
9825     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9826     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9827     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9828
9829
9830
9831     /**
9832      * @private
9833      */
9834     El.cache = {};
9835
9836     var docEl;
9837
9838     /**
9839      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9840      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9841      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9842      * @return {Element} The Element object
9843      * @static
9844      */
9845     El.get = function(el){
9846         var ex, elm, id;
9847         if(!el){ return null; }
9848         if(typeof el == "string"){ // element id
9849             if(!(elm = document.getElementById(el))){
9850                 return null;
9851             }
9852             if(ex = El.cache[el]){
9853                 ex.dom = elm;
9854             }else{
9855                 ex = El.cache[el] = new El(elm);
9856             }
9857             return ex;
9858         }else if(el.tagName){ // dom element
9859             if(!(id = el.id)){
9860                 id = Roo.id(el);
9861             }
9862             if(ex = El.cache[id]){
9863                 ex.dom = el;
9864             }else{
9865                 ex = El.cache[id] = new El(el);
9866             }
9867             return ex;
9868         }else if(el instanceof El){
9869             if(el != docEl){
9870                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9871                                                               // catch case where it hasn't been appended
9872                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9873             }
9874             return el;
9875         }else if(el.isComposite){
9876             return el;
9877         }else if(el instanceof Array){
9878             return El.select(el);
9879         }else if(el == document){
9880             // create a bogus element object representing the document object
9881             if(!docEl){
9882                 var f = function(){};
9883                 f.prototype = El.prototype;
9884                 docEl = new f();
9885                 docEl.dom = document;
9886             }
9887             return docEl;
9888         }
9889         return null;
9890     };
9891
9892     // private
9893     El.uncache = function(el){
9894         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9895             if(a[i]){
9896                 delete El.cache[a[i].id || a[i]];
9897             }
9898         }
9899     };
9900
9901     // private
9902     // Garbage collection - uncache elements/purge listeners on orphaned elements
9903     // so we don't hold a reference and cause the browser to retain them
9904     El.garbageCollect = function(){
9905         if(!Roo.enableGarbageCollector){
9906             clearInterval(El.collectorThread);
9907             return;
9908         }
9909         for(var eid in El.cache){
9910             var el = El.cache[eid], d = el.dom;
9911             // -------------------------------------------------------
9912             // Determining what is garbage:
9913             // -------------------------------------------------------
9914             // !d
9915             // dom node is null, definitely garbage
9916             // -------------------------------------------------------
9917             // !d.parentNode
9918             // no parentNode == direct orphan, definitely garbage
9919             // -------------------------------------------------------
9920             // !d.offsetParent && !document.getElementById(eid)
9921             // display none elements have no offsetParent so we will
9922             // also try to look it up by it's id. However, check
9923             // offsetParent first so we don't do unneeded lookups.
9924             // This enables collection of elements that are not orphans
9925             // directly, but somewhere up the line they have an orphan
9926             // parent.
9927             // -------------------------------------------------------
9928             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9929                 delete El.cache[eid];
9930                 if(d && Roo.enableListenerCollection){
9931                     E.purgeElement(d);
9932                 }
9933             }
9934         }
9935     }
9936     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9937
9938
9939     // dom is optional
9940     El.Flyweight = function(dom){
9941         this.dom = dom;
9942     };
9943     El.Flyweight.prototype = El.prototype;
9944
9945     El._flyweights = {};
9946     /**
9947      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9948      * the dom node can be overwritten by other code.
9949      * @param {String/HTMLElement} el The dom node or id
9950      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9951      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9952      * @static
9953      * @return {Element} The shared Element object
9954      */
9955     El.fly = function(el, named){
9956         named = named || '_global';
9957         el = Roo.getDom(el);
9958         if(!el){
9959             return null;
9960         }
9961         if(!El._flyweights[named]){
9962             El._flyweights[named] = new El.Flyweight();
9963         }
9964         El._flyweights[named].dom = el;
9965         return El._flyweights[named];
9966     };
9967
9968     /**
9969      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9970      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9971      * Shorthand of {@link Roo.Element#get}
9972      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9973      * @return {Element} The Element object
9974      * @member Roo
9975      * @method get
9976      */
9977     Roo.get = El.get;
9978     /**
9979      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9980      * the dom node can be overwritten by other code.
9981      * Shorthand of {@link Roo.Element#fly}
9982      * @param {String/HTMLElement} el The dom node or id
9983      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9984      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9985      * @static
9986      * @return {Element} The shared Element object
9987      * @member Roo
9988      * @method fly
9989      */
9990     Roo.fly = El.fly;
9991
9992     // speedy lookup for elements never to box adjust
9993     var noBoxAdjust = Roo.isStrict ? {
9994         select:1
9995     } : {
9996         input:1, select:1, textarea:1
9997     };
9998     if(Roo.isIE || Roo.isGecko){
9999         noBoxAdjust['button'] = 1;
10000     }
10001
10002
10003     Roo.EventManager.on(window, 'unload', function(){
10004         delete El.cache;
10005         delete El._flyweights;
10006     });
10007 })();
10008
10009
10010
10011
10012 if(Roo.DomQuery){
10013     Roo.Element.selectorFunction = Roo.DomQuery.select;
10014 }
10015
10016 Roo.Element.select = function(selector, unique, root){
10017     var els;
10018     if(typeof selector == "string"){
10019         els = Roo.Element.selectorFunction(selector, root);
10020     }else if(selector.length !== undefined){
10021         els = selector;
10022     }else{
10023         throw "Invalid selector";
10024     }
10025     if(unique === true){
10026         return new Roo.CompositeElement(els);
10027     }else{
10028         return new Roo.CompositeElementLite(els);
10029     }
10030 };
10031 /**
10032  * Selects elements based on the passed CSS selector to enable working on them as 1.
10033  * @param {String/Array} selector The CSS selector or an array of elements
10034  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10035  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10036  * @return {CompositeElementLite/CompositeElement}
10037  * @member Roo
10038  * @method select
10039  */
10040 Roo.select = Roo.Element.select;
10041
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055 /*
10056  * Based on:
10057  * Ext JS Library 1.1.1
10058  * Copyright(c) 2006-2007, Ext JS, LLC.
10059  *
10060  * Originally Released Under LGPL - original licence link has changed is not relivant.
10061  *
10062  * Fork - LGPL
10063  * <script type="text/javascript">
10064  */
10065
10066
10067
10068 //Notifies Element that fx methods are available
10069 Roo.enableFx = true;
10070
10071 /**
10072  * @class Roo.Fx
10073  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10074  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10075  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10076  * Element effects to work.</p><br/>
10077  *
10078  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10079  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10080  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10081  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10082  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10083  * expected results and should be done with care.</p><br/>
10084  *
10085  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10086  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10087 <pre>
10088 Value  Description
10089 -----  -----------------------------
10090 tl     The top left corner
10091 t      The center of the top edge
10092 tr     The top right corner
10093 l      The center of the left edge
10094 r      The center of the right edge
10095 bl     The bottom left corner
10096 b      The center of the bottom edge
10097 br     The bottom right corner
10098 </pre>
10099  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10100  * below are common options that can be passed to any Fx method.</b>
10101  * @cfg {Function} callback A function called when the effect is finished
10102  * @cfg {Object} scope The scope of the effect function
10103  * @cfg {String} easing A valid Easing value for the effect
10104  * @cfg {String} afterCls A css class to apply after the effect
10105  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10106  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10107  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10108  * effects that end with the element being visually hidden, ignored otherwise)
10109  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10110  * a function which returns such a specification that will be applied to the Element after the effect finishes
10111  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10112  * @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
10113  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10114  */
10115 Roo.Fx = {
10116         /**
10117          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10118          * origin for the slide effect.  This function automatically handles wrapping the element with
10119          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10120          * Usage:
10121          *<pre><code>
10122 // default: slide the element in from the top
10123 el.slideIn();
10124
10125 // custom: slide the element in from the right with a 2-second duration
10126 el.slideIn('r', { duration: 2 });
10127
10128 // common config options shown with default values
10129 el.slideIn('t', {
10130     easing: 'easeOut',
10131     duration: .5
10132 });
10133 </code></pre>
10134          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10135          * @param {Object} options (optional) Object literal with any of the Fx config options
10136          * @return {Roo.Element} The Element
10137          */
10138     slideIn : function(anchor, o){
10139         var el = this.getFxEl();
10140         o = o || {};
10141
10142         el.queueFx(o, function(){
10143
10144             anchor = anchor || "t";
10145
10146             // fix display to visibility
10147             this.fixDisplay();
10148
10149             // restore values after effect
10150             var r = this.getFxRestore();
10151             var b = this.getBox();
10152             // fixed size for slide
10153             this.setSize(b);
10154
10155             // wrap if needed
10156             var wrap = this.fxWrap(r.pos, o, "hidden");
10157
10158             var st = this.dom.style;
10159             st.visibility = "visible";
10160             st.position = "absolute";
10161
10162             // clear out temp styles after slide and unwrap
10163             var after = function(){
10164                 el.fxUnwrap(wrap, r.pos, o);
10165                 st.width = r.width;
10166                 st.height = r.height;
10167                 el.afterFx(o);
10168             };
10169             // time to calc the positions
10170             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10171
10172             switch(anchor.toLowerCase()){
10173                 case "t":
10174                     wrap.setSize(b.width, 0);
10175                     st.left = st.bottom = "0";
10176                     a = {height: bh};
10177                 break;
10178                 case "l":
10179                     wrap.setSize(0, b.height);
10180                     st.right = st.top = "0";
10181                     a = {width: bw};
10182                 break;
10183                 case "r":
10184                     wrap.setSize(0, b.height);
10185                     wrap.setX(b.right);
10186                     st.left = st.top = "0";
10187                     a = {width: bw, points: pt};
10188                 break;
10189                 case "b":
10190                     wrap.setSize(b.width, 0);
10191                     wrap.setY(b.bottom);
10192                     st.left = st.top = "0";
10193                     a = {height: bh, points: pt};
10194                 break;
10195                 case "tl":
10196                     wrap.setSize(0, 0);
10197                     st.right = st.bottom = "0";
10198                     a = {width: bw, height: bh};
10199                 break;
10200                 case "bl":
10201                     wrap.setSize(0, 0);
10202                     wrap.setY(b.y+b.height);
10203                     st.right = st.top = "0";
10204                     a = {width: bw, height: bh, points: pt};
10205                 break;
10206                 case "br":
10207                     wrap.setSize(0, 0);
10208                     wrap.setXY([b.right, b.bottom]);
10209                     st.left = st.top = "0";
10210                     a = {width: bw, height: bh, points: pt};
10211                 break;
10212                 case "tr":
10213                     wrap.setSize(0, 0);
10214                     wrap.setX(b.x+b.width);
10215                     st.left = st.bottom = "0";
10216                     a = {width: bw, height: bh, points: pt};
10217                 break;
10218             }
10219             this.dom.style.visibility = "visible";
10220             wrap.show();
10221
10222             arguments.callee.anim = wrap.fxanim(a,
10223                 o,
10224                 'motion',
10225                 .5,
10226                 'easeOut', after);
10227         });
10228         return this;
10229     },
10230     
10231         /**
10232          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10233          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10234          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10235          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10236          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10237          * Usage:
10238          *<pre><code>
10239 // default: slide the element out to the top
10240 el.slideOut();
10241
10242 // custom: slide the element out to the right with a 2-second duration
10243 el.slideOut('r', { duration: 2 });
10244
10245 // common config options shown with default values
10246 el.slideOut('t', {
10247     easing: 'easeOut',
10248     duration: .5,
10249     remove: false,
10250     useDisplay: false
10251 });
10252 </code></pre>
10253          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10254          * @param {Object} options (optional) Object literal with any of the Fx config options
10255          * @return {Roo.Element} The Element
10256          */
10257     slideOut : function(anchor, o){
10258         var el = this.getFxEl();
10259         o = o || {};
10260
10261         el.queueFx(o, function(){
10262
10263             anchor = anchor || "t";
10264
10265             // restore values after effect
10266             var r = this.getFxRestore();
10267             
10268             var b = this.getBox();
10269             // fixed size for slide
10270             this.setSize(b);
10271
10272             // wrap if needed
10273             var wrap = this.fxWrap(r.pos, o, "visible");
10274
10275             var st = this.dom.style;
10276             st.visibility = "visible";
10277             st.position = "absolute";
10278
10279             wrap.setSize(b);
10280
10281             var after = function(){
10282                 if(o.useDisplay){
10283                     el.setDisplayed(false);
10284                 }else{
10285                     el.hide();
10286                 }
10287
10288                 el.fxUnwrap(wrap, r.pos, o);
10289
10290                 st.width = r.width;
10291                 st.height = r.height;
10292
10293                 el.afterFx(o);
10294             };
10295
10296             var a, zero = {to: 0};
10297             switch(anchor.toLowerCase()){
10298                 case "t":
10299                     st.left = st.bottom = "0";
10300                     a = {height: zero};
10301                 break;
10302                 case "l":
10303                     st.right = st.top = "0";
10304                     a = {width: zero};
10305                 break;
10306                 case "r":
10307                     st.left = st.top = "0";
10308                     a = {width: zero, points: {to:[b.right, b.y]}};
10309                 break;
10310                 case "b":
10311                     st.left = st.top = "0";
10312                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10313                 break;
10314                 case "tl":
10315                     st.right = st.bottom = "0";
10316                     a = {width: zero, height: zero};
10317                 break;
10318                 case "bl":
10319                     st.right = st.top = "0";
10320                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10321                 break;
10322                 case "br":
10323                     st.left = st.top = "0";
10324                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10325                 break;
10326                 case "tr":
10327                     st.left = st.bottom = "0";
10328                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10329                 break;
10330             }
10331
10332             arguments.callee.anim = wrap.fxanim(a,
10333                 o,
10334                 'motion',
10335                 .5,
10336                 "easeOut", after);
10337         });
10338         return this;
10339     },
10340
10341         /**
10342          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10343          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10344          * The element must be removed from the DOM using the 'remove' config option if desired.
10345          * Usage:
10346          *<pre><code>
10347 // default
10348 el.puff();
10349
10350 // common config options shown with default values
10351 el.puff({
10352     easing: 'easeOut',
10353     duration: .5,
10354     remove: false,
10355     useDisplay: false
10356 });
10357 </code></pre>
10358          * @param {Object} options (optional) Object literal with any of the Fx config options
10359          * @return {Roo.Element} The Element
10360          */
10361     puff : function(o){
10362         var el = this.getFxEl();
10363         o = o || {};
10364
10365         el.queueFx(o, function(){
10366             this.clearOpacity();
10367             this.show();
10368
10369             // restore values after effect
10370             var r = this.getFxRestore();
10371             var st = this.dom.style;
10372
10373             var after = function(){
10374                 if(o.useDisplay){
10375                     el.setDisplayed(false);
10376                 }else{
10377                     el.hide();
10378                 }
10379
10380                 el.clearOpacity();
10381
10382                 el.setPositioning(r.pos);
10383                 st.width = r.width;
10384                 st.height = r.height;
10385                 st.fontSize = '';
10386                 el.afterFx(o);
10387             };
10388
10389             var width = this.getWidth();
10390             var height = this.getHeight();
10391
10392             arguments.callee.anim = this.fxanim({
10393                     width : {to: this.adjustWidth(width * 2)},
10394                     height : {to: this.adjustHeight(height * 2)},
10395                     points : {by: [-(width * .5), -(height * .5)]},
10396                     opacity : {to: 0},
10397                     fontSize: {to:200, unit: "%"}
10398                 },
10399                 o,
10400                 'motion',
10401                 .5,
10402                 "easeOut", after);
10403         });
10404         return this;
10405     },
10406
10407         /**
10408          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10409          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10410          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10411          * Usage:
10412          *<pre><code>
10413 // default
10414 el.switchOff();
10415
10416 // all config options shown with default values
10417 el.switchOff({
10418     easing: 'easeIn',
10419     duration: .3,
10420     remove: false,
10421     useDisplay: false
10422 });
10423 </code></pre>
10424          * @param {Object} options (optional) Object literal with any of the Fx config options
10425          * @return {Roo.Element} The Element
10426          */
10427     switchOff : function(o){
10428         var el = this.getFxEl();
10429         o = o || {};
10430
10431         el.queueFx(o, function(){
10432             this.clearOpacity();
10433             this.clip();
10434
10435             // restore values after effect
10436             var r = this.getFxRestore();
10437             var st = this.dom.style;
10438
10439             var after = function(){
10440                 if(o.useDisplay){
10441                     el.setDisplayed(false);
10442                 }else{
10443                     el.hide();
10444                 }
10445
10446                 el.clearOpacity();
10447                 el.setPositioning(r.pos);
10448                 st.width = r.width;
10449                 st.height = r.height;
10450
10451                 el.afterFx(o);
10452             };
10453
10454             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10455                 this.clearOpacity();
10456                 (function(){
10457                     this.fxanim({
10458                         height:{to:1},
10459                         points:{by:[0, this.getHeight() * .5]}
10460                     }, o, 'motion', 0.3, 'easeIn', after);
10461                 }).defer(100, this);
10462             });
10463         });
10464         return this;
10465     },
10466
10467     /**
10468      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10469      * changed using the "attr" config option) and then fading back to the original color. If no original
10470      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10471      * Usage:
10472 <pre><code>
10473 // default: highlight background to yellow
10474 el.highlight();
10475
10476 // custom: highlight foreground text to blue for 2 seconds
10477 el.highlight("0000ff", { attr: 'color', duration: 2 });
10478
10479 // common config options shown with default values
10480 el.highlight("ffff9c", {
10481     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10482     endColor: (current color) or "ffffff",
10483     easing: 'easeIn',
10484     duration: 1
10485 });
10486 </code></pre>
10487      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10488      * @param {Object} options (optional) Object literal with any of the Fx config options
10489      * @return {Roo.Element} The Element
10490      */ 
10491     highlight : function(color, o){
10492         var el = this.getFxEl();
10493         o = o || {};
10494
10495         el.queueFx(o, function(){
10496             color = color || "ffff9c";
10497             attr = o.attr || "backgroundColor";
10498
10499             this.clearOpacity();
10500             this.show();
10501
10502             var origColor = this.getColor(attr);
10503             var restoreColor = this.dom.style[attr];
10504             endColor = (o.endColor || origColor) || "ffffff";
10505
10506             var after = function(){
10507                 el.dom.style[attr] = restoreColor;
10508                 el.afterFx(o);
10509             };
10510
10511             var a = {};
10512             a[attr] = {from: color, to: endColor};
10513             arguments.callee.anim = this.fxanim(a,
10514                 o,
10515                 'color',
10516                 1,
10517                 'easeIn', after);
10518         });
10519         return this;
10520     },
10521
10522    /**
10523     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10524     * Usage:
10525 <pre><code>
10526 // default: a single light blue ripple
10527 el.frame();
10528
10529 // custom: 3 red ripples lasting 3 seconds total
10530 el.frame("ff0000", 3, { duration: 3 });
10531
10532 // common config options shown with default values
10533 el.frame("C3DAF9", 1, {
10534     duration: 1 //duration of entire animation (not each individual ripple)
10535     // Note: Easing is not configurable and will be ignored if included
10536 });
10537 </code></pre>
10538     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10539     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10540     * @param {Object} options (optional) Object literal with any of the Fx config options
10541     * @return {Roo.Element} The Element
10542     */
10543     frame : function(color, count, o){
10544         var el = this.getFxEl();
10545         o = o || {};
10546
10547         el.queueFx(o, function(){
10548             color = color || "#C3DAF9";
10549             if(color.length == 6){
10550                 color = "#" + color;
10551             }
10552             count = count || 1;
10553             duration = o.duration || 1;
10554             this.show();
10555
10556             var b = this.getBox();
10557             var animFn = function(){
10558                 var proxy = this.createProxy({
10559
10560                      style:{
10561                         visbility:"hidden",
10562                         position:"absolute",
10563                         "z-index":"35000", // yee haw
10564                         border:"0px solid " + color
10565                      }
10566                   });
10567                 var scale = Roo.isBorderBox ? 2 : 1;
10568                 proxy.animate({
10569                     top:{from:b.y, to:b.y - 20},
10570                     left:{from:b.x, to:b.x - 20},
10571                     borderWidth:{from:0, to:10},
10572                     opacity:{from:1, to:0},
10573                     height:{from:b.height, to:(b.height + (20*scale))},
10574                     width:{from:b.width, to:(b.width + (20*scale))}
10575                 }, duration, function(){
10576                     proxy.remove();
10577                 });
10578                 if(--count > 0){
10579                      animFn.defer((duration/2)*1000, this);
10580                 }else{
10581                     el.afterFx(o);
10582                 }
10583             };
10584             animFn.call(this);
10585         });
10586         return this;
10587     },
10588
10589    /**
10590     * Creates a pause before any subsequent queued effects begin.  If there are
10591     * no effects queued after the pause it will have no effect.
10592     * Usage:
10593 <pre><code>
10594 el.pause(1);
10595 </code></pre>
10596     * @param {Number} seconds The length of time to pause (in seconds)
10597     * @return {Roo.Element} The Element
10598     */
10599     pause : function(seconds){
10600         var el = this.getFxEl();
10601         var o = {};
10602
10603         el.queueFx(o, function(){
10604             setTimeout(function(){
10605                 el.afterFx(o);
10606             }, seconds * 1000);
10607         });
10608         return this;
10609     },
10610
10611    /**
10612     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10613     * using the "endOpacity" config option.
10614     * Usage:
10615 <pre><code>
10616 // default: fade in from opacity 0 to 100%
10617 el.fadeIn();
10618
10619 // custom: fade in from opacity 0 to 75% over 2 seconds
10620 el.fadeIn({ endOpacity: .75, duration: 2});
10621
10622 // common config options shown with default values
10623 el.fadeIn({
10624     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10625     easing: 'easeOut',
10626     duration: .5
10627 });
10628 </code></pre>
10629     * @param {Object} options (optional) Object literal with any of the Fx config options
10630     * @return {Roo.Element} The Element
10631     */
10632     fadeIn : function(o){
10633         var el = this.getFxEl();
10634         o = o || {};
10635         el.queueFx(o, function(){
10636             this.setOpacity(0);
10637             this.fixDisplay();
10638             this.dom.style.visibility = 'visible';
10639             var to = o.endOpacity || 1;
10640             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10641                 o, null, .5, "easeOut", function(){
10642                 if(to == 1){
10643                     this.clearOpacity();
10644                 }
10645                 el.afterFx(o);
10646             });
10647         });
10648         return this;
10649     },
10650
10651    /**
10652     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10653     * using the "endOpacity" config option.
10654     * Usage:
10655 <pre><code>
10656 // default: fade out from the element's current opacity to 0
10657 el.fadeOut();
10658
10659 // custom: fade out from the element's current opacity to 25% over 2 seconds
10660 el.fadeOut({ endOpacity: .25, duration: 2});
10661
10662 // common config options shown with default values
10663 el.fadeOut({
10664     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10665     easing: 'easeOut',
10666     duration: .5
10667     remove: false,
10668     useDisplay: false
10669 });
10670 </code></pre>
10671     * @param {Object} options (optional) Object literal with any of the Fx config options
10672     * @return {Roo.Element} The Element
10673     */
10674     fadeOut : function(o){
10675         var el = this.getFxEl();
10676         o = o || {};
10677         el.queueFx(o, function(){
10678             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10679                 o, null, .5, "easeOut", function(){
10680                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10681                      this.dom.style.display = "none";
10682                 }else{
10683                      this.dom.style.visibility = "hidden";
10684                 }
10685                 this.clearOpacity();
10686                 el.afterFx(o);
10687             });
10688         });
10689         return this;
10690     },
10691
10692    /**
10693     * Animates the transition of an element's dimensions from a starting height/width
10694     * to an ending height/width.
10695     * Usage:
10696 <pre><code>
10697 // change height and width to 100x100 pixels
10698 el.scale(100, 100);
10699
10700 // common config options shown with default values.  The height and width will default to
10701 // the element's existing values if passed as null.
10702 el.scale(
10703     [element's width],
10704     [element's height], {
10705     easing: 'easeOut',
10706     duration: .35
10707 });
10708 </code></pre>
10709     * @param {Number} width  The new width (pass undefined to keep the original width)
10710     * @param {Number} height  The new height (pass undefined to keep the original height)
10711     * @param {Object} options (optional) Object literal with any of the Fx config options
10712     * @return {Roo.Element} The Element
10713     */
10714     scale : function(w, h, o){
10715         this.shift(Roo.apply({}, o, {
10716             width: w,
10717             height: h
10718         }));
10719         return this;
10720     },
10721
10722    /**
10723     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10724     * Any of these properties not specified in the config object will not be changed.  This effect 
10725     * requires that at least one new dimension, position or opacity setting must be passed in on
10726     * the config object in order for the function to have any effect.
10727     * Usage:
10728 <pre><code>
10729 // slide the element horizontally to x position 200 while changing the height and opacity
10730 el.shift({ x: 200, height: 50, opacity: .8 });
10731
10732 // common config options shown with default values.
10733 el.shift({
10734     width: [element's width],
10735     height: [element's height],
10736     x: [element's x position],
10737     y: [element's y position],
10738     opacity: [element's opacity],
10739     easing: 'easeOut',
10740     duration: .35
10741 });
10742 </code></pre>
10743     * @param {Object} options  Object literal with any of the Fx config options
10744     * @return {Roo.Element} The Element
10745     */
10746     shift : function(o){
10747         var el = this.getFxEl();
10748         o = o || {};
10749         el.queueFx(o, function(){
10750             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10751             if(w !== undefined){
10752                 a.width = {to: this.adjustWidth(w)};
10753             }
10754             if(h !== undefined){
10755                 a.height = {to: this.adjustHeight(h)};
10756             }
10757             if(x !== undefined || y !== undefined){
10758                 a.points = {to: [
10759                     x !== undefined ? x : this.getX(),
10760                     y !== undefined ? y : this.getY()
10761                 ]};
10762             }
10763             if(op !== undefined){
10764                 a.opacity = {to: op};
10765             }
10766             if(o.xy !== undefined){
10767                 a.points = {to: o.xy};
10768             }
10769             arguments.callee.anim = this.fxanim(a,
10770                 o, 'motion', .35, "easeOut", function(){
10771                 el.afterFx(o);
10772             });
10773         });
10774         return this;
10775     },
10776
10777         /**
10778          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10779          * ending point of the effect.
10780          * Usage:
10781          *<pre><code>
10782 // default: slide the element downward while fading out
10783 el.ghost();
10784
10785 // custom: slide the element out to the right with a 2-second duration
10786 el.ghost('r', { duration: 2 });
10787
10788 // common config options shown with default values
10789 el.ghost('b', {
10790     easing: 'easeOut',
10791     duration: .5
10792     remove: false,
10793     useDisplay: false
10794 });
10795 </code></pre>
10796          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10797          * @param {Object} options (optional) Object literal with any of the Fx config options
10798          * @return {Roo.Element} The Element
10799          */
10800     ghost : function(anchor, o){
10801         var el = this.getFxEl();
10802         o = o || {};
10803
10804         el.queueFx(o, function(){
10805             anchor = anchor || "b";
10806
10807             // restore values after effect
10808             var r = this.getFxRestore();
10809             var w = this.getWidth(),
10810                 h = this.getHeight();
10811
10812             var st = this.dom.style;
10813
10814             var after = function(){
10815                 if(o.useDisplay){
10816                     el.setDisplayed(false);
10817                 }else{
10818                     el.hide();
10819                 }
10820
10821                 el.clearOpacity();
10822                 el.setPositioning(r.pos);
10823                 st.width = r.width;
10824                 st.height = r.height;
10825
10826                 el.afterFx(o);
10827             };
10828
10829             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10830             switch(anchor.toLowerCase()){
10831                 case "t":
10832                     pt.by = [0, -h];
10833                 break;
10834                 case "l":
10835                     pt.by = [-w, 0];
10836                 break;
10837                 case "r":
10838                     pt.by = [w, 0];
10839                 break;
10840                 case "b":
10841                     pt.by = [0, h];
10842                 break;
10843                 case "tl":
10844                     pt.by = [-w, -h];
10845                 break;
10846                 case "bl":
10847                     pt.by = [-w, h];
10848                 break;
10849                 case "br":
10850                     pt.by = [w, h];
10851                 break;
10852                 case "tr":
10853                     pt.by = [w, -h];
10854                 break;
10855             }
10856
10857             arguments.callee.anim = this.fxanim(a,
10858                 o,
10859                 'motion',
10860                 .5,
10861                 "easeOut", after);
10862         });
10863         return this;
10864     },
10865
10866         /**
10867          * Ensures that all effects queued after syncFx is called on the element are
10868          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10869          * @return {Roo.Element} The Element
10870          */
10871     syncFx : function(){
10872         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10873             block : false,
10874             concurrent : true,
10875             stopFx : false
10876         });
10877         return this;
10878     },
10879
10880         /**
10881          * Ensures that all effects queued after sequenceFx is called on the element are
10882          * run in sequence.  This is the opposite of {@link #syncFx}.
10883          * @return {Roo.Element} The Element
10884          */
10885     sequenceFx : function(){
10886         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10887             block : false,
10888             concurrent : false,
10889             stopFx : false
10890         });
10891         return this;
10892     },
10893
10894         /* @private */
10895     nextFx : function(){
10896         var ef = this.fxQueue[0];
10897         if(ef){
10898             ef.call(this);
10899         }
10900     },
10901
10902         /**
10903          * Returns true if the element has any effects actively running or queued, else returns false.
10904          * @return {Boolean} True if element has active effects, else false
10905          */
10906     hasActiveFx : function(){
10907         return this.fxQueue && this.fxQueue[0];
10908     },
10909
10910         /**
10911          * Stops any running effects and clears the element's internal effects queue if it contains
10912          * any additional effects that haven't started yet.
10913          * @return {Roo.Element} The Element
10914          */
10915     stopFx : function(){
10916         if(this.hasActiveFx()){
10917             var cur = this.fxQueue[0];
10918             if(cur && cur.anim && cur.anim.isAnimated()){
10919                 this.fxQueue = [cur]; // clear out others
10920                 cur.anim.stop(true);
10921             }
10922         }
10923         return this;
10924     },
10925
10926         /* @private */
10927     beforeFx : function(o){
10928         if(this.hasActiveFx() && !o.concurrent){
10929            if(o.stopFx){
10930                this.stopFx();
10931                return true;
10932            }
10933            return false;
10934         }
10935         return true;
10936     },
10937
10938         /**
10939          * Returns true if the element is currently blocking so that no other effect can be queued
10940          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10941          * used to ensure that an effect initiated by a user action runs to completion prior to the
10942          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10943          * @return {Boolean} True if blocking, else false
10944          */
10945     hasFxBlock : function(){
10946         var q = this.fxQueue;
10947         return q && q[0] && q[0].block;
10948     },
10949
10950         /* @private */
10951     queueFx : function(o, fn){
10952         if(!this.fxQueue){
10953             this.fxQueue = [];
10954         }
10955         if(!this.hasFxBlock()){
10956             Roo.applyIf(o, this.fxDefaults);
10957             if(!o.concurrent){
10958                 var run = this.beforeFx(o);
10959                 fn.block = o.block;
10960                 this.fxQueue.push(fn);
10961                 if(run){
10962                     this.nextFx();
10963                 }
10964             }else{
10965                 fn.call(this);
10966             }
10967         }
10968         return this;
10969     },
10970
10971         /* @private */
10972     fxWrap : function(pos, o, vis){
10973         var wrap;
10974         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10975             var wrapXY;
10976             if(o.fixPosition){
10977                 wrapXY = this.getXY();
10978             }
10979             var div = document.createElement("div");
10980             div.style.visibility = vis;
10981             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10982             wrap.setPositioning(pos);
10983             if(wrap.getStyle("position") == "static"){
10984                 wrap.position("relative");
10985             }
10986             this.clearPositioning('auto');
10987             wrap.clip();
10988             wrap.dom.appendChild(this.dom);
10989             if(wrapXY){
10990                 wrap.setXY(wrapXY);
10991             }
10992         }
10993         return wrap;
10994     },
10995
10996         /* @private */
10997     fxUnwrap : function(wrap, pos, o){
10998         this.clearPositioning();
10999         this.setPositioning(pos);
11000         if(!o.wrap){
11001             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11002             wrap.remove();
11003         }
11004     },
11005
11006         /* @private */
11007     getFxRestore : function(){
11008         var st = this.dom.style;
11009         return {pos: this.getPositioning(), width: st.width, height : st.height};
11010     },
11011
11012         /* @private */
11013     afterFx : function(o){
11014         if(o.afterStyle){
11015             this.applyStyles(o.afterStyle);
11016         }
11017         if(o.afterCls){
11018             this.addClass(o.afterCls);
11019         }
11020         if(o.remove === true){
11021             this.remove();
11022         }
11023         Roo.callback(o.callback, o.scope, [this]);
11024         if(!o.concurrent){
11025             this.fxQueue.shift();
11026             this.nextFx();
11027         }
11028     },
11029
11030         /* @private */
11031     getFxEl : function(){ // support for composite element fx
11032         return Roo.get(this.dom);
11033     },
11034
11035         /* @private */
11036     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11037         animType = animType || 'run';
11038         opt = opt || {};
11039         var anim = Roo.lib.Anim[animType](
11040             this.dom, args,
11041             (opt.duration || defaultDur) || .35,
11042             (opt.easing || defaultEase) || 'easeOut',
11043             function(){
11044                 Roo.callback(cb, this);
11045             },
11046             this
11047         );
11048         opt.anim = anim;
11049         return anim;
11050     }
11051 };
11052
11053 // backwords compat
11054 Roo.Fx.resize = Roo.Fx.scale;
11055
11056 //When included, Roo.Fx is automatically applied to Element so that all basic
11057 //effects are available directly via the Element API
11058 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11059  * Based on:
11060  * Ext JS Library 1.1.1
11061  * Copyright(c) 2006-2007, Ext JS, LLC.
11062  *
11063  * Originally Released Under LGPL - original licence link has changed is not relivant.
11064  *
11065  * Fork - LGPL
11066  * <script type="text/javascript">
11067  */
11068
11069
11070 /**
11071  * @class Roo.CompositeElement
11072  * Standard composite class. Creates a Roo.Element for every element in the collection.
11073  * <br><br>
11074  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11075  * actions will be performed on all the elements in this collection.</b>
11076  * <br><br>
11077  * All methods return <i>this</i> and can be chained.
11078  <pre><code>
11079  var els = Roo.select("#some-el div.some-class", true);
11080  // or select directly from an existing element
11081  var el = Roo.get('some-el');
11082  el.select('div.some-class', true);
11083
11084  els.setWidth(100); // all elements become 100 width
11085  els.hide(true); // all elements fade out and hide
11086  // or
11087  els.setWidth(100).hide(true);
11088  </code></pre>
11089  */
11090 Roo.CompositeElement = function(els){
11091     this.elements = [];
11092     this.addElements(els);
11093 };
11094 Roo.CompositeElement.prototype = {
11095     isComposite: true,
11096     addElements : function(els){
11097         if(!els) {
11098             return this;
11099         }
11100         if(typeof els == "string"){
11101             els = Roo.Element.selectorFunction(els);
11102         }
11103         var yels = this.elements;
11104         var index = yels.length-1;
11105         for(var i = 0, len = els.length; i < len; i++) {
11106                 yels[++index] = Roo.get(els[i]);
11107         }
11108         return this;
11109     },
11110
11111     /**
11112     * Clears this composite and adds the elements returned by the passed selector.
11113     * @param {String/Array} els A string CSS selector, an array of elements or an element
11114     * @return {CompositeElement} this
11115     */
11116     fill : function(els){
11117         this.elements = [];
11118         this.add(els);
11119         return this;
11120     },
11121
11122     /**
11123     * Filters this composite to only elements that match the passed selector.
11124     * @param {String} selector A string CSS selector
11125     * @param {Boolean} inverse return inverse filter (not matches)
11126     * @return {CompositeElement} this
11127     */
11128     filter : function(selector, inverse){
11129         var els = [];
11130         inverse = inverse || false;
11131         this.each(function(el){
11132             var match = inverse ? !el.is(selector) : el.is(selector);
11133             if(match){
11134                 els[els.length] = el.dom;
11135             }
11136         });
11137         this.fill(els);
11138         return this;
11139     },
11140
11141     invoke : function(fn, args){
11142         var els = this.elements;
11143         for(var i = 0, len = els.length; i < len; i++) {
11144                 Roo.Element.prototype[fn].apply(els[i], args);
11145         }
11146         return this;
11147     },
11148     /**
11149     * Adds elements to this composite.
11150     * @param {String/Array} els A string CSS selector, an array of elements or an element
11151     * @return {CompositeElement} this
11152     */
11153     add : function(els){
11154         if(typeof els == "string"){
11155             this.addElements(Roo.Element.selectorFunction(els));
11156         }else if(els.length !== undefined){
11157             this.addElements(els);
11158         }else{
11159             this.addElements([els]);
11160         }
11161         return this;
11162     },
11163     /**
11164     * Calls the passed function passing (el, this, index) for each element in this composite.
11165     * @param {Function} fn The function to call
11166     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11167     * @return {CompositeElement} this
11168     */
11169     each : function(fn, scope){
11170         var els = this.elements;
11171         for(var i = 0, len = els.length; i < len; i++){
11172             if(fn.call(scope || els[i], els[i], this, i) === false) {
11173                 break;
11174             }
11175         }
11176         return this;
11177     },
11178
11179     /**
11180      * Returns the Element object at the specified index
11181      * @param {Number} index
11182      * @return {Roo.Element}
11183      */
11184     item : function(index){
11185         return this.elements[index] || null;
11186     },
11187
11188     /**
11189      * Returns the first Element
11190      * @return {Roo.Element}
11191      */
11192     first : function(){
11193         return this.item(0);
11194     },
11195
11196     /**
11197      * Returns the last Element
11198      * @return {Roo.Element}
11199      */
11200     last : function(){
11201         return this.item(this.elements.length-1);
11202     },
11203
11204     /**
11205      * Returns the number of elements in this composite
11206      * @return Number
11207      */
11208     getCount : function(){
11209         return this.elements.length;
11210     },
11211
11212     /**
11213      * Returns true if this composite contains the passed element
11214      * @return Boolean
11215      */
11216     contains : function(el){
11217         return this.indexOf(el) !== -1;
11218     },
11219
11220     /**
11221      * Returns true if this composite contains the passed element
11222      * @return Boolean
11223      */
11224     indexOf : function(el){
11225         return this.elements.indexOf(Roo.get(el));
11226     },
11227
11228
11229     /**
11230     * Removes the specified element(s).
11231     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11232     * or an array of any of those.
11233     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11234     * @return {CompositeElement} this
11235     */
11236     removeElement : function(el, removeDom){
11237         if(el instanceof Array){
11238             for(var i = 0, len = el.length; i < len; i++){
11239                 this.removeElement(el[i]);
11240             }
11241             return this;
11242         }
11243         var index = typeof el == 'number' ? el : this.indexOf(el);
11244         if(index !== -1){
11245             if(removeDom){
11246                 var d = this.elements[index];
11247                 if(d.dom){
11248                     d.remove();
11249                 }else{
11250                     d.parentNode.removeChild(d);
11251                 }
11252             }
11253             this.elements.splice(index, 1);
11254         }
11255         return this;
11256     },
11257
11258     /**
11259     * Replaces the specified element with the passed element.
11260     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11261     * to replace.
11262     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11263     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11264     * @return {CompositeElement} this
11265     */
11266     replaceElement : function(el, replacement, domReplace){
11267         var index = typeof el == 'number' ? el : this.indexOf(el);
11268         if(index !== -1){
11269             if(domReplace){
11270                 this.elements[index].replaceWith(replacement);
11271             }else{
11272                 this.elements.splice(index, 1, Roo.get(replacement))
11273             }
11274         }
11275         return this;
11276     },
11277
11278     /**
11279      * Removes all elements.
11280      */
11281     clear : function(){
11282         this.elements = [];
11283     }
11284 };
11285 (function(){
11286     Roo.CompositeElement.createCall = function(proto, fnName){
11287         if(!proto[fnName]){
11288             proto[fnName] = function(){
11289                 return this.invoke(fnName, arguments);
11290             };
11291         }
11292     };
11293     for(var fnName in Roo.Element.prototype){
11294         if(typeof Roo.Element.prototype[fnName] == "function"){
11295             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11296         }
11297     };
11298 })();
11299 /*
11300  * Based on:
11301  * Ext JS Library 1.1.1
11302  * Copyright(c) 2006-2007, Ext JS, LLC.
11303  *
11304  * Originally Released Under LGPL - original licence link has changed is not relivant.
11305  *
11306  * Fork - LGPL
11307  * <script type="text/javascript">
11308  */
11309
11310 /**
11311  * @class Roo.CompositeElementLite
11312  * @extends Roo.CompositeElement
11313  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11314  <pre><code>
11315  var els = Roo.select("#some-el div.some-class");
11316  // or select directly from an existing element
11317  var el = Roo.get('some-el');
11318  el.select('div.some-class');
11319
11320  els.setWidth(100); // all elements become 100 width
11321  els.hide(true); // all elements fade out and hide
11322  // or
11323  els.setWidth(100).hide(true);
11324  </code></pre><br><br>
11325  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11326  * actions will be performed on all the elements in this collection.</b>
11327  */
11328 Roo.CompositeElementLite = function(els){
11329     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11330     this.el = new Roo.Element.Flyweight();
11331 };
11332 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11333     addElements : function(els){
11334         if(els){
11335             if(els instanceof Array){
11336                 this.elements = this.elements.concat(els);
11337             }else{
11338                 var yels = this.elements;
11339                 var index = yels.length-1;
11340                 for(var i = 0, len = els.length; i < len; i++) {
11341                     yels[++index] = els[i];
11342                 }
11343             }
11344         }
11345         return this;
11346     },
11347     invoke : function(fn, args){
11348         var els = this.elements;
11349         var el = this.el;
11350         for(var i = 0, len = els.length; i < len; i++) {
11351             el.dom = els[i];
11352                 Roo.Element.prototype[fn].apply(el, args);
11353         }
11354         return this;
11355     },
11356     /**
11357      * Returns a flyweight Element of the dom element object at the specified index
11358      * @param {Number} index
11359      * @return {Roo.Element}
11360      */
11361     item : function(index){
11362         if(!this.elements[index]){
11363             return null;
11364         }
11365         this.el.dom = this.elements[index];
11366         return this.el;
11367     },
11368
11369     // fixes scope with flyweight
11370     addListener : function(eventName, handler, scope, opt){
11371         var els = this.elements;
11372         for(var i = 0, len = els.length; i < len; i++) {
11373             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11374         }
11375         return this;
11376     },
11377
11378     /**
11379     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11380     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11381     * a reference to the dom node, use el.dom.</b>
11382     * @param {Function} fn The function to call
11383     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11384     * @return {CompositeElement} this
11385     */
11386     each : function(fn, scope){
11387         var els = this.elements;
11388         var el = this.el;
11389         for(var i = 0, len = els.length; i < len; i++){
11390             el.dom = els[i];
11391                 if(fn.call(scope || el, el, this, i) === false){
11392                 break;
11393             }
11394         }
11395         return this;
11396     },
11397
11398     indexOf : function(el){
11399         return this.elements.indexOf(Roo.getDom(el));
11400     },
11401
11402     replaceElement : function(el, replacement, domReplace){
11403         var index = typeof el == 'number' ? el : this.indexOf(el);
11404         if(index !== -1){
11405             replacement = Roo.getDom(replacement);
11406             if(domReplace){
11407                 var d = this.elements[index];
11408                 d.parentNode.insertBefore(replacement, d);
11409                 d.parentNode.removeChild(d);
11410             }
11411             this.elements.splice(index, 1, replacement);
11412         }
11413         return this;
11414     }
11415 });
11416 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11417
11418 /*
11419  * Based on:
11420  * Ext JS Library 1.1.1
11421  * Copyright(c) 2006-2007, Ext JS, LLC.
11422  *
11423  * Originally Released Under LGPL - original licence link has changed is not relivant.
11424  *
11425  * Fork - LGPL
11426  * <script type="text/javascript">
11427  */
11428
11429  
11430
11431 /**
11432  * @class Roo.data.Connection
11433  * @extends Roo.util.Observable
11434  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11435  * either to a configured URL, or to a URL specified at request time.<br><br>
11436  * <p>
11437  * Requests made by this class are asynchronous, and will return immediately. No data from
11438  * the server will be available to the statement immediately following the {@link #request} call.
11439  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11440  * <p>
11441  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11442  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11443  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11444  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11445  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11446  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11447  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11448  * standard DOM methods.
11449  * @constructor
11450  * @param {Object} config a configuration object.
11451  */
11452 Roo.data.Connection = function(config){
11453     Roo.apply(this, config);
11454     this.addEvents({
11455         /**
11456          * @event beforerequest
11457          * Fires before a network request is made to retrieve a data object.
11458          * @param {Connection} conn This Connection object.
11459          * @param {Object} options The options config object passed to the {@link #request} method.
11460          */
11461         "beforerequest" : true,
11462         /**
11463          * @event requestcomplete
11464          * Fires if the request was successfully completed.
11465          * @param {Connection} conn This Connection object.
11466          * @param {Object} response The XHR object containing the response data.
11467          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11468          * @param {Object} options The options config object passed to the {@link #request} method.
11469          */
11470         "requestcomplete" : true,
11471         /**
11472          * @event requestexception
11473          * Fires if an error HTTP status was returned from the server.
11474          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11475          * @param {Connection} conn This Connection object.
11476          * @param {Object} response The XHR object containing the response data.
11477          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11478          * @param {Object} options The options config object passed to the {@link #request} method.
11479          */
11480         "requestexception" : true
11481     });
11482     Roo.data.Connection.superclass.constructor.call(this);
11483 };
11484
11485 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11486     /**
11487      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11488      */
11489     /**
11490      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11491      * extra parameters to each request made by this object. (defaults to undefined)
11492      */
11493     /**
11494      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11495      *  to each request made by this object. (defaults to undefined)
11496      */
11497     /**
11498      * @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)
11499      */
11500     /**
11501      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11502      */
11503     timeout : 30000,
11504     /**
11505      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11506      * @type Boolean
11507      */
11508     autoAbort:false,
11509
11510     /**
11511      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11512      * @type Boolean
11513      */
11514     disableCaching: true,
11515
11516     /**
11517      * Sends an HTTP request to a remote server.
11518      * @param {Object} options An object which may contain the following properties:<ul>
11519      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11520      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11521      * request, a url encoded string or a function to call to get either.</li>
11522      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11523      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11524      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11525      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11526      * <li>options {Object} The parameter to the request call.</li>
11527      * <li>success {Boolean} True if the request succeeded.</li>
11528      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11529      * </ul></li>
11530      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11531      * The callback is passed the following parameters:<ul>
11532      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11533      * <li>options {Object} The parameter to the request call.</li>
11534      * </ul></li>
11535      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11536      * The callback is passed the following parameters:<ul>
11537      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11538      * <li>options {Object} The parameter to the request call.</li>
11539      * </ul></li>
11540      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11541      * for the callback function. Defaults to the browser window.</li>
11542      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11543      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11544      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11545      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11546      * params for the post data. Any params will be appended to the URL.</li>
11547      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11548      * </ul>
11549      * @return {Number} transactionId
11550      */
11551     request : function(o){
11552         if(this.fireEvent("beforerequest", this, o) !== false){
11553             var p = o.params;
11554
11555             if(typeof p == "function"){
11556                 p = p.call(o.scope||window, o);
11557             }
11558             if(typeof p == "object"){
11559                 p = Roo.urlEncode(o.params);
11560             }
11561             if(this.extraParams){
11562                 var extras = Roo.urlEncode(this.extraParams);
11563                 p = p ? (p + '&' + extras) : extras;
11564             }
11565
11566             var url = o.url || this.url;
11567             if(typeof url == 'function'){
11568                 url = url.call(o.scope||window, o);
11569             }
11570
11571             if(o.form){
11572                 var form = Roo.getDom(o.form);
11573                 url = url || form.action;
11574
11575                 var enctype = form.getAttribute("enctype");
11576                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11577                     return this.doFormUpload(o, p, url);
11578                 }
11579                 var f = Roo.lib.Ajax.serializeForm(form);
11580                 p = p ? (p + '&' + f) : f;
11581             }
11582
11583             var hs = o.headers;
11584             if(this.defaultHeaders){
11585                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11586                 if(!o.headers){
11587                     o.headers = hs;
11588                 }
11589             }
11590
11591             var cb = {
11592                 success: this.handleResponse,
11593                 failure: this.handleFailure,
11594                 scope: this,
11595                 argument: {options: o},
11596                 timeout : o.timeout || this.timeout
11597             };
11598
11599             var method = o.method||this.method||(p ? "POST" : "GET");
11600
11601             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11602                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11603             }
11604
11605             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11606                 if(o.autoAbort){
11607                     this.abort();
11608                 }
11609             }else if(this.autoAbort !== false){
11610                 this.abort();
11611             }
11612
11613             if((method == 'GET' && p) || o.xmlData){
11614                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11615                 p = '';
11616             }
11617             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11618             return this.transId;
11619         }else{
11620             Roo.callback(o.callback, o.scope, [o, null, null]);
11621             return null;
11622         }
11623     },
11624
11625     /**
11626      * Determine whether this object has a request outstanding.
11627      * @param {Number} transactionId (Optional) defaults to the last transaction
11628      * @return {Boolean} True if there is an outstanding request.
11629      */
11630     isLoading : function(transId){
11631         if(transId){
11632             return Roo.lib.Ajax.isCallInProgress(transId);
11633         }else{
11634             return this.transId ? true : false;
11635         }
11636     },
11637
11638     /**
11639      * Aborts any outstanding request.
11640      * @param {Number} transactionId (Optional) defaults to the last transaction
11641      */
11642     abort : function(transId){
11643         if(transId || this.isLoading()){
11644             Roo.lib.Ajax.abort(transId || this.transId);
11645         }
11646     },
11647
11648     // private
11649     handleResponse : function(response){
11650         this.transId = false;
11651         var options = response.argument.options;
11652         response.argument = options ? options.argument : null;
11653         this.fireEvent("requestcomplete", this, response, options);
11654         Roo.callback(options.success, options.scope, [response, options]);
11655         Roo.callback(options.callback, options.scope, [options, true, response]);
11656     },
11657
11658     // private
11659     handleFailure : function(response, e){
11660         this.transId = false;
11661         var options = response.argument.options;
11662         response.argument = options ? options.argument : null;
11663         this.fireEvent("requestexception", this, response, options, e);
11664         Roo.callback(options.failure, options.scope, [response, options]);
11665         Roo.callback(options.callback, options.scope, [options, false, response]);
11666     },
11667
11668     // private
11669     doFormUpload : function(o, ps, url){
11670         var id = Roo.id();
11671         var frame = document.createElement('iframe');
11672         frame.id = id;
11673         frame.name = id;
11674         frame.className = 'x-hidden';
11675         if(Roo.isIE){
11676             frame.src = Roo.SSL_SECURE_URL;
11677         }
11678         document.body.appendChild(frame);
11679
11680         if(Roo.isIE){
11681            document.frames[id].name = id;
11682         }
11683
11684         var form = Roo.getDom(o.form);
11685         form.target = id;
11686         form.method = 'POST';
11687         form.enctype = form.encoding = 'multipart/form-data';
11688         if(url){
11689             form.action = url;
11690         }
11691
11692         var hiddens, hd;
11693         if(ps){ // add dynamic params
11694             hiddens = [];
11695             ps = Roo.urlDecode(ps, false);
11696             for(var k in ps){
11697                 if(ps.hasOwnProperty(k)){
11698                     hd = document.createElement('input');
11699                     hd.type = 'hidden';
11700                     hd.name = k;
11701                     hd.value = ps[k];
11702                     form.appendChild(hd);
11703                     hiddens.push(hd);
11704                 }
11705             }
11706         }
11707
11708         function cb(){
11709             var r = {  // bogus response object
11710                 responseText : '',
11711                 responseXML : null
11712             };
11713
11714             r.argument = o ? o.argument : null;
11715
11716             try { //
11717                 var doc;
11718                 if(Roo.isIE){
11719                     doc = frame.contentWindow.document;
11720                 }else {
11721                     doc = (frame.contentDocument || window.frames[id].document);
11722                 }
11723                 if(doc && doc.body){
11724                     r.responseText = doc.body.innerHTML;
11725                 }
11726                 if(doc && doc.XMLDocument){
11727                     r.responseXML = doc.XMLDocument;
11728                 }else {
11729                     r.responseXML = doc;
11730                 }
11731             }
11732             catch(e) {
11733                 // ignore
11734             }
11735
11736             Roo.EventManager.removeListener(frame, 'load', cb, this);
11737
11738             this.fireEvent("requestcomplete", this, r, o);
11739             Roo.callback(o.success, o.scope, [r, o]);
11740             Roo.callback(o.callback, o.scope, [o, true, r]);
11741
11742             setTimeout(function(){document.body.removeChild(frame);}, 100);
11743         }
11744
11745         Roo.EventManager.on(frame, 'load', cb, this);
11746         form.submit();
11747
11748         if(hiddens){ // remove dynamic params
11749             for(var i = 0, len = hiddens.length; i < len; i++){
11750                 form.removeChild(hiddens[i]);
11751             }
11752         }
11753     }
11754 });
11755 /*
11756  * Based on:
11757  * Ext JS Library 1.1.1
11758  * Copyright(c) 2006-2007, Ext JS, LLC.
11759  *
11760  * Originally Released Under LGPL - original licence link has changed is not relivant.
11761  *
11762  * Fork - LGPL
11763  * <script type="text/javascript">
11764  */
11765  
11766 /**
11767  * Global Ajax request class.
11768  * 
11769  * @class Roo.Ajax
11770  * @extends Roo.data.Connection
11771  * @static
11772  * 
11773  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11774  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11775  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11776  * @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)
11777  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11778  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11779  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11780  */
11781 Roo.Ajax = new Roo.data.Connection({
11782     // fix up the docs
11783     /**
11784      * @scope Roo.Ajax
11785      * @type {Boolear} 
11786      */
11787     autoAbort : false,
11788
11789     /**
11790      * Serialize the passed form into a url encoded string
11791      * @scope Roo.Ajax
11792      * @param {String/HTMLElement} form
11793      * @return {String}
11794      */
11795     serializeForm : function(form){
11796         return Roo.lib.Ajax.serializeForm(form);
11797     }
11798 });/*
11799  * Based on:
11800  * Ext JS Library 1.1.1
11801  * Copyright(c) 2006-2007, Ext JS, LLC.
11802  *
11803  * Originally Released Under LGPL - original licence link has changed is not relivant.
11804  *
11805  * Fork - LGPL
11806  * <script type="text/javascript">
11807  */
11808
11809  
11810 /**
11811  * @class Roo.UpdateManager
11812  * @extends Roo.util.Observable
11813  * Provides AJAX-style update for Element object.<br><br>
11814  * Usage:<br>
11815  * <pre><code>
11816  * // Get it from a Roo.Element object
11817  * var el = Roo.get("foo");
11818  * var mgr = el.getUpdateManager();
11819  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11820  * ...
11821  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11822  * <br>
11823  * // or directly (returns the same UpdateManager instance)
11824  * var mgr = new Roo.UpdateManager("myElementId");
11825  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11826  * mgr.on("update", myFcnNeedsToKnow);
11827  * <br>
11828    // short handed call directly from the element object
11829    Roo.get("foo").load({
11830         url: "bar.php",
11831         scripts:true,
11832         params: "for=bar",
11833         text: "Loading Foo..."
11834    });
11835  * </code></pre>
11836  * @constructor
11837  * Create new UpdateManager directly.
11838  * @param {String/HTMLElement/Roo.Element} el The element to update
11839  * @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).
11840  */
11841 Roo.UpdateManager = function(el, forceNew){
11842     el = Roo.get(el);
11843     if(!forceNew && el.updateManager){
11844         return el.updateManager;
11845     }
11846     /**
11847      * The Element object
11848      * @type Roo.Element
11849      */
11850     this.el = el;
11851     /**
11852      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11853      * @type String
11854      */
11855     this.defaultUrl = null;
11856
11857     this.addEvents({
11858         /**
11859          * @event beforeupdate
11860          * Fired before an update is made, return false from your handler and the update is cancelled.
11861          * @param {Roo.Element} el
11862          * @param {String/Object/Function} url
11863          * @param {String/Object} params
11864          */
11865         "beforeupdate": true,
11866         /**
11867          * @event update
11868          * Fired after successful update is made.
11869          * @param {Roo.Element} el
11870          * @param {Object} oResponseObject The response Object
11871          */
11872         "update": true,
11873         /**
11874          * @event failure
11875          * Fired on update failure.
11876          * @param {Roo.Element} el
11877          * @param {Object} oResponseObject The response Object
11878          */
11879         "failure": true
11880     });
11881     var d = Roo.UpdateManager.defaults;
11882     /**
11883      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11884      * @type String
11885      */
11886     this.sslBlankUrl = d.sslBlankUrl;
11887     /**
11888      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11889      * @type Boolean
11890      */
11891     this.disableCaching = d.disableCaching;
11892     /**
11893      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11894      * @type String
11895      */
11896     this.indicatorText = d.indicatorText;
11897     /**
11898      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11899      * @type String
11900      */
11901     this.showLoadIndicator = d.showLoadIndicator;
11902     /**
11903      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11904      * @type Number
11905      */
11906     this.timeout = d.timeout;
11907
11908     /**
11909      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11910      * @type Boolean
11911      */
11912     this.loadScripts = d.loadScripts;
11913
11914     /**
11915      * Transaction object of current executing transaction
11916      */
11917     this.transaction = null;
11918
11919     /**
11920      * @private
11921      */
11922     this.autoRefreshProcId = null;
11923     /**
11924      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11925      * @type Function
11926      */
11927     this.refreshDelegate = this.refresh.createDelegate(this);
11928     /**
11929      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11930      * @type Function
11931      */
11932     this.updateDelegate = this.update.createDelegate(this);
11933     /**
11934      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11935      * @type Function
11936      */
11937     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11938     /**
11939      * @private
11940      */
11941     this.successDelegate = this.processSuccess.createDelegate(this);
11942     /**
11943      * @private
11944      */
11945     this.failureDelegate = this.processFailure.createDelegate(this);
11946
11947     if(!this.renderer){
11948      /**
11949       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11950       */
11951     this.renderer = new Roo.UpdateManager.BasicRenderer();
11952     }
11953     
11954     Roo.UpdateManager.superclass.constructor.call(this);
11955 };
11956
11957 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11958     /**
11959      * Get the Element this UpdateManager is bound to
11960      * @return {Roo.Element} The element
11961      */
11962     getEl : function(){
11963         return this.el;
11964     },
11965     /**
11966      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11967      * @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:
11968 <pre><code>
11969 um.update({<br/>
11970     url: "your-url.php",<br/>
11971     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11972     callback: yourFunction,<br/>
11973     scope: yourObject, //(optional scope)  <br/>
11974     discardUrl: false, <br/>
11975     nocache: false,<br/>
11976     text: "Loading...",<br/>
11977     timeout: 30,<br/>
11978     scripts: false<br/>
11979 });
11980 </code></pre>
11981      * The only required property is url. The optional properties nocache, text and scripts
11982      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11983      * @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}
11984      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11985      * @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.
11986      */
11987     update : function(url, params, callback, discardUrl){
11988         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11989             var method = this.method,
11990                 cfg;
11991             if(typeof url == "object"){ // must be config object
11992                 cfg = url;
11993                 url = cfg.url;
11994                 params = params || cfg.params;
11995                 callback = callback || cfg.callback;
11996                 discardUrl = discardUrl || cfg.discardUrl;
11997                 if(callback && cfg.scope){
11998                     callback = callback.createDelegate(cfg.scope);
11999                 }
12000                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12001                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12002                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12003                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12004                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12005             }
12006             this.showLoading();
12007             if(!discardUrl){
12008                 this.defaultUrl = url;
12009             }
12010             if(typeof url == "function"){
12011                 url = url.call(this);
12012             }
12013
12014             method = method || (params ? "POST" : "GET");
12015             if(method == "GET"){
12016                 url = this.prepareUrl(url);
12017             }
12018
12019             var o = Roo.apply(cfg ||{}, {
12020                 url : url,
12021                 params: params,
12022                 success: this.successDelegate,
12023                 failure: this.failureDelegate,
12024                 callback: undefined,
12025                 timeout: (this.timeout*1000),
12026                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12027             });
12028             Roo.log("updated manager called with timeout of " + o.timeout);
12029             this.transaction = Roo.Ajax.request(o);
12030         }
12031     },
12032
12033     /**
12034      * 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.
12035      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12036      * @param {String/HTMLElement} form The form Id or form element
12037      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12038      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12039      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12040      */
12041     formUpdate : function(form, url, reset, callback){
12042         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12043             if(typeof url == "function"){
12044                 url = url.call(this);
12045             }
12046             form = Roo.getDom(form);
12047             this.transaction = Roo.Ajax.request({
12048                 form: form,
12049                 url:url,
12050                 success: this.successDelegate,
12051                 failure: this.failureDelegate,
12052                 timeout: (this.timeout*1000),
12053                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12054             });
12055             this.showLoading.defer(1, this);
12056         }
12057     },
12058
12059     /**
12060      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12061      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12062      */
12063     refresh : function(callback){
12064         if(this.defaultUrl == null){
12065             return;
12066         }
12067         this.update(this.defaultUrl, null, callback, true);
12068     },
12069
12070     /**
12071      * Set this element to auto refresh.
12072      * @param {Number} interval How often to update (in seconds).
12073      * @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)
12074      * @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}
12075      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12076      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12077      */
12078     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12079         if(refreshNow){
12080             this.update(url || this.defaultUrl, params, callback, true);
12081         }
12082         if(this.autoRefreshProcId){
12083             clearInterval(this.autoRefreshProcId);
12084         }
12085         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12086     },
12087
12088     /**
12089      * Stop auto refresh on this element.
12090      */
12091      stopAutoRefresh : function(){
12092         if(this.autoRefreshProcId){
12093             clearInterval(this.autoRefreshProcId);
12094             delete this.autoRefreshProcId;
12095         }
12096     },
12097
12098     isAutoRefreshing : function(){
12099        return this.autoRefreshProcId ? true : false;
12100     },
12101     /**
12102      * Called to update the element to "Loading" state. Override to perform custom action.
12103      */
12104     showLoading : function(){
12105         if(this.showLoadIndicator){
12106             this.el.update(this.indicatorText);
12107         }
12108     },
12109
12110     /**
12111      * Adds unique parameter to query string if disableCaching = true
12112      * @private
12113      */
12114     prepareUrl : function(url){
12115         if(this.disableCaching){
12116             var append = "_dc=" + (new Date().getTime());
12117             if(url.indexOf("?") !== -1){
12118                 url += "&" + append;
12119             }else{
12120                 url += "?" + append;
12121             }
12122         }
12123         return url;
12124     },
12125
12126     /**
12127      * @private
12128      */
12129     processSuccess : function(response){
12130         this.transaction = null;
12131         if(response.argument.form && response.argument.reset){
12132             try{ // put in try/catch since some older FF releases had problems with this
12133                 response.argument.form.reset();
12134             }catch(e){}
12135         }
12136         if(this.loadScripts){
12137             this.renderer.render(this.el, response, this,
12138                 this.updateComplete.createDelegate(this, [response]));
12139         }else{
12140             this.renderer.render(this.el, response, this);
12141             this.updateComplete(response);
12142         }
12143     },
12144
12145     updateComplete : function(response){
12146         this.fireEvent("update", this.el, response);
12147         if(typeof response.argument.callback == "function"){
12148             response.argument.callback(this.el, true, response);
12149         }
12150     },
12151
12152     /**
12153      * @private
12154      */
12155     processFailure : function(response){
12156         this.transaction = null;
12157         this.fireEvent("failure", this.el, response);
12158         if(typeof response.argument.callback == "function"){
12159             response.argument.callback(this.el, false, response);
12160         }
12161     },
12162
12163     /**
12164      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12165      * @param {Object} renderer The object implementing the render() method
12166      */
12167     setRenderer : function(renderer){
12168         this.renderer = renderer;
12169     },
12170
12171     getRenderer : function(){
12172        return this.renderer;
12173     },
12174
12175     /**
12176      * Set the defaultUrl used for updates
12177      * @param {String/Function} defaultUrl The url or a function to call to get the url
12178      */
12179     setDefaultUrl : function(defaultUrl){
12180         this.defaultUrl = defaultUrl;
12181     },
12182
12183     /**
12184      * Aborts the executing transaction
12185      */
12186     abort : function(){
12187         if(this.transaction){
12188             Roo.Ajax.abort(this.transaction);
12189         }
12190     },
12191
12192     /**
12193      * Returns true if an update is in progress
12194      * @return {Boolean}
12195      */
12196     isUpdating : function(){
12197         if(this.transaction){
12198             return Roo.Ajax.isLoading(this.transaction);
12199         }
12200         return false;
12201     }
12202 });
12203
12204 /**
12205  * @class Roo.UpdateManager.defaults
12206  * @static (not really - but it helps the doc tool)
12207  * The defaults collection enables customizing the default properties of UpdateManager
12208  */
12209    Roo.UpdateManager.defaults = {
12210        /**
12211          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12212          * @type Number
12213          */
12214          timeout : 30,
12215
12216          /**
12217          * True to process scripts by default (Defaults to false).
12218          * @type Boolean
12219          */
12220         loadScripts : false,
12221
12222         /**
12223         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12224         * @type String
12225         */
12226         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12227         /**
12228          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12229          * @type Boolean
12230          */
12231         disableCaching : false,
12232         /**
12233          * Whether to show indicatorText when loading (Defaults to true).
12234          * @type Boolean
12235          */
12236         showLoadIndicator : true,
12237         /**
12238          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12239          * @type String
12240          */
12241         indicatorText : '<div class="loading-indicator">Loading...</div>'
12242    };
12243
12244 /**
12245  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12246  *Usage:
12247  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12248  * @param {String/HTMLElement/Roo.Element} el The element to update
12249  * @param {String} url The url
12250  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12251  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12252  * @static
12253  * @deprecated
12254  * @member Roo.UpdateManager
12255  */
12256 Roo.UpdateManager.updateElement = function(el, url, params, options){
12257     var um = Roo.get(el, true).getUpdateManager();
12258     Roo.apply(um, options);
12259     um.update(url, params, options ? options.callback : null);
12260 };
12261 // alias for backwards compat
12262 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12263 /**
12264  * @class Roo.UpdateManager.BasicRenderer
12265  * Default Content renderer. Updates the elements innerHTML with the responseText.
12266  */
12267 Roo.UpdateManager.BasicRenderer = function(){};
12268
12269 Roo.UpdateManager.BasicRenderer.prototype = {
12270     /**
12271      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12272      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12273      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12274      * @param {Roo.Element} el The element being rendered
12275      * @param {Object} response The YUI Connect response object
12276      * @param {UpdateManager} updateManager The calling update manager
12277      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12278      */
12279      render : function(el, response, updateManager, callback){
12280         el.update(response.responseText, updateManager.loadScripts, callback);
12281     }
12282 };
12283 /*
12284  * Based on:
12285  * Roo JS
12286  * (c)) Alan Knowles
12287  * Licence : LGPL
12288  */
12289
12290
12291 /**
12292  * @class Roo.DomTemplate
12293  * @extends Roo.Template
12294  * An effort at a dom based template engine..
12295  *
12296  * Similar to XTemplate, except it uses dom parsing to create the template..
12297  *
12298  * Supported features:
12299  *
12300  *  Tags:
12301
12302 <pre><code>
12303       {a_variable} - output encoded.
12304       {a_variable.format:("Y-m-d")} - call a method on the variable
12305       {a_variable:raw} - unencoded output
12306       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12307       {a_variable:this.method_on_template(...)} - call a method on the template object.
12308  
12309 </code></pre>
12310  *  The tpl tag:
12311 <pre><code>
12312         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12313         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12314         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12315         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12316   
12317 </code></pre>
12318  *      
12319  */
12320 Roo.DomTemplate = function()
12321 {
12322      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12323      if (this.html) {
12324         this.compile();
12325      }
12326 };
12327
12328
12329 Roo.extend(Roo.DomTemplate, Roo.Template, {
12330     /**
12331      * id counter for sub templates.
12332      */
12333     id : 0,
12334     /**
12335      * flag to indicate if dom parser is inside a pre,
12336      * it will strip whitespace if not.
12337      */
12338     inPre : false,
12339     
12340     /**
12341      * The various sub templates
12342      */
12343     tpls : false,
12344     
12345     
12346     
12347     /**
12348      *
12349      * basic tag replacing syntax
12350      * WORD:WORD()
12351      *
12352      * // you can fake an object call by doing this
12353      *  x.t:(test,tesT) 
12354      * 
12355      */
12356     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12357     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12358     
12359     iterChild : function (node, method) {
12360         
12361         var oldPre = this.inPre;
12362         if (node.tagName == 'PRE') {
12363             this.inPre = true;
12364         }
12365         for( var i = 0; i < node.childNodes.length; i++) {
12366             method.call(this, node.childNodes[i]);
12367         }
12368         this.inPre = oldPre;
12369     },
12370     
12371     
12372     
12373     /**
12374      * compile the template
12375      *
12376      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12377      *
12378      */
12379     compile: function()
12380     {
12381         var s = this.html;
12382         
12383         // covert the html into DOM...
12384         var doc = false;
12385         var div =false;
12386         try {
12387             doc = document.implementation.createHTMLDocument("");
12388             doc.documentElement.innerHTML =   this.html  ;
12389             div = doc.documentElement;
12390         } catch (e) {
12391             // old IE... - nasty -- it causes all sorts of issues.. with
12392             // images getting pulled from server..
12393             div = document.createElement('div');
12394             div.innerHTML = this.html;
12395         }
12396         //doc.documentElement.innerHTML = htmlBody
12397          
12398         
12399         
12400         this.tpls = [];
12401         var _t = this;
12402         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12403         
12404         var tpls = this.tpls;
12405         
12406         // create a top level template from the snippet..
12407         
12408         //Roo.log(div.innerHTML);
12409         
12410         var tpl = {
12411             uid : 'master',
12412             id : this.id++,
12413             attr : false,
12414             value : false,
12415             body : div.innerHTML,
12416             
12417             forCall : false,
12418             execCall : false,
12419             dom : div,
12420             isTop : true
12421             
12422         };
12423         tpls.unshift(tpl);
12424         
12425         
12426         // compile them...
12427         this.tpls = [];
12428         Roo.each(tpls, function(tp){
12429             this.compileTpl(tp);
12430             this.tpls[tp.id] = tp;
12431         }, this);
12432         
12433         this.master = tpls[0];
12434         return this;
12435         
12436         
12437     },
12438     
12439     compileNode : function(node, istop) {
12440         // test for
12441         //Roo.log(node);
12442         
12443         
12444         // skip anything not a tag..
12445         if (node.nodeType != 1) {
12446             if (node.nodeType == 3 && !this.inPre) {
12447                 // reduce white space..
12448                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12449                 
12450             }
12451             return;
12452         }
12453         
12454         var tpl = {
12455             uid : false,
12456             id : false,
12457             attr : false,
12458             value : false,
12459             body : '',
12460             
12461             forCall : false,
12462             execCall : false,
12463             dom : false,
12464             isTop : istop
12465             
12466             
12467         };
12468         
12469         
12470         switch(true) {
12471             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12472             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12473             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12474             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12475             // no default..
12476         }
12477         
12478         
12479         if (!tpl.attr) {
12480             // just itterate children..
12481             this.iterChild(node,this.compileNode);
12482             return;
12483         }
12484         tpl.uid = this.id++;
12485         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12486         node.removeAttribute('roo-'+ tpl.attr);
12487         if (tpl.attr != 'name') {
12488             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12489             node.parentNode.replaceChild(placeholder,  node);
12490         } else {
12491             
12492             var placeholder =  document.createElement('span');
12493             placeholder.className = 'roo-tpl-' + tpl.value;
12494             node.parentNode.replaceChild(placeholder,  node);
12495         }
12496         
12497         // parent now sees '{domtplXXXX}
12498         this.iterChild(node,this.compileNode);
12499         
12500         // we should now have node body...
12501         var div = document.createElement('div');
12502         div.appendChild(node);
12503         tpl.dom = node;
12504         // this has the unfortunate side effect of converting tagged attributes
12505         // eg. href="{...}" into %7C...%7D
12506         // this has been fixed by searching for those combo's although it's a bit hacky..
12507         
12508         
12509         tpl.body = div.innerHTML;
12510         
12511         
12512          
12513         tpl.id = tpl.uid;
12514         switch(tpl.attr) {
12515             case 'for' :
12516                 switch (tpl.value) {
12517                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12518                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12519                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12520                 }
12521                 break;
12522             
12523             case 'exec':
12524                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12525                 break;
12526             
12527             case 'if':     
12528                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12529                 break;
12530             
12531             case 'name':
12532                 tpl.id  = tpl.value; // replace non characters???
12533                 break;
12534             
12535         }
12536         
12537         
12538         this.tpls.push(tpl);
12539         
12540         
12541         
12542     },
12543     
12544     
12545     
12546     
12547     /**
12548      * Compile a segment of the template into a 'sub-template'
12549      *
12550      * 
12551      * 
12552      *
12553      */
12554     compileTpl : function(tpl)
12555     {
12556         var fm = Roo.util.Format;
12557         var useF = this.disableFormats !== true;
12558         
12559         var sep = Roo.isGecko ? "+\n" : ",\n";
12560         
12561         var undef = function(str) {
12562             Roo.debug && Roo.log("Property not found :"  + str);
12563             return '';
12564         };
12565           
12566         //Roo.log(tpl.body);
12567         
12568         
12569         
12570         var fn = function(m, lbrace, name, format, args)
12571         {
12572             //Roo.log("ARGS");
12573             //Roo.log(arguments);
12574             args = args ? args.replace(/\\'/g,"'") : args;
12575             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12576             if (typeof(format) == 'undefined') {
12577                 format =  'htmlEncode'; 
12578             }
12579             if (format == 'raw' ) {
12580                 format = false;
12581             }
12582             
12583             if(name.substr(0, 6) == 'domtpl'){
12584                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12585             }
12586             
12587             // build an array of options to determine if value is undefined..
12588             
12589             // basically get 'xxxx.yyyy' then do
12590             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12591             //    (function () { Roo.log("Property not found"); return ''; })() :
12592             //    ......
12593             
12594             var udef_ar = [];
12595             var lookfor = '';
12596             Roo.each(name.split('.'), function(st) {
12597                 lookfor += (lookfor.length ? '.': '') + st;
12598                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12599             });
12600             
12601             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12602             
12603             
12604             if(format && useF){
12605                 
12606                 args = args ? ',' + args : "";
12607                  
12608                 if(format.substr(0, 5) != "this."){
12609                     format = "fm." + format + '(';
12610                 }else{
12611                     format = 'this.call("'+ format.substr(5) + '", ';
12612                     args = ", values";
12613                 }
12614                 
12615                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12616             }
12617              
12618             if (args && args.length) {
12619                 // called with xxyx.yuu:(test,test)
12620                 // change to ()
12621                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12622             }
12623             // raw.. - :raw modifier..
12624             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12625             
12626         };
12627         var body;
12628         // branched to use + in gecko and [].join() in others
12629         if(Roo.isGecko){
12630             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12631                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12632                     "';};};";
12633         }else{
12634             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12635             body.push(tpl.body.replace(/(\r\n|\n)/g,
12636                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12637             body.push("'].join('');};};");
12638             body = body.join('');
12639         }
12640         
12641         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12642        
12643         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12644         eval(body);
12645         
12646         return this;
12647     },
12648      
12649     /**
12650      * same as applyTemplate, except it's done to one of the subTemplates
12651      * when using named templates, you can do:
12652      *
12653      * var str = pl.applySubTemplate('your-name', values);
12654      *
12655      * 
12656      * @param {Number} id of the template
12657      * @param {Object} values to apply to template
12658      * @param {Object} parent (normaly the instance of this object)
12659      */
12660     applySubTemplate : function(id, values, parent)
12661     {
12662         
12663         
12664         var t = this.tpls[id];
12665         
12666         
12667         try { 
12668             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12669                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12670                 return '';
12671             }
12672         } catch(e) {
12673             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12674             Roo.log(values);
12675           
12676             return '';
12677         }
12678         try { 
12679             
12680             if(t.execCall && t.execCall.call(this, values, parent)){
12681                 return '';
12682             }
12683         } catch(e) {
12684             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12685             Roo.log(values);
12686             return '';
12687         }
12688         
12689         try {
12690             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12691             parent = t.target ? values : parent;
12692             if(t.forCall && vs instanceof Array){
12693                 var buf = [];
12694                 for(var i = 0, len = vs.length; i < len; i++){
12695                     try {
12696                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12697                     } catch (e) {
12698                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12699                         Roo.log(e.body);
12700                         //Roo.log(t.compiled);
12701                         Roo.log(vs[i]);
12702                     }   
12703                 }
12704                 return buf.join('');
12705             }
12706         } catch (e) {
12707             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12708             Roo.log(values);
12709             return '';
12710         }
12711         try {
12712             return t.compiled.call(this, vs, parent);
12713         } catch (e) {
12714             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12715             Roo.log(e.body);
12716             //Roo.log(t.compiled);
12717             Roo.log(values);
12718             return '';
12719         }
12720     },
12721
12722    
12723
12724     applyTemplate : function(values){
12725         return this.master.compiled.call(this, values, {});
12726         //var s = this.subs;
12727     },
12728
12729     apply : function(){
12730         return this.applyTemplate.apply(this, arguments);
12731     }
12732
12733  });
12734
12735 Roo.DomTemplate.from = function(el){
12736     el = Roo.getDom(el);
12737     return new Roo.Domtemplate(el.value || el.innerHTML);
12738 };/*
12739  * Based on:
12740  * Ext JS Library 1.1.1
12741  * Copyright(c) 2006-2007, Ext JS, LLC.
12742  *
12743  * Originally Released Under LGPL - original licence link has changed is not relivant.
12744  *
12745  * Fork - LGPL
12746  * <script type="text/javascript">
12747  */
12748
12749 /**
12750  * @class Roo.util.DelayedTask
12751  * Provides a convenient method of performing setTimeout where a new
12752  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12753  * You can use this class to buffer
12754  * the keypress events for a certain number of milliseconds, and perform only if they stop
12755  * for that amount of time.
12756  * @constructor The parameters to this constructor serve as defaults and are not required.
12757  * @param {Function} fn (optional) The default function to timeout
12758  * @param {Object} scope (optional) The default scope of that timeout
12759  * @param {Array} args (optional) The default Array of arguments
12760  */
12761 Roo.util.DelayedTask = function(fn, scope, args){
12762     var id = null, d, t;
12763
12764     var call = function(){
12765         var now = new Date().getTime();
12766         if(now - t >= d){
12767             clearInterval(id);
12768             id = null;
12769             fn.apply(scope, args || []);
12770         }
12771     };
12772     /**
12773      * Cancels any pending timeout and queues a new one
12774      * @param {Number} delay The milliseconds to delay
12775      * @param {Function} newFn (optional) Overrides function passed to constructor
12776      * @param {Object} newScope (optional) Overrides scope passed to constructor
12777      * @param {Array} newArgs (optional) Overrides args passed to constructor
12778      */
12779     this.delay = function(delay, newFn, newScope, newArgs){
12780         if(id && delay != d){
12781             this.cancel();
12782         }
12783         d = delay;
12784         t = new Date().getTime();
12785         fn = newFn || fn;
12786         scope = newScope || scope;
12787         args = newArgs || args;
12788         if(!id){
12789             id = setInterval(call, d);
12790         }
12791     };
12792
12793     /**
12794      * Cancel the last queued timeout
12795      */
12796     this.cancel = function(){
12797         if(id){
12798             clearInterval(id);
12799             id = null;
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 Roo.util.TaskRunner = function(interval){
12815     interval = interval || 10;
12816     var tasks = [], removeQueue = [];
12817     var id = 0;
12818     var running = false;
12819
12820     var stopThread = function(){
12821         running = false;
12822         clearInterval(id);
12823         id = 0;
12824     };
12825
12826     var startThread = function(){
12827         if(!running){
12828             running = true;
12829             id = setInterval(runTasks, interval);
12830         }
12831     };
12832
12833     var removeTask = function(task){
12834         removeQueue.push(task);
12835         if(task.onStop){
12836             task.onStop();
12837         }
12838     };
12839
12840     var runTasks = function(){
12841         if(removeQueue.length > 0){
12842             for(var i = 0, len = removeQueue.length; i < len; i++){
12843                 tasks.remove(removeQueue[i]);
12844             }
12845             removeQueue = [];
12846             if(tasks.length < 1){
12847                 stopThread();
12848                 return;
12849             }
12850         }
12851         var now = new Date().getTime();
12852         for(var i = 0, len = tasks.length; i < len; ++i){
12853             var t = tasks[i];
12854             var itime = now - t.taskRunTime;
12855             if(t.interval <= itime){
12856                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12857                 t.taskRunTime = now;
12858                 if(rt === false || t.taskRunCount === t.repeat){
12859                     removeTask(t);
12860                     return;
12861                 }
12862             }
12863             if(t.duration && t.duration <= (now - t.taskStartTime)){
12864                 removeTask(t);
12865             }
12866         }
12867     };
12868
12869     /**
12870      * Queues a new task.
12871      * @param {Object} task
12872      */
12873     this.start = function(task){
12874         tasks.push(task);
12875         task.taskStartTime = new Date().getTime();
12876         task.taskRunTime = 0;
12877         task.taskRunCount = 0;
12878         startThread();
12879         return task;
12880     };
12881
12882     this.stop = function(task){
12883         removeTask(task);
12884         return task;
12885     };
12886
12887     this.stopAll = function(){
12888         stopThread();
12889         for(var i = 0, len = tasks.length; i < len; i++){
12890             if(tasks[i].onStop){
12891                 tasks[i].onStop();
12892             }
12893         }
12894         tasks = [];
12895         removeQueue = [];
12896     };
12897 };
12898
12899 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12900  * Based on:
12901  * Ext JS Library 1.1.1
12902  * Copyright(c) 2006-2007, Ext JS, LLC.
12903  *
12904  * Originally Released Under LGPL - original licence link has changed is not relivant.
12905  *
12906  * Fork - LGPL
12907  * <script type="text/javascript">
12908  */
12909
12910  
12911 /**
12912  * @class Roo.util.MixedCollection
12913  * @extends Roo.util.Observable
12914  * A Collection class that maintains both numeric indexes and keys and exposes events.
12915  * @constructor
12916  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12917  * collection (defaults to false)
12918  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12919  * and return the key value for that item.  This is used when available to look up the key on items that
12920  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12921  * equivalent to providing an implementation for the {@link #getKey} method.
12922  */
12923 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12924     this.items = [];
12925     this.map = {};
12926     this.keys = [];
12927     this.length = 0;
12928     this.addEvents({
12929         /**
12930          * @event clear
12931          * Fires when the collection is cleared.
12932          */
12933         "clear" : true,
12934         /**
12935          * @event add
12936          * Fires when an item is added to the collection.
12937          * @param {Number} index The index at which the item was added.
12938          * @param {Object} o The item added.
12939          * @param {String} key The key associated with the added item.
12940          */
12941         "add" : true,
12942         /**
12943          * @event replace
12944          * Fires when an item is replaced in the collection.
12945          * @param {String} key he key associated with the new added.
12946          * @param {Object} old The item being replaced.
12947          * @param {Object} new The new item.
12948          */
12949         "replace" : true,
12950         /**
12951          * @event remove
12952          * Fires when an item is removed from the collection.
12953          * @param {Object} o The item being removed.
12954          * @param {String} key (optional) The key associated with the removed item.
12955          */
12956         "remove" : true,
12957         "sort" : true
12958     });
12959     this.allowFunctions = allowFunctions === true;
12960     if(keyFn){
12961         this.getKey = keyFn;
12962     }
12963     Roo.util.MixedCollection.superclass.constructor.call(this);
12964 };
12965
12966 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12967     allowFunctions : false,
12968     
12969 /**
12970  * Adds an item to the collection.
12971  * @param {String} key The key to associate with the item
12972  * @param {Object} o The item to add.
12973  * @return {Object} The item added.
12974  */
12975     add : function(key, o){
12976         if(arguments.length == 1){
12977             o = arguments[0];
12978             key = this.getKey(o);
12979         }
12980         if(typeof key == "undefined" || key === null){
12981             this.length++;
12982             this.items.push(o);
12983             this.keys.push(null);
12984         }else{
12985             var old = this.map[key];
12986             if(old){
12987                 return this.replace(key, o);
12988             }
12989             this.length++;
12990             this.items.push(o);
12991             this.map[key] = o;
12992             this.keys.push(key);
12993         }
12994         this.fireEvent("add", this.length-1, o, key);
12995         return o;
12996     },
12997        
12998 /**
12999   * MixedCollection has a generic way to fetch keys if you implement getKey.
13000 <pre><code>
13001 // normal way
13002 var mc = new Roo.util.MixedCollection();
13003 mc.add(someEl.dom.id, someEl);
13004 mc.add(otherEl.dom.id, otherEl);
13005 //and so on
13006
13007 // using getKey
13008 var mc = new Roo.util.MixedCollection();
13009 mc.getKey = function(el){
13010    return el.dom.id;
13011 };
13012 mc.add(someEl);
13013 mc.add(otherEl);
13014
13015 // or via the constructor
13016 var mc = new Roo.util.MixedCollection(false, function(el){
13017    return el.dom.id;
13018 });
13019 mc.add(someEl);
13020 mc.add(otherEl);
13021 </code></pre>
13022  * @param o {Object} The item for which to find the key.
13023  * @return {Object} The key for the passed item.
13024  */
13025     getKey : function(o){
13026          return o.id; 
13027     },
13028    
13029 /**
13030  * Replaces an item in the collection.
13031  * @param {String} key The key associated with the item to replace, or the item to replace.
13032  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13033  * @return {Object}  The new item.
13034  */
13035     replace : function(key, o){
13036         if(arguments.length == 1){
13037             o = arguments[0];
13038             key = this.getKey(o);
13039         }
13040         var old = this.item(key);
13041         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13042              return this.add(key, o);
13043         }
13044         var index = this.indexOfKey(key);
13045         this.items[index] = o;
13046         this.map[key] = o;
13047         this.fireEvent("replace", key, old, o);
13048         return o;
13049     },
13050    
13051 /**
13052  * Adds all elements of an Array or an Object to the collection.
13053  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13054  * an Array of values, each of which are added to the collection.
13055  */
13056     addAll : function(objs){
13057         if(arguments.length > 1 || objs instanceof Array){
13058             var args = arguments.length > 1 ? arguments : objs;
13059             for(var i = 0, len = args.length; i < len; i++){
13060                 this.add(args[i]);
13061             }
13062         }else{
13063             for(var key in objs){
13064                 if(this.allowFunctions || typeof objs[key] != "function"){
13065                     this.add(key, objs[key]);
13066                 }
13067             }
13068         }
13069     },
13070    
13071 /**
13072  * Executes the specified function once for every item in the collection, passing each
13073  * item as the first and only parameter. returning false from the function will stop the iteration.
13074  * @param {Function} fn The function to execute for each item.
13075  * @param {Object} scope (optional) The scope in which to execute the function.
13076  */
13077     each : function(fn, scope){
13078         var items = [].concat(this.items); // each safe for removal
13079         for(var i = 0, len = items.length; i < len; i++){
13080             if(fn.call(scope || items[i], items[i], i, len) === false){
13081                 break;
13082             }
13083         }
13084     },
13085    
13086 /**
13087  * Executes the specified function once for every key in the collection, passing each
13088  * key, and its associated item as the first two parameters.
13089  * @param {Function} fn The function to execute for each item.
13090  * @param {Object} scope (optional) The scope in which to execute the function.
13091  */
13092     eachKey : function(fn, scope){
13093         for(var i = 0, len = this.keys.length; i < len; i++){
13094             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13095         }
13096     },
13097    
13098 /**
13099  * Returns the first item in the collection which elicits a true return value from the
13100  * passed selection function.
13101  * @param {Function} fn The selection function to execute for each item.
13102  * @param {Object} scope (optional) The scope in which to execute the function.
13103  * @return {Object} The first item in the collection which returned true from the selection function.
13104  */
13105     find : function(fn, scope){
13106         for(var i = 0, len = this.items.length; i < len; i++){
13107             if(fn.call(scope || window, this.items[i], this.keys[i])){
13108                 return this.items[i];
13109             }
13110         }
13111         return null;
13112     },
13113    
13114 /**
13115  * Inserts an item at the specified index in the collection.
13116  * @param {Number} index The index to insert the item at.
13117  * @param {String} key The key to associate with the new item, or the item itself.
13118  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13119  * @return {Object} The item inserted.
13120  */
13121     insert : function(index, key, o){
13122         if(arguments.length == 2){
13123             o = arguments[1];
13124             key = this.getKey(o);
13125         }
13126         if(index >= this.length){
13127             return this.add(key, o);
13128         }
13129         this.length++;
13130         this.items.splice(index, 0, o);
13131         if(typeof key != "undefined" && key != null){
13132             this.map[key] = o;
13133         }
13134         this.keys.splice(index, 0, key);
13135         this.fireEvent("add", index, o, key);
13136         return o;
13137     },
13138    
13139 /**
13140  * Removed an item from the collection.
13141  * @param {Object} o The item to remove.
13142  * @return {Object} The item removed.
13143  */
13144     remove : function(o){
13145         return this.removeAt(this.indexOf(o));
13146     },
13147    
13148 /**
13149  * Remove an item from a specified index in the collection.
13150  * @param {Number} index The index within the collection of the item to remove.
13151  */
13152     removeAt : function(index){
13153         if(index < this.length && index >= 0){
13154             this.length--;
13155             var o = this.items[index];
13156             this.items.splice(index, 1);
13157             var key = this.keys[index];
13158             if(typeof key != "undefined"){
13159                 delete this.map[key];
13160             }
13161             this.keys.splice(index, 1);
13162             this.fireEvent("remove", o, key);
13163         }
13164     },
13165    
13166 /**
13167  * Removed an item associated with the passed key fom the collection.
13168  * @param {String} key The key of the item to remove.
13169  */
13170     removeKey : function(key){
13171         return this.removeAt(this.indexOfKey(key));
13172     },
13173    
13174 /**
13175  * Returns the number of items in the collection.
13176  * @return {Number} the number of items in the collection.
13177  */
13178     getCount : function(){
13179         return this.length; 
13180     },
13181    
13182 /**
13183  * Returns index within the collection of the passed Object.
13184  * @param {Object} o The item to find the index of.
13185  * @return {Number} index of the item.
13186  */
13187     indexOf : function(o){
13188         if(!this.items.indexOf){
13189             for(var i = 0, len = this.items.length; i < len; i++){
13190                 if(this.items[i] == o) {
13191                     return i;
13192                 }
13193             }
13194             return -1;
13195         }else{
13196             return this.items.indexOf(o);
13197         }
13198     },
13199    
13200 /**
13201  * Returns index within the collection of the passed key.
13202  * @param {String} key The key to find the index of.
13203  * @return {Number} index of the key.
13204  */
13205     indexOfKey : function(key){
13206         if(!this.keys.indexOf){
13207             for(var i = 0, len = this.keys.length; i < len; i++){
13208                 if(this.keys[i] == key) {
13209                     return i;
13210                 }
13211             }
13212             return -1;
13213         }else{
13214             return this.keys.indexOf(key);
13215         }
13216     },
13217    
13218 /**
13219  * Returns the item associated with the passed key OR index. Key has priority over index.
13220  * @param {String/Number} key The key or index of the item.
13221  * @return {Object} The item associated with the passed key.
13222  */
13223     item : function(key){
13224         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13225         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13226     },
13227     
13228 /**
13229  * Returns the item at the specified index.
13230  * @param {Number} index The index of the item.
13231  * @return {Object}
13232  */
13233     itemAt : function(index){
13234         return this.items[index];
13235     },
13236     
13237 /**
13238  * Returns the item associated with the passed key.
13239  * @param {String/Number} key The key of the item.
13240  * @return {Object} The item associated with the passed key.
13241  */
13242     key : function(key){
13243         return this.map[key];
13244     },
13245    
13246 /**
13247  * Returns true if the collection contains the passed Object as an item.
13248  * @param {Object} o  The Object to look for in the collection.
13249  * @return {Boolean} True if the collection contains the Object as an item.
13250  */
13251     contains : function(o){
13252         return this.indexOf(o) != -1;
13253     },
13254    
13255 /**
13256  * Returns true if the collection contains the passed Object as a key.
13257  * @param {String} key The key to look for in the collection.
13258  * @return {Boolean} True if the collection contains the Object as a key.
13259  */
13260     containsKey : function(key){
13261         return typeof this.map[key] != "undefined";
13262     },
13263    
13264 /**
13265  * Removes all items from the collection.
13266  */
13267     clear : function(){
13268         this.length = 0;
13269         this.items = [];
13270         this.keys = [];
13271         this.map = {};
13272         this.fireEvent("clear");
13273     },
13274    
13275 /**
13276  * Returns the first item in the collection.
13277  * @return {Object} the first item in the collection..
13278  */
13279     first : function(){
13280         return this.items[0]; 
13281     },
13282    
13283 /**
13284  * Returns the last item in the collection.
13285  * @return {Object} the last item in the collection..
13286  */
13287     last : function(){
13288         return this.items[this.length-1];   
13289     },
13290     
13291     _sort : function(property, dir, fn){
13292         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13293         fn = fn || function(a, b){
13294             return a-b;
13295         };
13296         var c = [], k = this.keys, items = this.items;
13297         for(var i = 0, len = items.length; i < len; i++){
13298             c[c.length] = {key: k[i], value: items[i], index: i};
13299         }
13300         c.sort(function(a, b){
13301             var v = fn(a[property], b[property]) * dsc;
13302             if(v == 0){
13303                 v = (a.index < b.index ? -1 : 1);
13304             }
13305             return v;
13306         });
13307         for(var i = 0, len = c.length; i < len; i++){
13308             items[i] = c[i].value;
13309             k[i] = c[i].key;
13310         }
13311         this.fireEvent("sort", this);
13312     },
13313     
13314     /**
13315      * Sorts this collection with the passed comparison function
13316      * @param {String} direction (optional) "ASC" or "DESC"
13317      * @param {Function} fn (optional) comparison function
13318      */
13319     sort : function(dir, fn){
13320         this._sort("value", dir, fn);
13321     },
13322     
13323     /**
13324      * Sorts this collection by keys
13325      * @param {String} direction (optional) "ASC" or "DESC"
13326      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13327      */
13328     keySort : function(dir, fn){
13329         this._sort("key", dir, fn || function(a, b){
13330             return String(a).toUpperCase()-String(b).toUpperCase();
13331         });
13332     },
13333     
13334     /**
13335      * Returns a range of items in this collection
13336      * @param {Number} startIndex (optional) defaults to 0
13337      * @param {Number} endIndex (optional) default to the last item
13338      * @return {Array} An array of items
13339      */
13340     getRange : function(start, end){
13341         var items = this.items;
13342         if(items.length < 1){
13343             return [];
13344         }
13345         start = start || 0;
13346         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13347         var r = [];
13348         if(start <= end){
13349             for(var i = start; i <= end; i++) {
13350                     r[r.length] = items[i];
13351             }
13352         }else{
13353             for(var i = start; i >= end; i--) {
13354                     r[r.length] = items[i];
13355             }
13356         }
13357         return r;
13358     },
13359         
13360     /**
13361      * Filter the <i>objects</i> in this collection by a specific property. 
13362      * Returns a new collection that has been filtered.
13363      * @param {String} property A property on your objects
13364      * @param {String/RegExp} value Either string that the property values 
13365      * should start with or a RegExp to test against the property
13366      * @return {MixedCollection} The new filtered collection
13367      */
13368     filter : function(property, value){
13369         if(!value.exec){ // not a regex
13370             value = String(value);
13371             if(value.length == 0){
13372                 return this.clone();
13373             }
13374             value = new RegExp("^" + Roo.escapeRe(value), "i");
13375         }
13376         return this.filterBy(function(o){
13377             return o && value.test(o[property]);
13378         });
13379         },
13380     
13381     /**
13382      * Filter by a function. * Returns a new collection that has been filtered.
13383      * The passed function will be called with each 
13384      * object in the collection. If the function returns true, the value is included 
13385      * otherwise it is filtered.
13386      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13387      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13388      * @return {MixedCollection} The new filtered collection
13389      */
13390     filterBy : function(fn, scope){
13391         var r = new Roo.util.MixedCollection();
13392         r.getKey = this.getKey;
13393         var k = this.keys, it = this.items;
13394         for(var i = 0, len = it.length; i < len; i++){
13395             if(fn.call(scope||this, it[i], k[i])){
13396                                 r.add(k[i], it[i]);
13397                         }
13398         }
13399         return r;
13400     },
13401     
13402     /**
13403      * Creates a duplicate of this collection
13404      * @return {MixedCollection}
13405      */
13406     clone : function(){
13407         var r = new Roo.util.MixedCollection();
13408         var k = this.keys, it = this.items;
13409         for(var i = 0, len = it.length; i < len; i++){
13410             r.add(k[i], it[i]);
13411         }
13412         r.getKey = this.getKey;
13413         return r;
13414     }
13415 });
13416 /**
13417  * Returns the item associated with the passed key or index.
13418  * @method
13419  * @param {String/Number} key The key or index of the item.
13420  * @return {Object} The item associated with the passed key.
13421  */
13422 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13423  * Based on:
13424  * Ext JS Library 1.1.1
13425  * Copyright(c) 2006-2007, Ext JS, LLC.
13426  *
13427  * Originally Released Under LGPL - original licence link has changed is not relivant.
13428  *
13429  * Fork - LGPL
13430  * <script type="text/javascript">
13431  */
13432 /**
13433  * @class Roo.util.JSON
13434  * Modified version of Douglas Crockford"s json.js that doesn"t
13435  * mess with the Object prototype 
13436  * http://www.json.org/js.html
13437  * @singleton
13438  */
13439 Roo.util.JSON = new (function(){
13440     var useHasOwn = {}.hasOwnProperty ? true : false;
13441     
13442     // crashes Safari in some instances
13443     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13444     
13445     var pad = function(n) {
13446         return n < 10 ? "0" + n : n;
13447     };
13448     
13449     var m = {
13450         "\b": '\\b',
13451         "\t": '\\t',
13452         "\n": '\\n',
13453         "\f": '\\f',
13454         "\r": '\\r',
13455         '"' : '\\"',
13456         "\\": '\\\\'
13457     };
13458
13459     var encodeString = function(s){
13460         if (/["\\\x00-\x1f]/.test(s)) {
13461             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13462                 var c = m[b];
13463                 if(c){
13464                     return c;
13465                 }
13466                 c = b.charCodeAt();
13467                 return "\\u00" +
13468                     Math.floor(c / 16).toString(16) +
13469                     (c % 16).toString(16);
13470             }) + '"';
13471         }
13472         return '"' + s + '"';
13473     };
13474     
13475     var encodeArray = function(o){
13476         var a = ["["], b, i, l = o.length, v;
13477             for (i = 0; i < l; i += 1) {
13478                 v = o[i];
13479                 switch (typeof v) {
13480                     case "undefined":
13481                     case "function":
13482                     case "unknown":
13483                         break;
13484                     default:
13485                         if (b) {
13486                             a.push(',');
13487                         }
13488                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13489                         b = true;
13490                 }
13491             }
13492             a.push("]");
13493             return a.join("");
13494     };
13495     
13496     var encodeDate = function(o){
13497         return '"' + o.getFullYear() + "-" +
13498                 pad(o.getMonth() + 1) + "-" +
13499                 pad(o.getDate()) + "T" +
13500                 pad(o.getHours()) + ":" +
13501                 pad(o.getMinutes()) + ":" +
13502                 pad(o.getSeconds()) + '"';
13503     };
13504     
13505     /**
13506      * Encodes an Object, Array or other value
13507      * @param {Mixed} o The variable to encode
13508      * @return {String} The JSON string
13509      */
13510     this.encode = function(o)
13511     {
13512         // should this be extended to fully wrap stringify..
13513         
13514         if(typeof o == "undefined" || o === null){
13515             return "null";
13516         }else if(o instanceof Array){
13517             return encodeArray(o);
13518         }else if(o instanceof Date){
13519             return encodeDate(o);
13520         }else if(typeof o == "string"){
13521             return encodeString(o);
13522         }else if(typeof o == "number"){
13523             return isFinite(o) ? String(o) : "null";
13524         }else if(typeof o == "boolean"){
13525             return String(o);
13526         }else {
13527             var a = ["{"], b, i, v;
13528             for (i in o) {
13529                 if(!useHasOwn || o.hasOwnProperty(i)) {
13530                     v = o[i];
13531                     switch (typeof v) {
13532                     case "undefined":
13533                     case "function":
13534                     case "unknown":
13535                         break;
13536                     default:
13537                         if(b){
13538                             a.push(',');
13539                         }
13540                         a.push(this.encode(i), ":",
13541                                 v === null ? "null" : this.encode(v));
13542                         b = true;
13543                     }
13544                 }
13545             }
13546             a.push("}");
13547             return a.join("");
13548         }
13549     };
13550     
13551     /**
13552      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13553      * @param {String} json The JSON string
13554      * @return {Object} The resulting object
13555      */
13556     this.decode = function(json){
13557         
13558         return  /** eval:var:json */ eval("(" + json + ')');
13559     };
13560 })();
13561 /** 
13562  * Shorthand for {@link Roo.util.JSON#encode}
13563  * @member Roo encode 
13564  * @method */
13565 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13566 /** 
13567  * Shorthand for {@link Roo.util.JSON#decode}
13568  * @member Roo decode 
13569  * @method */
13570 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13571 /*
13572  * Based on:
13573  * Ext JS Library 1.1.1
13574  * Copyright(c) 2006-2007, Ext JS, LLC.
13575  *
13576  * Originally Released Under LGPL - original licence link has changed is not relivant.
13577  *
13578  * Fork - LGPL
13579  * <script type="text/javascript">
13580  */
13581  
13582 /**
13583  * @class Roo.util.Format
13584  * Reusable data formatting functions
13585  * @singleton
13586  */
13587 Roo.util.Format = function(){
13588     var trimRe = /^\s+|\s+$/g;
13589     return {
13590         /**
13591          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13592          * @param {String} value The string to truncate
13593          * @param {Number} length The maximum length to allow before truncating
13594          * @return {String} The converted text
13595          */
13596         ellipsis : function(value, len){
13597             if(value && value.length > len){
13598                 return value.substr(0, len-3)+"...";
13599             }
13600             return value;
13601         },
13602
13603         /**
13604          * Checks a reference and converts it to empty string if it is undefined
13605          * @param {Mixed} value Reference to check
13606          * @return {Mixed} Empty string if converted, otherwise the original value
13607          */
13608         undef : function(value){
13609             return typeof value != "undefined" ? value : "";
13610         },
13611
13612         /**
13613          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13614          * @param {String} value The string to encode
13615          * @return {String} The encoded text
13616          */
13617         htmlEncode : function(value){
13618             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13619         },
13620
13621         /**
13622          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13623          * @param {String} value The string to decode
13624          * @return {String} The decoded text
13625          */
13626         htmlDecode : function(value){
13627             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13628         },
13629
13630         /**
13631          * Trims any whitespace from either side of a string
13632          * @param {String} value The text to trim
13633          * @return {String} The trimmed text
13634          */
13635         trim : function(value){
13636             return String(value).replace(trimRe, "");
13637         },
13638
13639         /**
13640          * Returns a substring from within an original string
13641          * @param {String} value The original text
13642          * @param {Number} start The start index of the substring
13643          * @param {Number} length The length of the substring
13644          * @return {String} The substring
13645          */
13646         substr : function(value, start, length){
13647             return String(value).substr(start, length);
13648         },
13649
13650         /**
13651          * Converts a string to all lower case letters
13652          * @param {String} value The text to convert
13653          * @return {String} The converted text
13654          */
13655         lowercase : function(value){
13656             return String(value).toLowerCase();
13657         },
13658
13659         /**
13660          * Converts a string to all upper case letters
13661          * @param {String} value The text to convert
13662          * @return {String} The converted text
13663          */
13664         uppercase : function(value){
13665             return String(value).toUpperCase();
13666         },
13667
13668         /**
13669          * Converts the first character only of a string to upper case
13670          * @param {String} value The text to convert
13671          * @return {String} The converted text
13672          */
13673         capitalize : function(value){
13674             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13675         },
13676
13677         // private
13678         call : function(value, fn){
13679             if(arguments.length > 2){
13680                 var args = Array.prototype.slice.call(arguments, 2);
13681                 args.unshift(value);
13682                  
13683                 return /** eval:var:value */  eval(fn).apply(window, args);
13684             }else{
13685                 /** eval:var:value */
13686                 return /** eval:var:value */ eval(fn).call(window, value);
13687             }
13688         },
13689
13690        
13691         /**
13692          * safer version of Math.toFixed..??/
13693          * @param {Number/String} value The numeric value to format
13694          * @param {Number/String} value Decimal places 
13695          * @return {String} The formatted currency string
13696          */
13697         toFixed : function(v, n)
13698         {
13699             // why not use to fixed - precision is buggered???
13700             if (!n) {
13701                 return Math.round(v-0);
13702             }
13703             var fact = Math.pow(10,n+1);
13704             v = (Math.round((v-0)*fact))/fact;
13705             var z = (''+fact).substring(2);
13706             if (v == Math.floor(v)) {
13707                 return Math.floor(v) + '.' + z;
13708             }
13709             
13710             // now just padd decimals..
13711             var ps = String(v).split('.');
13712             var fd = (ps[1] + z);
13713             var r = fd.substring(0,n); 
13714             var rm = fd.substring(n); 
13715             if (rm < 5) {
13716                 return ps[0] + '.' + r;
13717             }
13718             r*=1; // turn it into a number;
13719             r++;
13720             if (String(r).length != n) {
13721                 ps[0]*=1;
13722                 ps[0]++;
13723                 r = String(r).substring(1); // chop the end off.
13724             }
13725             
13726             return ps[0] + '.' + r;
13727              
13728         },
13729         
13730         /**
13731          * Format a number as US currency
13732          * @param {Number/String} value The numeric value to format
13733          * @return {String} The formatted currency string
13734          */
13735         usMoney : function(v){
13736             return '$' + Roo.util.Format.number(v);
13737         },
13738         
13739         /**
13740          * Format a number
13741          * eventually this should probably emulate php's number_format
13742          * @param {Number/String} value The numeric value to format
13743          * @param {Number} decimals number of decimal places
13744          * @return {String} The formatted currency string
13745          */
13746         number : function(v,decimals)
13747         {
13748             // multiply and round.
13749             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13750             var mul = Math.pow(10, decimals);
13751             var zero = String(mul).substring(1);
13752             v = (Math.round((v-0)*mul))/mul;
13753             
13754             // if it's '0' number.. then
13755             
13756             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13757             v = String(v);
13758             var ps = v.split('.');
13759             var whole = ps[0];
13760             
13761             
13762             var r = /(\d+)(\d{3})/;
13763             // add comma's
13764             while (r.test(whole)) {
13765                 whole = whole.replace(r, '$1' + ',' + '$2');
13766             }
13767             
13768             
13769             var sub = ps[1] ?
13770                     // has decimals..
13771                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13772                     // does not have decimals
13773                     (decimals ? ('.' + zero) : '');
13774             
13775             
13776             return whole + sub ;
13777         },
13778         
13779         /**
13780          * Parse a value into a formatted date using the specified format pattern.
13781          * @param {Mixed} value The value to format
13782          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13783          * @return {String} The formatted date string
13784          */
13785         date : function(v, format){
13786             if(!v){
13787                 return "";
13788             }
13789             if(!(v instanceof Date)){
13790                 v = new Date(Date.parse(v));
13791             }
13792             return v.dateFormat(format || Roo.util.Format.defaults.date);
13793         },
13794
13795         /**
13796          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13797          * @param {String} format Any valid date format string
13798          * @return {Function} The date formatting function
13799          */
13800         dateRenderer : function(format){
13801             return function(v){
13802                 return Roo.util.Format.date(v, format);  
13803             };
13804         },
13805
13806         // private
13807         stripTagsRE : /<\/?[^>]+>/gi,
13808         
13809         /**
13810          * Strips all HTML tags
13811          * @param {Mixed} value The text from which to strip tags
13812          * @return {String} The stripped text
13813          */
13814         stripTags : function(v){
13815             return !v ? v : String(v).replace(this.stripTagsRE, "");
13816         }
13817     };
13818 }();
13819 Roo.util.Format.defaults = {
13820     date : 'd/M/Y'
13821 };/*
13822  * Based on:
13823  * Ext JS Library 1.1.1
13824  * Copyright(c) 2006-2007, Ext JS, LLC.
13825  *
13826  * Originally Released Under LGPL - original licence link has changed is not relivant.
13827  *
13828  * Fork - LGPL
13829  * <script type="text/javascript">
13830  */
13831
13832
13833  
13834
13835 /**
13836  * @class Roo.MasterTemplate
13837  * @extends Roo.Template
13838  * Provides a template that can have child templates. The syntax is:
13839 <pre><code>
13840 var t = new Roo.MasterTemplate(
13841         '&lt;select name="{name}"&gt;',
13842                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13843         '&lt;/select&gt;'
13844 );
13845 t.add('options', {value: 'foo', text: 'bar'});
13846 // or you can add multiple child elements in one shot
13847 t.addAll('options', [
13848     {value: 'foo', text: 'bar'},
13849     {value: 'foo2', text: 'bar2'},
13850     {value: 'foo3', text: 'bar3'}
13851 ]);
13852 // then append, applying the master template values
13853 t.append('my-form', {name: 'my-select'});
13854 </code></pre>
13855 * A name attribute for the child template is not required if you have only one child
13856 * template or you want to refer to them by index.
13857  */
13858 Roo.MasterTemplate = function(){
13859     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13860     this.originalHtml = this.html;
13861     var st = {};
13862     var m, re = this.subTemplateRe;
13863     re.lastIndex = 0;
13864     var subIndex = 0;
13865     while(m = re.exec(this.html)){
13866         var name = m[1], content = m[2];
13867         st[subIndex] = {
13868             name: name,
13869             index: subIndex,
13870             buffer: [],
13871             tpl : new Roo.Template(content)
13872         };
13873         if(name){
13874             st[name] = st[subIndex];
13875         }
13876         st[subIndex].tpl.compile();
13877         st[subIndex].tpl.call = this.call.createDelegate(this);
13878         subIndex++;
13879     }
13880     this.subCount = subIndex;
13881     this.subs = st;
13882 };
13883 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13884     /**
13885     * The regular expression used to match sub templates
13886     * @type RegExp
13887     * @property
13888     */
13889     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13890
13891     /**
13892      * Applies the passed values to a child template.
13893      * @param {String/Number} name (optional) The name or index of the child template
13894      * @param {Array/Object} values The values to be applied to the template
13895      * @return {MasterTemplate} this
13896      */
13897      add : function(name, values){
13898         if(arguments.length == 1){
13899             values = arguments[0];
13900             name = 0;
13901         }
13902         var s = this.subs[name];
13903         s.buffer[s.buffer.length] = s.tpl.apply(values);
13904         return this;
13905     },
13906
13907     /**
13908      * Applies all the passed values to a child template.
13909      * @param {String/Number} name (optional) The name or index of the child template
13910      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13911      * @param {Boolean} reset (optional) True to reset the template first
13912      * @return {MasterTemplate} this
13913      */
13914     fill : function(name, values, reset){
13915         var a = arguments;
13916         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13917             values = a[0];
13918             name = 0;
13919             reset = a[1];
13920         }
13921         if(reset){
13922             this.reset();
13923         }
13924         for(var i = 0, len = values.length; i < len; i++){
13925             this.add(name, values[i]);
13926         }
13927         return this;
13928     },
13929
13930     /**
13931      * Resets the template for reuse
13932      * @return {MasterTemplate} this
13933      */
13934      reset : function(){
13935         var s = this.subs;
13936         for(var i = 0; i < this.subCount; i++){
13937             s[i].buffer = [];
13938         }
13939         return this;
13940     },
13941
13942     applyTemplate : function(values){
13943         var s = this.subs;
13944         var replaceIndex = -1;
13945         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13946             return s[++replaceIndex].buffer.join("");
13947         });
13948         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13949     },
13950
13951     apply : function(){
13952         return this.applyTemplate.apply(this, arguments);
13953     },
13954
13955     compile : function(){return this;}
13956 });
13957
13958 /**
13959  * Alias for fill().
13960  * @method
13961  */
13962 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13963  /**
13964  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13965  * var tpl = Roo.MasterTemplate.from('element-id');
13966  * @param {String/HTMLElement} el
13967  * @param {Object} config
13968  * @static
13969  */
13970 Roo.MasterTemplate.from = function(el, config){
13971     el = Roo.getDom(el);
13972     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13973 };/*
13974  * Based on:
13975  * Ext JS Library 1.1.1
13976  * Copyright(c) 2006-2007, Ext JS, LLC.
13977  *
13978  * Originally Released Under LGPL - original licence link has changed is not relivant.
13979  *
13980  * Fork - LGPL
13981  * <script type="text/javascript">
13982  */
13983
13984  
13985 /**
13986  * @class Roo.util.CSS
13987  * Utility class for manipulating CSS rules
13988  * @singleton
13989  */
13990 Roo.util.CSS = function(){
13991         var rules = null;
13992         var doc = document;
13993
13994     var camelRe = /(-[a-z])/gi;
13995     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13996
13997    return {
13998    /**
13999     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14000     * tag and appended to the HEAD of the document.
14001     * @param {String|Object} cssText The text containing the css rules
14002     * @param {String} id An id to add to the stylesheet for later removal
14003     * @return {StyleSheet}
14004     */
14005     createStyleSheet : function(cssText, id){
14006         var ss;
14007         var head = doc.getElementsByTagName("head")[0];
14008         var nrules = doc.createElement("style");
14009         nrules.setAttribute("type", "text/css");
14010         if(id){
14011             nrules.setAttribute("id", id);
14012         }
14013         if (typeof(cssText) != 'string') {
14014             // support object maps..
14015             // not sure if this a good idea.. 
14016             // perhaps it should be merged with the general css handling
14017             // and handle js style props.
14018             var cssTextNew = [];
14019             for(var n in cssText) {
14020                 var citems = [];
14021                 for(var k in cssText[n]) {
14022                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14023                 }
14024                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14025                 
14026             }
14027             cssText = cssTextNew.join("\n");
14028             
14029         }
14030        
14031        
14032        if(Roo.isIE){
14033            head.appendChild(nrules);
14034            ss = nrules.styleSheet;
14035            ss.cssText = cssText;
14036        }else{
14037            try{
14038                 nrules.appendChild(doc.createTextNode(cssText));
14039            }catch(e){
14040                nrules.cssText = cssText; 
14041            }
14042            head.appendChild(nrules);
14043            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14044        }
14045        this.cacheStyleSheet(ss);
14046        return ss;
14047    },
14048
14049    /**
14050     * Removes a style or link tag by id
14051     * @param {String} id The id of the tag
14052     */
14053    removeStyleSheet : function(id){
14054        var existing = doc.getElementById(id);
14055        if(existing){
14056            existing.parentNode.removeChild(existing);
14057        }
14058    },
14059
14060    /**
14061     * Dynamically swaps an existing stylesheet reference for a new one
14062     * @param {String} id The id of an existing link tag to remove
14063     * @param {String} url The href of the new stylesheet to include
14064     */
14065    swapStyleSheet : function(id, url){
14066        this.removeStyleSheet(id);
14067        var ss = doc.createElement("link");
14068        ss.setAttribute("rel", "stylesheet");
14069        ss.setAttribute("type", "text/css");
14070        ss.setAttribute("id", id);
14071        ss.setAttribute("href", url);
14072        doc.getElementsByTagName("head")[0].appendChild(ss);
14073    },
14074    
14075    /**
14076     * Refresh the rule cache if you have dynamically added stylesheets
14077     * @return {Object} An object (hash) of rules indexed by selector
14078     */
14079    refreshCache : function(){
14080        return this.getRules(true);
14081    },
14082
14083    // private
14084    cacheStyleSheet : function(stylesheet){
14085        if(!rules){
14086            rules = {};
14087        }
14088        try{// try catch for cross domain access issue
14089            var ssRules = stylesheet.cssRules || stylesheet.rules;
14090            for(var j = ssRules.length-1; j >= 0; --j){
14091                rules[ssRules[j].selectorText] = ssRules[j];
14092            }
14093        }catch(e){}
14094    },
14095    
14096    /**
14097     * Gets all css rules for the document
14098     * @param {Boolean} refreshCache true to refresh the internal cache
14099     * @return {Object} An object (hash) of rules indexed by selector
14100     */
14101    getRules : function(refreshCache){
14102                 if(rules == null || refreshCache){
14103                         rules = {};
14104                         var ds = doc.styleSheets;
14105                         for(var i =0, len = ds.length; i < len; i++){
14106                             try{
14107                         this.cacheStyleSheet(ds[i]);
14108                     }catch(e){} 
14109                 }
14110                 }
14111                 return rules;
14112         },
14113         
14114         /**
14115     * Gets an an individual CSS rule by selector(s)
14116     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14117     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14118     * @return {CSSRule} The CSS rule or null if one is not found
14119     */
14120    getRule : function(selector, refreshCache){
14121                 var rs = this.getRules(refreshCache);
14122                 if(!(selector instanceof Array)){
14123                     return rs[selector];
14124                 }
14125                 for(var i = 0; i < selector.length; i++){
14126                         if(rs[selector[i]]){
14127                                 return rs[selector[i]];
14128                         }
14129                 }
14130                 return null;
14131         },
14132         
14133         
14134         /**
14135     * Updates a rule property
14136     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14137     * @param {String} property The css property
14138     * @param {String} value The new value for the property
14139     * @return {Boolean} true If a rule was found and updated
14140     */
14141    updateRule : function(selector, property, value){
14142                 if(!(selector instanceof Array)){
14143                         var rule = this.getRule(selector);
14144                         if(rule){
14145                                 rule.style[property.replace(camelRe, camelFn)] = value;
14146                                 return true;
14147                         }
14148                 }else{
14149                         for(var i = 0; i < selector.length; i++){
14150                                 if(this.updateRule(selector[i], property, value)){
14151                                         return true;
14152                                 }
14153                         }
14154                 }
14155                 return false;
14156         }
14157    };   
14158 }();/*
14159  * Based on:
14160  * Ext JS Library 1.1.1
14161  * Copyright(c) 2006-2007, Ext JS, LLC.
14162  *
14163  * Originally Released Under LGPL - original licence link has changed is not relivant.
14164  *
14165  * Fork - LGPL
14166  * <script type="text/javascript">
14167  */
14168
14169  
14170
14171 /**
14172  * @class Roo.util.ClickRepeater
14173  * @extends Roo.util.Observable
14174  * 
14175  * A wrapper class which can be applied to any element. Fires a "click" event while the
14176  * mouse is pressed. The interval between firings may be specified in the config but
14177  * defaults to 10 milliseconds.
14178  * 
14179  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14180  * 
14181  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14182  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14183  * Similar to an autorepeat key delay.
14184  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14185  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14186  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14187  *           "interval" and "delay" are ignored. "immediate" is honored.
14188  * @cfg {Boolean} preventDefault True to prevent the default click event
14189  * @cfg {Boolean} stopDefault True to stop the default click event
14190  * 
14191  * @history
14192  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14193  *     2007-02-02 jvs Renamed to ClickRepeater
14194  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14195  *
14196  *  @constructor
14197  * @param {String/HTMLElement/Element} el The element to listen on
14198  * @param {Object} config
14199  **/
14200 Roo.util.ClickRepeater = function(el, config)
14201 {
14202     this.el = Roo.get(el);
14203     this.el.unselectable();
14204
14205     Roo.apply(this, config);
14206
14207     this.addEvents({
14208     /**
14209      * @event mousedown
14210      * Fires when the mouse button is depressed.
14211      * @param {Roo.util.ClickRepeater} this
14212      */
14213         "mousedown" : true,
14214     /**
14215      * @event click
14216      * Fires on a specified interval during the time the element is pressed.
14217      * @param {Roo.util.ClickRepeater} this
14218      */
14219         "click" : true,
14220     /**
14221      * @event mouseup
14222      * Fires when the mouse key is released.
14223      * @param {Roo.util.ClickRepeater} this
14224      */
14225         "mouseup" : true
14226     });
14227
14228     this.el.on("mousedown", this.handleMouseDown, this);
14229     if(this.preventDefault || this.stopDefault){
14230         this.el.on("click", function(e){
14231             if(this.preventDefault){
14232                 e.preventDefault();
14233             }
14234             if(this.stopDefault){
14235                 e.stopEvent();
14236             }
14237         }, this);
14238     }
14239
14240     // allow inline handler
14241     if(this.handler){
14242         this.on("click", this.handler,  this.scope || this);
14243     }
14244
14245     Roo.util.ClickRepeater.superclass.constructor.call(this);
14246 };
14247
14248 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14249     interval : 20,
14250     delay: 250,
14251     preventDefault : true,
14252     stopDefault : false,
14253     timer : 0,
14254
14255     // private
14256     handleMouseDown : function(){
14257         clearTimeout(this.timer);
14258         this.el.blur();
14259         if(this.pressClass){
14260             this.el.addClass(this.pressClass);
14261         }
14262         this.mousedownTime = new Date();
14263
14264         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14265         this.el.on("mouseout", this.handleMouseOut, this);
14266
14267         this.fireEvent("mousedown", this);
14268         this.fireEvent("click", this);
14269         
14270         this.timer = this.click.defer(this.delay || this.interval, this);
14271     },
14272
14273     // private
14274     click : function(){
14275         this.fireEvent("click", this);
14276         this.timer = this.click.defer(this.getInterval(), this);
14277     },
14278
14279     // private
14280     getInterval: function(){
14281         if(!this.accelerate){
14282             return this.interval;
14283         }
14284         var pressTime = this.mousedownTime.getElapsed();
14285         if(pressTime < 500){
14286             return 400;
14287         }else if(pressTime < 1700){
14288             return 320;
14289         }else if(pressTime < 2600){
14290             return 250;
14291         }else if(pressTime < 3500){
14292             return 180;
14293         }else if(pressTime < 4400){
14294             return 140;
14295         }else if(pressTime < 5300){
14296             return 80;
14297         }else if(pressTime < 6200){
14298             return 50;
14299         }else{
14300             return 10;
14301         }
14302     },
14303
14304     // private
14305     handleMouseOut : function(){
14306         clearTimeout(this.timer);
14307         if(this.pressClass){
14308             this.el.removeClass(this.pressClass);
14309         }
14310         this.el.on("mouseover", this.handleMouseReturn, this);
14311     },
14312
14313     // private
14314     handleMouseReturn : function(){
14315         this.el.un("mouseover", this.handleMouseReturn);
14316         if(this.pressClass){
14317             this.el.addClass(this.pressClass);
14318         }
14319         this.click();
14320     },
14321
14322     // private
14323     handleMouseUp : function(){
14324         clearTimeout(this.timer);
14325         this.el.un("mouseover", this.handleMouseReturn);
14326         this.el.un("mouseout", this.handleMouseOut);
14327         Roo.get(document).un("mouseup", this.handleMouseUp);
14328         this.el.removeClass(this.pressClass);
14329         this.fireEvent("mouseup", this);
14330     }
14331 });/*
14332  * Based on:
14333  * Ext JS Library 1.1.1
14334  * Copyright(c) 2006-2007, Ext JS, LLC.
14335  *
14336  * Originally Released Under LGPL - original licence link has changed is not relivant.
14337  *
14338  * Fork - LGPL
14339  * <script type="text/javascript">
14340  */
14341
14342  
14343 /**
14344  * @class Roo.KeyNav
14345  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14346  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14347  * way to implement custom navigation schemes for any UI component.</p>
14348  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14349  * pageUp, pageDown, del, home, end.  Usage:</p>
14350  <pre><code>
14351 var nav = new Roo.KeyNav("my-element", {
14352     "left" : function(e){
14353         this.moveLeft(e.ctrlKey);
14354     },
14355     "right" : function(e){
14356         this.moveRight(e.ctrlKey);
14357     },
14358     "enter" : function(e){
14359         this.save();
14360     },
14361     scope : this
14362 });
14363 </code></pre>
14364  * @constructor
14365  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14366  * @param {Object} config The config
14367  */
14368 Roo.KeyNav = function(el, config){
14369     this.el = Roo.get(el);
14370     Roo.apply(this, config);
14371     if(!this.disabled){
14372         this.disabled = true;
14373         this.enable();
14374     }
14375 };
14376
14377 Roo.KeyNav.prototype = {
14378     /**
14379      * @cfg {Boolean} disabled
14380      * True to disable this KeyNav instance (defaults to false)
14381      */
14382     disabled : false,
14383     /**
14384      * @cfg {String} defaultEventAction
14385      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14386      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14387      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14388      */
14389     defaultEventAction: "stopEvent",
14390     /**
14391      * @cfg {Boolean} forceKeyDown
14392      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14393      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14394      * handle keydown instead of keypress.
14395      */
14396     forceKeyDown : false,
14397
14398     // private
14399     prepareEvent : function(e){
14400         var k = e.getKey();
14401         var h = this.keyToHandler[k];
14402         //if(h && this[h]){
14403         //    e.stopPropagation();
14404         //}
14405         if(Roo.isSafari && h && k >= 37 && k <= 40){
14406             e.stopEvent();
14407         }
14408     },
14409
14410     // private
14411     relay : function(e){
14412         var k = e.getKey();
14413         var h = this.keyToHandler[k];
14414         if(h && this[h]){
14415             if(this.doRelay(e, this[h], h) !== true){
14416                 e[this.defaultEventAction]();
14417             }
14418         }
14419     },
14420
14421     // private
14422     doRelay : function(e, h, hname){
14423         return h.call(this.scope || this, e);
14424     },
14425
14426     // possible handlers
14427     enter : false,
14428     left : false,
14429     right : false,
14430     up : false,
14431     down : false,
14432     tab : false,
14433     esc : false,
14434     pageUp : false,
14435     pageDown : false,
14436     del : false,
14437     home : false,
14438     end : false,
14439
14440     // quick lookup hash
14441     keyToHandler : {
14442         37 : "left",
14443         39 : "right",
14444         38 : "up",
14445         40 : "down",
14446         33 : "pageUp",
14447         34 : "pageDown",
14448         46 : "del",
14449         36 : "home",
14450         35 : "end",
14451         13 : "enter",
14452         27 : "esc",
14453         9  : "tab"
14454     },
14455
14456         /**
14457          * Enable this KeyNav
14458          */
14459         enable: function(){
14460                 if(this.disabled){
14461             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14462             // the EventObject will normalize Safari automatically
14463             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14464                 this.el.on("keydown", this.relay,  this);
14465             }else{
14466                 this.el.on("keydown", this.prepareEvent,  this);
14467                 this.el.on("keypress", this.relay,  this);
14468             }
14469                     this.disabled = false;
14470                 }
14471         },
14472
14473         /**
14474          * Disable this KeyNav
14475          */
14476         disable: function(){
14477                 if(!this.disabled){
14478                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14479                 this.el.un("keydown", this.relay);
14480             }else{
14481                 this.el.un("keydown", this.prepareEvent);
14482                 this.el.un("keypress", this.relay);
14483             }
14484                     this.disabled = true;
14485                 }
14486         }
14487 };/*
14488  * Based on:
14489  * Ext JS Library 1.1.1
14490  * Copyright(c) 2006-2007, Ext JS, LLC.
14491  *
14492  * Originally Released Under LGPL - original licence link has changed is not relivant.
14493  *
14494  * Fork - LGPL
14495  * <script type="text/javascript">
14496  */
14497
14498  
14499 /**
14500  * @class Roo.KeyMap
14501  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14502  * The constructor accepts the same config object as defined by {@link #addBinding}.
14503  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14504  * combination it will call the function with this signature (if the match is a multi-key
14505  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14506  * A KeyMap can also handle a string representation of keys.<br />
14507  * Usage:
14508  <pre><code>
14509 // map one key by key code
14510 var map = new Roo.KeyMap("my-element", {
14511     key: 13, // or Roo.EventObject.ENTER
14512     fn: myHandler,
14513     scope: myObject
14514 });
14515
14516 // map multiple keys to one action by string
14517 var map = new Roo.KeyMap("my-element", {
14518     key: "a\r\n\t",
14519     fn: myHandler,
14520     scope: myObject
14521 });
14522
14523 // map multiple keys to multiple actions by strings and array of codes
14524 var map = new Roo.KeyMap("my-element", [
14525     {
14526         key: [10,13],
14527         fn: function(){ alert("Return was pressed"); }
14528     }, {
14529         key: "abc",
14530         fn: function(){ alert('a, b or c was pressed'); }
14531     }, {
14532         key: "\t",
14533         ctrl:true,
14534         shift:true,
14535         fn: function(){ alert('Control + shift + tab was pressed.'); }
14536     }
14537 ]);
14538 </code></pre>
14539  * <b>Note: A KeyMap starts enabled</b>
14540  * @constructor
14541  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14542  * @param {Object} config The config (see {@link #addBinding})
14543  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14544  */
14545 Roo.KeyMap = function(el, config, eventName){
14546     this.el  = Roo.get(el);
14547     this.eventName = eventName || "keydown";
14548     this.bindings = [];
14549     if(config){
14550         this.addBinding(config);
14551     }
14552     this.enable();
14553 };
14554
14555 Roo.KeyMap.prototype = {
14556     /**
14557      * True to stop the event from bubbling and prevent the default browser action if the
14558      * key was handled by the KeyMap (defaults to false)
14559      * @type Boolean
14560      */
14561     stopEvent : false,
14562
14563     /**
14564      * Add a new binding to this KeyMap. The following config object properties are supported:
14565      * <pre>
14566 Property    Type             Description
14567 ----------  ---------------  ----------------------------------------------------------------------
14568 key         String/Array     A single keycode or an array of keycodes to handle
14569 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14570 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14571 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14572 fn          Function         The function to call when KeyMap finds the expected key combination
14573 scope       Object           The scope of the callback function
14574 </pre>
14575      *
14576      * Usage:
14577      * <pre><code>
14578 // Create a KeyMap
14579 var map = new Roo.KeyMap(document, {
14580     key: Roo.EventObject.ENTER,
14581     fn: handleKey,
14582     scope: this
14583 });
14584
14585 //Add a new binding to the existing KeyMap later
14586 map.addBinding({
14587     key: 'abc',
14588     shift: true,
14589     fn: handleKey,
14590     scope: this
14591 });
14592 </code></pre>
14593      * @param {Object/Array} config A single KeyMap config or an array of configs
14594      */
14595         addBinding : function(config){
14596         if(config instanceof Array){
14597             for(var i = 0, len = config.length; i < len; i++){
14598                 this.addBinding(config[i]);
14599             }
14600             return;
14601         }
14602         var keyCode = config.key,
14603             shift = config.shift, 
14604             ctrl = config.ctrl, 
14605             alt = config.alt,
14606             fn = config.fn,
14607             scope = config.scope;
14608         if(typeof keyCode == "string"){
14609             var ks = [];
14610             var keyString = keyCode.toUpperCase();
14611             for(var j = 0, len = keyString.length; j < len; j++){
14612                 ks.push(keyString.charCodeAt(j));
14613             }
14614             keyCode = ks;
14615         }
14616         var keyArray = keyCode instanceof Array;
14617         var handler = function(e){
14618             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14619                 var k = e.getKey();
14620                 if(keyArray){
14621                     for(var i = 0, len = keyCode.length; i < len; i++){
14622                         if(keyCode[i] == k){
14623                           if(this.stopEvent){
14624                               e.stopEvent();
14625                           }
14626                           fn.call(scope || window, k, e);
14627                           return;
14628                         }
14629                     }
14630                 }else{
14631                     if(k == keyCode){
14632                         if(this.stopEvent){
14633                            e.stopEvent();
14634                         }
14635                         fn.call(scope || window, k, e);
14636                     }
14637                 }
14638             }
14639         };
14640         this.bindings.push(handler);  
14641         },
14642
14643     /**
14644      * Shorthand for adding a single key listener
14645      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14646      * following options:
14647      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14648      * @param {Function} fn The function to call
14649      * @param {Object} scope (optional) The scope of the function
14650      */
14651     on : function(key, fn, scope){
14652         var keyCode, shift, ctrl, alt;
14653         if(typeof key == "object" && !(key instanceof Array)){
14654             keyCode = key.key;
14655             shift = key.shift;
14656             ctrl = key.ctrl;
14657             alt = key.alt;
14658         }else{
14659             keyCode = key;
14660         }
14661         this.addBinding({
14662             key: keyCode,
14663             shift: shift,
14664             ctrl: ctrl,
14665             alt: alt,
14666             fn: fn,
14667             scope: scope
14668         })
14669     },
14670
14671     // private
14672     handleKeyDown : function(e){
14673             if(this.enabled){ //just in case
14674             var b = this.bindings;
14675             for(var i = 0, len = b.length; i < len; i++){
14676                 b[i].call(this, e);
14677             }
14678             }
14679         },
14680         
14681         /**
14682          * Returns true if this KeyMap is enabled
14683          * @return {Boolean} 
14684          */
14685         isEnabled : function(){
14686             return this.enabled;  
14687         },
14688         
14689         /**
14690          * Enables this KeyMap
14691          */
14692         enable: function(){
14693                 if(!this.enabled){
14694                     this.el.on(this.eventName, this.handleKeyDown, this);
14695                     this.enabled = true;
14696                 }
14697         },
14698
14699         /**
14700          * Disable this KeyMap
14701          */
14702         disable: function(){
14703                 if(this.enabled){
14704                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14705                     this.enabled = false;
14706                 }
14707         }
14708 };/*
14709  * Based on:
14710  * Ext JS Library 1.1.1
14711  * Copyright(c) 2006-2007, Ext JS, LLC.
14712  *
14713  * Originally Released Under LGPL - original licence link has changed is not relivant.
14714  *
14715  * Fork - LGPL
14716  * <script type="text/javascript">
14717  */
14718
14719  
14720 /**
14721  * @class Roo.util.TextMetrics
14722  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14723  * wide, in pixels, a given block of text will be.
14724  * @singleton
14725  */
14726 Roo.util.TextMetrics = function(){
14727     var shared;
14728     return {
14729         /**
14730          * Measures the size of the specified text
14731          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14732          * that can affect the size of the rendered text
14733          * @param {String} text The text to measure
14734          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14735          * in order to accurately measure the text height
14736          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14737          */
14738         measure : function(el, text, fixedWidth){
14739             if(!shared){
14740                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14741             }
14742             shared.bind(el);
14743             shared.setFixedWidth(fixedWidth || 'auto');
14744             return shared.getSize(text);
14745         },
14746
14747         /**
14748          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14749          * the overhead of multiple calls to initialize the style properties on each measurement.
14750          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14751          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14752          * in order to accurately measure the text height
14753          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14754          */
14755         createInstance : function(el, fixedWidth){
14756             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14757         }
14758     };
14759 }();
14760
14761  
14762
14763 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14764     var ml = new Roo.Element(document.createElement('div'));
14765     document.body.appendChild(ml.dom);
14766     ml.position('absolute');
14767     ml.setLeftTop(-1000, -1000);
14768     ml.hide();
14769
14770     if(fixedWidth){
14771         ml.setWidth(fixedWidth);
14772     }
14773      
14774     var instance = {
14775         /**
14776          * Returns the size of the specified text based on the internal element's style and width properties
14777          * @memberOf Roo.util.TextMetrics.Instance#
14778          * @param {String} text The text to measure
14779          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14780          */
14781         getSize : function(text){
14782             ml.update(text);
14783             var s = ml.getSize();
14784             ml.update('');
14785             return s;
14786         },
14787
14788         /**
14789          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14790          * that can affect the size of the rendered text
14791          * @memberOf Roo.util.TextMetrics.Instance#
14792          * @param {String/HTMLElement} el The element, dom node or id
14793          */
14794         bind : function(el){
14795             ml.setStyle(
14796                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14797             );
14798         },
14799
14800         /**
14801          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14802          * to set a fixed width in order to accurately measure the text height.
14803          * @memberOf Roo.util.TextMetrics.Instance#
14804          * @param {Number} width The width to set on the element
14805          */
14806         setFixedWidth : function(width){
14807             ml.setWidth(width);
14808         },
14809
14810         /**
14811          * Returns the measured width of the specified text
14812          * @memberOf Roo.util.TextMetrics.Instance#
14813          * @param {String} text The text to measure
14814          * @return {Number} width The width in pixels
14815          */
14816         getWidth : function(text){
14817             ml.dom.style.width = 'auto';
14818             return this.getSize(text).width;
14819         },
14820
14821         /**
14822          * Returns the measured height of the specified text.  For multiline text, be sure to call
14823          * {@link #setFixedWidth} if necessary.
14824          * @memberOf Roo.util.TextMetrics.Instance#
14825          * @param {String} text The text to measure
14826          * @return {Number} height The height in pixels
14827          */
14828         getHeight : function(text){
14829             return this.getSize(text).height;
14830         }
14831     };
14832
14833     instance.bind(bindTo);
14834
14835     return instance;
14836 };
14837
14838 // backwards compat
14839 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14840  * Based on:
14841  * Ext JS Library 1.1.1
14842  * Copyright(c) 2006-2007, Ext JS, LLC.
14843  *
14844  * Originally Released Under LGPL - original licence link has changed is not relivant.
14845  *
14846  * Fork - LGPL
14847  * <script type="text/javascript">
14848  */
14849
14850 /**
14851  * @class Roo.state.Provider
14852  * Abstract base class for state provider implementations. This class provides methods
14853  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14854  * Provider interface.
14855  */
14856 Roo.state.Provider = function(){
14857     /**
14858      * @event statechange
14859      * Fires when a state change occurs.
14860      * @param {Provider} this This state provider
14861      * @param {String} key The state key which was changed
14862      * @param {String} value The encoded value for the state
14863      */
14864     this.addEvents({
14865         "statechange": true
14866     });
14867     this.state = {};
14868     Roo.state.Provider.superclass.constructor.call(this);
14869 };
14870 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14871     /**
14872      * Returns the current value for a key
14873      * @param {String} name The key name
14874      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14875      * @return {Mixed} The state data
14876      */
14877     get : function(name, defaultValue){
14878         return typeof this.state[name] == "undefined" ?
14879             defaultValue : this.state[name];
14880     },
14881     
14882     /**
14883      * Clears a value from the state
14884      * @param {String} name The key name
14885      */
14886     clear : function(name){
14887         delete this.state[name];
14888         this.fireEvent("statechange", this, name, null);
14889     },
14890     
14891     /**
14892      * Sets the value for a key
14893      * @param {String} name The key name
14894      * @param {Mixed} value The value to set
14895      */
14896     set : function(name, value){
14897         this.state[name] = value;
14898         this.fireEvent("statechange", this, name, value);
14899     },
14900     
14901     /**
14902      * Decodes a string previously encoded with {@link #encodeValue}.
14903      * @param {String} value The value to decode
14904      * @return {Mixed} The decoded value
14905      */
14906     decodeValue : function(cookie){
14907         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14908         var matches = re.exec(unescape(cookie));
14909         if(!matches || !matches[1]) {
14910             return; // non state cookie
14911         }
14912         var type = matches[1];
14913         var v = matches[2];
14914         switch(type){
14915             case "n":
14916                 return parseFloat(v);
14917             case "d":
14918                 return new Date(Date.parse(v));
14919             case "b":
14920                 return (v == "1");
14921             case "a":
14922                 var all = [];
14923                 var values = v.split("^");
14924                 for(var i = 0, len = values.length; i < len; i++){
14925                     all.push(this.decodeValue(values[i]));
14926                 }
14927                 return all;
14928            case "o":
14929                 var all = {};
14930                 var values = v.split("^");
14931                 for(var i = 0, len = values.length; i < len; i++){
14932                     var kv = values[i].split("=");
14933                     all[kv[0]] = this.decodeValue(kv[1]);
14934                 }
14935                 return all;
14936            default:
14937                 return v;
14938         }
14939     },
14940     
14941     /**
14942      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14943      * @param {Mixed} value The value to encode
14944      * @return {String} The encoded value
14945      */
14946     encodeValue : function(v){
14947         var enc;
14948         if(typeof v == "number"){
14949             enc = "n:" + v;
14950         }else if(typeof v == "boolean"){
14951             enc = "b:" + (v ? "1" : "0");
14952         }else if(v instanceof Date){
14953             enc = "d:" + v.toGMTString();
14954         }else if(v instanceof Array){
14955             var flat = "";
14956             for(var i = 0, len = v.length; i < len; i++){
14957                 flat += this.encodeValue(v[i]);
14958                 if(i != len-1) {
14959                     flat += "^";
14960                 }
14961             }
14962             enc = "a:" + flat;
14963         }else if(typeof v == "object"){
14964             var flat = "";
14965             for(var key in v){
14966                 if(typeof v[key] != "function"){
14967                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14968                 }
14969             }
14970             enc = "o:" + flat.substring(0, flat.length-1);
14971         }else{
14972             enc = "s:" + v;
14973         }
14974         return escape(enc);        
14975     }
14976 });
14977
14978 /*
14979  * Based on:
14980  * Ext JS Library 1.1.1
14981  * Copyright(c) 2006-2007, Ext JS, LLC.
14982  *
14983  * Originally Released Under LGPL - original licence link has changed is not relivant.
14984  *
14985  * Fork - LGPL
14986  * <script type="text/javascript">
14987  */
14988 /**
14989  * @class Roo.state.Manager
14990  * This is the global state manager. By default all components that are "state aware" check this class
14991  * for state information if you don't pass them a custom state provider. In order for this class
14992  * to be useful, it must be initialized with a provider when your application initializes.
14993  <pre><code>
14994 // in your initialization function
14995 init : function(){
14996    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14997    ...
14998    // supposed you have a {@link Roo.BorderLayout}
14999    var layout = new Roo.BorderLayout(...);
15000    layout.restoreState();
15001    // or a {Roo.BasicDialog}
15002    var dialog = new Roo.BasicDialog(...);
15003    dialog.restoreState();
15004  </code></pre>
15005  * @singleton
15006  */
15007 Roo.state.Manager = function(){
15008     var provider = new Roo.state.Provider();
15009     
15010     return {
15011         /**
15012          * Configures the default state provider for your application
15013          * @param {Provider} stateProvider The state provider to set
15014          */
15015         setProvider : function(stateProvider){
15016             provider = stateProvider;
15017         },
15018         
15019         /**
15020          * Returns the current value for a key
15021          * @param {String} name The key name
15022          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15023          * @return {Mixed} The state data
15024          */
15025         get : function(key, defaultValue){
15026             return provider.get(key, defaultValue);
15027         },
15028         
15029         /**
15030          * Sets the value for a key
15031          * @param {String} name The key name
15032          * @param {Mixed} value The state data
15033          */
15034          set : function(key, value){
15035             provider.set(key, value);
15036         },
15037         
15038         /**
15039          * Clears a value from the state
15040          * @param {String} name The key name
15041          */
15042         clear : function(key){
15043             provider.clear(key);
15044         },
15045         
15046         /**
15047          * Gets the currently configured state provider
15048          * @return {Provider} The state provider
15049          */
15050         getProvider : function(){
15051             return provider;
15052         }
15053     };
15054 }();
15055 /*
15056  * Based on:
15057  * Ext JS Library 1.1.1
15058  * Copyright(c) 2006-2007, Ext JS, LLC.
15059  *
15060  * Originally Released Under LGPL - original licence link has changed is not relivant.
15061  *
15062  * Fork - LGPL
15063  * <script type="text/javascript">
15064  */
15065 /**
15066  * @class Roo.state.CookieProvider
15067  * @extends Roo.state.Provider
15068  * The default Provider implementation which saves state via cookies.
15069  * <br />Usage:
15070  <pre><code>
15071    var cp = new Roo.state.CookieProvider({
15072        path: "/cgi-bin/",
15073        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15074        domain: "roojs.com"
15075    })
15076    Roo.state.Manager.setProvider(cp);
15077  </code></pre>
15078  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15079  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15080  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15081  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15082  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15083  * domain the page is running on including the 'www' like 'www.roojs.com')
15084  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15085  * @constructor
15086  * Create a new CookieProvider
15087  * @param {Object} config The configuration object
15088  */
15089 Roo.state.CookieProvider = function(config){
15090     Roo.state.CookieProvider.superclass.constructor.call(this);
15091     this.path = "/";
15092     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15093     this.domain = null;
15094     this.secure = false;
15095     Roo.apply(this, config);
15096     this.state = this.readCookies();
15097 };
15098
15099 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15100     // private
15101     set : function(name, value){
15102         if(typeof value == "undefined" || value === null){
15103             this.clear(name);
15104             return;
15105         }
15106         this.setCookie(name, value);
15107         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15108     },
15109
15110     // private
15111     clear : function(name){
15112         this.clearCookie(name);
15113         Roo.state.CookieProvider.superclass.clear.call(this, name);
15114     },
15115
15116     // private
15117     readCookies : function(){
15118         var cookies = {};
15119         var c = document.cookie + ";";
15120         var re = /\s?(.*?)=(.*?);/g;
15121         var matches;
15122         while((matches = re.exec(c)) != null){
15123             var name = matches[1];
15124             var value = matches[2];
15125             if(name && name.substring(0,3) == "ys-"){
15126                 cookies[name.substr(3)] = this.decodeValue(value);
15127             }
15128         }
15129         return cookies;
15130     },
15131
15132     // private
15133     setCookie : function(name, value){
15134         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15135            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15136            ((this.path == null) ? "" : ("; path=" + this.path)) +
15137            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15138            ((this.secure == true) ? "; secure" : "");
15139     },
15140
15141     // private
15142     clearCookie : function(name){
15143         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15144            ((this.path == null) ? "" : ("; path=" + this.path)) +
15145            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15146            ((this.secure == true) ? "; secure" : "");
15147     }
15148 });/*
15149  * Based on:
15150  * Ext JS Library 1.1.1
15151  * Copyright(c) 2006-2007, Ext JS, LLC.
15152  *
15153  * Originally Released Under LGPL - original licence link has changed is not relivant.
15154  *
15155  * Fork - LGPL
15156  * <script type="text/javascript">
15157  */
15158  
15159
15160 /**
15161  * @class Roo.ComponentMgr
15162  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15163  * @singleton
15164  */
15165 Roo.ComponentMgr = function(){
15166     var all = new Roo.util.MixedCollection();
15167
15168     return {
15169         /**
15170          * Registers a component.
15171          * @param {Roo.Component} c The component
15172          */
15173         register : function(c){
15174             all.add(c);
15175         },
15176
15177         /**
15178          * Unregisters a component.
15179          * @param {Roo.Component} c The component
15180          */
15181         unregister : function(c){
15182             all.remove(c);
15183         },
15184
15185         /**
15186          * Returns a component by id
15187          * @param {String} id The component id
15188          */
15189         get : function(id){
15190             return all.get(id);
15191         },
15192
15193         /**
15194          * Registers a function that will be called when a specified component is added to ComponentMgr
15195          * @param {String} id The component id
15196          * @param {Funtction} fn The callback function
15197          * @param {Object} scope The scope of the callback
15198          */
15199         onAvailable : function(id, fn, scope){
15200             all.on("add", function(index, o){
15201                 if(o.id == id){
15202                     fn.call(scope || o, o);
15203                     all.un("add", fn, scope);
15204                 }
15205             });
15206         }
15207     };
15208 }();/*
15209  * Based on:
15210  * Ext JS Library 1.1.1
15211  * Copyright(c) 2006-2007, Ext JS, LLC.
15212  *
15213  * Originally Released Under LGPL - original licence link has changed is not relivant.
15214  *
15215  * Fork - LGPL
15216  * <script type="text/javascript">
15217  */
15218  
15219 /**
15220  * @class Roo.Component
15221  * @extends Roo.util.Observable
15222  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15223  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15224  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15225  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15226  * All visual components (widgets) that require rendering into a layout should subclass Component.
15227  * @constructor
15228  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15229  * 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
15230  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15231  */
15232 Roo.Component = function(config){
15233     config = config || {};
15234     if(config.tagName || config.dom || typeof config == "string"){ // element object
15235         config = {el: config, id: config.id || config};
15236     }
15237     this.initialConfig = config;
15238
15239     Roo.apply(this, config);
15240     this.addEvents({
15241         /**
15242          * @event disable
15243          * Fires after the component is disabled.
15244              * @param {Roo.Component} this
15245              */
15246         disable : true,
15247         /**
15248          * @event enable
15249          * Fires after the component is enabled.
15250              * @param {Roo.Component} this
15251              */
15252         enable : true,
15253         /**
15254          * @event beforeshow
15255          * Fires before the component is shown.  Return false to stop the show.
15256              * @param {Roo.Component} this
15257              */
15258         beforeshow : true,
15259         /**
15260          * @event show
15261          * Fires after the component is shown.
15262              * @param {Roo.Component} this
15263              */
15264         show : true,
15265         /**
15266          * @event beforehide
15267          * Fires before the component is hidden. Return false to stop the hide.
15268              * @param {Roo.Component} this
15269              */
15270         beforehide : true,
15271         /**
15272          * @event hide
15273          * Fires after the component is hidden.
15274              * @param {Roo.Component} this
15275              */
15276         hide : true,
15277         /**
15278          * @event beforerender
15279          * Fires before the component is rendered. Return false to stop the render.
15280              * @param {Roo.Component} this
15281              */
15282         beforerender : true,
15283         /**
15284          * @event render
15285          * Fires after the component is rendered.
15286              * @param {Roo.Component} this
15287              */
15288         render : true,
15289         /**
15290          * @event beforedestroy
15291          * Fires before the component is destroyed. Return false to stop the destroy.
15292              * @param {Roo.Component} this
15293              */
15294         beforedestroy : true,
15295         /**
15296          * @event destroy
15297          * Fires after the component is destroyed.
15298              * @param {Roo.Component} this
15299              */
15300         destroy : true
15301     });
15302     if(!this.id){
15303         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15304     }
15305     Roo.ComponentMgr.register(this);
15306     Roo.Component.superclass.constructor.call(this);
15307     this.initComponent();
15308     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15309         this.render(this.renderTo);
15310         delete this.renderTo;
15311     }
15312 };
15313
15314 /** @private */
15315 Roo.Component.AUTO_ID = 1000;
15316
15317 Roo.extend(Roo.Component, Roo.util.Observable, {
15318     /**
15319      * @scope Roo.Component.prototype
15320      * @type {Boolean}
15321      * true if this component is hidden. Read-only.
15322      */
15323     hidden : false,
15324     /**
15325      * @type {Boolean}
15326      * true if this component is disabled. Read-only.
15327      */
15328     disabled : false,
15329     /**
15330      * @type {Boolean}
15331      * true if this component has been rendered. Read-only.
15332      */
15333     rendered : false,
15334     
15335     /** @cfg {String} disableClass
15336      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15337      */
15338     disabledClass : "x-item-disabled",
15339         /** @cfg {Boolean} allowDomMove
15340          * Whether the component can move the Dom node when rendering (defaults to true).
15341          */
15342     allowDomMove : true,
15343     /** @cfg {String} hideMode (display|visibility)
15344      * How this component should hidden. Supported values are
15345      * "visibility" (css visibility), "offsets" (negative offset position) and
15346      * "display" (css display) - defaults to "display".
15347      */
15348     hideMode: 'display',
15349
15350     /** @private */
15351     ctype : "Roo.Component",
15352
15353     /**
15354      * @cfg {String} actionMode 
15355      * which property holds the element that used for  hide() / show() / disable() / enable()
15356      * default is 'el' 
15357      */
15358     actionMode : "el",
15359
15360     /** @private */
15361     getActionEl : function(){
15362         return this[this.actionMode];
15363     },
15364
15365     initComponent : Roo.emptyFn,
15366     /**
15367      * If this is a lazy rendering component, render it to its container element.
15368      * @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.
15369      */
15370     render : function(container, position){
15371         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15372             if(!container && this.el){
15373                 this.el = Roo.get(this.el);
15374                 container = this.el.dom.parentNode;
15375                 this.allowDomMove = false;
15376             }
15377             this.container = Roo.get(container);
15378             this.rendered = true;
15379             if(position !== undefined){
15380                 if(typeof position == 'number'){
15381                     position = this.container.dom.childNodes[position];
15382                 }else{
15383                     position = Roo.getDom(position);
15384                 }
15385             }
15386             this.onRender(this.container, position || null);
15387             if(this.cls){
15388                 this.el.addClass(this.cls);
15389                 delete this.cls;
15390             }
15391             if(this.style){
15392                 this.el.applyStyles(this.style);
15393                 delete this.style;
15394             }
15395             this.fireEvent("render", this);
15396             this.afterRender(this.container);
15397             if(this.hidden){
15398                 this.hide();
15399             }
15400             if(this.disabled){
15401                 this.disable();
15402             }
15403         }
15404         return this;
15405     },
15406
15407     /** @private */
15408     // default function is not really useful
15409     onRender : function(ct, position){
15410         if(this.el){
15411             this.el = Roo.get(this.el);
15412             if(this.allowDomMove !== false){
15413                 ct.dom.insertBefore(this.el.dom, position);
15414             }
15415         }
15416     },
15417
15418     /** @private */
15419     getAutoCreate : function(){
15420         var cfg = typeof this.autoCreate == "object" ?
15421                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15422         if(this.id && !cfg.id){
15423             cfg.id = this.id;
15424         }
15425         return cfg;
15426     },
15427
15428     /** @private */
15429     afterRender : Roo.emptyFn,
15430
15431     /**
15432      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15433      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15434      */
15435     destroy : function(){
15436         if(this.fireEvent("beforedestroy", this) !== false){
15437             this.purgeListeners();
15438             this.beforeDestroy();
15439             if(this.rendered){
15440                 this.el.removeAllListeners();
15441                 this.el.remove();
15442                 if(this.actionMode == "container"){
15443                     this.container.remove();
15444                 }
15445             }
15446             this.onDestroy();
15447             Roo.ComponentMgr.unregister(this);
15448             this.fireEvent("destroy", this);
15449         }
15450     },
15451
15452         /** @private */
15453     beforeDestroy : function(){
15454
15455     },
15456
15457         /** @private */
15458         onDestroy : function(){
15459
15460     },
15461
15462     /**
15463      * Returns the underlying {@link Roo.Element}.
15464      * @return {Roo.Element} The element
15465      */
15466     getEl : function(){
15467         return this.el;
15468     },
15469
15470     /**
15471      * Returns the id of this component.
15472      * @return {String}
15473      */
15474     getId : function(){
15475         return this.id;
15476     },
15477
15478     /**
15479      * Try to focus this component.
15480      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15481      * @return {Roo.Component} this
15482      */
15483     focus : function(selectText){
15484         if(this.rendered){
15485             this.el.focus();
15486             if(selectText === true){
15487                 this.el.dom.select();
15488             }
15489         }
15490         return this;
15491     },
15492
15493     /** @private */
15494     blur : function(){
15495         if(this.rendered){
15496             this.el.blur();
15497         }
15498         return this;
15499     },
15500
15501     /**
15502      * Disable this component.
15503      * @return {Roo.Component} this
15504      */
15505     disable : function(){
15506         if(this.rendered){
15507             this.onDisable();
15508         }
15509         this.disabled = true;
15510         this.fireEvent("disable", this);
15511         return this;
15512     },
15513
15514         // private
15515     onDisable : function(){
15516         this.getActionEl().addClass(this.disabledClass);
15517         this.el.dom.disabled = true;
15518     },
15519
15520     /**
15521      * Enable this component.
15522      * @return {Roo.Component} this
15523      */
15524     enable : function(){
15525         if(this.rendered){
15526             this.onEnable();
15527         }
15528         this.disabled = false;
15529         this.fireEvent("enable", this);
15530         return this;
15531     },
15532
15533         // private
15534     onEnable : function(){
15535         this.getActionEl().removeClass(this.disabledClass);
15536         this.el.dom.disabled = false;
15537     },
15538
15539     /**
15540      * Convenience function for setting disabled/enabled by boolean.
15541      * @param {Boolean} disabled
15542      */
15543     setDisabled : function(disabled){
15544         this[disabled ? "disable" : "enable"]();
15545     },
15546
15547     /**
15548      * Show this component.
15549      * @return {Roo.Component} this
15550      */
15551     show: function(){
15552         if(this.fireEvent("beforeshow", this) !== false){
15553             this.hidden = false;
15554             if(this.rendered){
15555                 this.onShow();
15556             }
15557             this.fireEvent("show", this);
15558         }
15559         return this;
15560     },
15561
15562     // private
15563     onShow : function(){
15564         var ae = this.getActionEl();
15565         if(this.hideMode == 'visibility'){
15566             ae.dom.style.visibility = "visible";
15567         }else if(this.hideMode == 'offsets'){
15568             ae.removeClass('x-hidden');
15569         }else{
15570             ae.dom.style.display = "";
15571         }
15572     },
15573
15574     /**
15575      * Hide this component.
15576      * @return {Roo.Component} this
15577      */
15578     hide: function(){
15579         if(this.fireEvent("beforehide", this) !== false){
15580             this.hidden = true;
15581             if(this.rendered){
15582                 this.onHide();
15583             }
15584             this.fireEvent("hide", this);
15585         }
15586         return this;
15587     },
15588
15589     // private
15590     onHide : function(){
15591         var ae = this.getActionEl();
15592         if(this.hideMode == 'visibility'){
15593             ae.dom.style.visibility = "hidden";
15594         }else if(this.hideMode == 'offsets'){
15595             ae.addClass('x-hidden');
15596         }else{
15597             ae.dom.style.display = "none";
15598         }
15599     },
15600
15601     /**
15602      * Convenience function to hide or show this component by boolean.
15603      * @param {Boolean} visible True to show, false to hide
15604      * @return {Roo.Component} this
15605      */
15606     setVisible: function(visible){
15607         if(visible) {
15608             this.show();
15609         }else{
15610             this.hide();
15611         }
15612         return this;
15613     },
15614
15615     /**
15616      * Returns true if this component is visible.
15617      */
15618     isVisible : function(){
15619         return this.getActionEl().isVisible();
15620     },
15621
15622     cloneConfig : function(overrides){
15623         overrides = overrides || {};
15624         var id = overrides.id || Roo.id();
15625         var cfg = Roo.applyIf(overrides, this.initialConfig);
15626         cfg.id = id; // prevent dup id
15627         return new this.constructor(cfg);
15628     }
15629 });/*
15630  * Based on:
15631  * Ext JS Library 1.1.1
15632  * Copyright(c) 2006-2007, Ext JS, LLC.
15633  *
15634  * Originally Released Under LGPL - original licence link has changed is not relivant.
15635  *
15636  * Fork - LGPL
15637  * <script type="text/javascript">
15638  */
15639
15640 /**
15641  * @class Roo.BoxComponent
15642  * @extends Roo.Component
15643  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15644  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15645  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15646  * layout containers.
15647  * @constructor
15648  * @param {Roo.Element/String/Object} config The configuration options.
15649  */
15650 Roo.BoxComponent = function(config){
15651     Roo.Component.call(this, config);
15652     this.addEvents({
15653         /**
15654          * @event resize
15655          * Fires after the component is resized.
15656              * @param {Roo.Component} this
15657              * @param {Number} adjWidth The box-adjusted width that was set
15658              * @param {Number} adjHeight The box-adjusted height that was set
15659              * @param {Number} rawWidth The width that was originally specified
15660              * @param {Number} rawHeight The height that was originally specified
15661              */
15662         resize : true,
15663         /**
15664          * @event move
15665          * Fires after the component is moved.
15666              * @param {Roo.Component} this
15667              * @param {Number} x The new x position
15668              * @param {Number} y The new y position
15669              */
15670         move : true
15671     });
15672 };
15673
15674 Roo.extend(Roo.BoxComponent, Roo.Component, {
15675     // private, set in afterRender to signify that the component has been rendered
15676     boxReady : false,
15677     // private, used to defer height settings to subclasses
15678     deferHeight: false,
15679     /** @cfg {Number} width
15680      * width (optional) size of component
15681      */
15682      /** @cfg {Number} height
15683      * height (optional) size of component
15684      */
15685      
15686     /**
15687      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15688      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15689      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15690      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15691      * @return {Roo.BoxComponent} this
15692      */
15693     setSize : function(w, h){
15694         // support for standard size objects
15695         if(typeof w == 'object'){
15696             h = w.height;
15697             w = w.width;
15698         }
15699         // not rendered
15700         if(!this.boxReady){
15701             this.width = w;
15702             this.height = h;
15703             return this;
15704         }
15705
15706         // prevent recalcs when not needed
15707         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15708             return this;
15709         }
15710         this.lastSize = {width: w, height: h};
15711
15712         var adj = this.adjustSize(w, h);
15713         var aw = adj.width, ah = adj.height;
15714         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15715             var rz = this.getResizeEl();
15716             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15717                 rz.setSize(aw, ah);
15718             }else if(!this.deferHeight && ah !== undefined){
15719                 rz.setHeight(ah);
15720             }else if(aw !== undefined){
15721                 rz.setWidth(aw);
15722             }
15723             this.onResize(aw, ah, w, h);
15724             this.fireEvent('resize', this, aw, ah, w, h);
15725         }
15726         return this;
15727     },
15728
15729     /**
15730      * Gets the current size of the component's underlying element.
15731      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15732      */
15733     getSize : function(){
15734         return this.el.getSize();
15735     },
15736
15737     /**
15738      * Gets the current XY position of the component's underlying element.
15739      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15740      * @return {Array} The XY position of the element (e.g., [100, 200])
15741      */
15742     getPosition : function(local){
15743         if(local === true){
15744             return [this.el.getLeft(true), this.el.getTop(true)];
15745         }
15746         return this.xy || this.el.getXY();
15747     },
15748
15749     /**
15750      * Gets the current box measurements of the component's underlying element.
15751      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15752      * @returns {Object} box An object in the format {x, y, width, height}
15753      */
15754     getBox : function(local){
15755         var s = this.el.getSize();
15756         if(local){
15757             s.x = this.el.getLeft(true);
15758             s.y = this.el.getTop(true);
15759         }else{
15760             var xy = this.xy || this.el.getXY();
15761             s.x = xy[0];
15762             s.y = xy[1];
15763         }
15764         return s;
15765     },
15766
15767     /**
15768      * Sets the current box measurements of the component's underlying element.
15769      * @param {Object} box An object in the format {x, y, width, height}
15770      * @returns {Roo.BoxComponent} this
15771      */
15772     updateBox : function(box){
15773         this.setSize(box.width, box.height);
15774         this.setPagePosition(box.x, box.y);
15775         return this;
15776     },
15777
15778     // protected
15779     getResizeEl : function(){
15780         return this.resizeEl || this.el;
15781     },
15782
15783     // protected
15784     getPositionEl : function(){
15785         return this.positionEl || this.el;
15786     },
15787
15788     /**
15789      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15790      * This method fires the move event.
15791      * @param {Number} left The new left
15792      * @param {Number} top The new top
15793      * @returns {Roo.BoxComponent} this
15794      */
15795     setPosition : function(x, y){
15796         this.x = x;
15797         this.y = y;
15798         if(!this.boxReady){
15799             return this;
15800         }
15801         var adj = this.adjustPosition(x, y);
15802         var ax = adj.x, ay = adj.y;
15803
15804         var el = this.getPositionEl();
15805         if(ax !== undefined || ay !== undefined){
15806             if(ax !== undefined && ay !== undefined){
15807                 el.setLeftTop(ax, ay);
15808             }else if(ax !== undefined){
15809                 el.setLeft(ax);
15810             }else if(ay !== undefined){
15811                 el.setTop(ay);
15812             }
15813             this.onPosition(ax, ay);
15814             this.fireEvent('move', this, ax, ay);
15815         }
15816         return this;
15817     },
15818
15819     /**
15820      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15821      * This method fires the move event.
15822      * @param {Number} x The new x position
15823      * @param {Number} y The new y position
15824      * @returns {Roo.BoxComponent} this
15825      */
15826     setPagePosition : function(x, y){
15827         this.pageX = x;
15828         this.pageY = y;
15829         if(!this.boxReady){
15830             return;
15831         }
15832         if(x === undefined || y === undefined){ // cannot translate undefined points
15833             return;
15834         }
15835         var p = this.el.translatePoints(x, y);
15836         this.setPosition(p.left, p.top);
15837         return this;
15838     },
15839
15840     // private
15841     onRender : function(ct, position){
15842         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15843         if(this.resizeEl){
15844             this.resizeEl = Roo.get(this.resizeEl);
15845         }
15846         if(this.positionEl){
15847             this.positionEl = Roo.get(this.positionEl);
15848         }
15849     },
15850
15851     // private
15852     afterRender : function(){
15853         Roo.BoxComponent.superclass.afterRender.call(this);
15854         this.boxReady = true;
15855         this.setSize(this.width, this.height);
15856         if(this.x || this.y){
15857             this.setPosition(this.x, this.y);
15858         }
15859         if(this.pageX || this.pageY){
15860             this.setPagePosition(this.pageX, this.pageY);
15861         }
15862     },
15863
15864     /**
15865      * Force the component's size to recalculate based on the underlying element's current height and width.
15866      * @returns {Roo.BoxComponent} this
15867      */
15868     syncSize : function(){
15869         delete this.lastSize;
15870         this.setSize(this.el.getWidth(), this.el.getHeight());
15871         return this;
15872     },
15873
15874     /**
15875      * Called after the component is resized, this method is empty by default but can be implemented by any
15876      * subclass that needs to perform custom logic after a resize occurs.
15877      * @param {Number} adjWidth The box-adjusted width that was set
15878      * @param {Number} adjHeight The box-adjusted height that was set
15879      * @param {Number} rawWidth The width that was originally specified
15880      * @param {Number} rawHeight The height that was originally specified
15881      */
15882     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15883
15884     },
15885
15886     /**
15887      * Called after the component is moved, this method is empty by default but can be implemented by any
15888      * subclass that needs to perform custom logic after a move occurs.
15889      * @param {Number} x The new x position
15890      * @param {Number} y The new y position
15891      */
15892     onPosition : function(x, y){
15893
15894     },
15895
15896     // private
15897     adjustSize : function(w, h){
15898         if(this.autoWidth){
15899             w = 'auto';
15900         }
15901         if(this.autoHeight){
15902             h = 'auto';
15903         }
15904         return {width : w, height: h};
15905     },
15906
15907     // private
15908     adjustPosition : function(x, y){
15909         return {x : x, y: y};
15910     }
15911 });/*
15912  * Original code for Roojs - LGPL
15913  * <script type="text/javascript">
15914  */
15915  
15916 /**
15917  * @class Roo.XComponent
15918  * A delayed Element creator...
15919  * Or a way to group chunks of interface together.
15920  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15921  *  used in conjunction with XComponent.build() it will create an instance of each element,
15922  *  then call addxtype() to build the User interface.
15923  * 
15924  * Mypart.xyx = new Roo.XComponent({
15925
15926     parent : 'Mypart.xyz', // empty == document.element.!!
15927     order : '001',
15928     name : 'xxxx'
15929     region : 'xxxx'
15930     disabled : function() {} 
15931      
15932     tree : function() { // return an tree of xtype declared components
15933         var MODULE = this;
15934         return 
15935         {
15936             xtype : 'NestedLayoutPanel',
15937             // technicall
15938         }
15939      ]
15940  *})
15941  *
15942  *
15943  * It can be used to build a big heiracy, with parent etc.
15944  * or you can just use this to render a single compoent to a dom element
15945  * MYPART.render(Roo.Element | String(id) | dom_element )
15946  *
15947  *
15948  * Usage patterns.
15949  *
15950  * Classic Roo
15951  *
15952  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15953  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15954  *
15955  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15956  *
15957  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15958  * - if mulitple topModules exist, the last one is defined as the top module.
15959  *
15960  * Embeded Roo
15961  * 
15962  * When the top level or multiple modules are to embedded into a existing HTML page,
15963  * the parent element can container '#id' of the element where the module will be drawn.
15964  *
15965  * Bootstrap Roo
15966  *
15967  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15968  * it relies more on a include mechanism, where sub modules are included into an outer page.
15969  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15970  * 
15971  * Bootstrap Roo Included elements
15972  *
15973  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15974  * hence confusing the component builder as it thinks there are multiple top level elements. 
15975  *
15976  * 
15977  * 
15978  * @extends Roo.util.Observable
15979  * @constructor
15980  * @param cfg {Object} configuration of component
15981  * 
15982  */
15983 Roo.XComponent = function(cfg) {
15984     Roo.apply(this, cfg);
15985     this.addEvents({ 
15986         /**
15987              * @event built
15988              * Fires when this the componnt is built
15989              * @param {Roo.XComponent} c the component
15990              */
15991         'built' : true
15992         
15993     });
15994     this.region = this.region || 'center'; // default..
15995     Roo.XComponent.register(this);
15996     this.modules = false;
15997     this.el = false; // where the layout goes..
15998     
15999     
16000 }
16001 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16002     /**
16003      * @property el
16004      * The created element (with Roo.factory())
16005      * @type {Roo.Layout}
16006      */
16007     el  : false,
16008     
16009     /**
16010      * @property el
16011      * for BC  - use el in new code
16012      * @type {Roo.Layout}
16013      */
16014     panel : false,
16015     
16016     /**
16017      * @property layout
16018      * for BC  - use el in new code
16019      * @type {Roo.Layout}
16020      */
16021     layout : false,
16022     
16023      /**
16024      * @cfg {Function|boolean} disabled
16025      * If this module is disabled by some rule, return true from the funtion
16026      */
16027     disabled : false,
16028     
16029     /**
16030      * @cfg {String} parent 
16031      * Name of parent element which it get xtype added to..
16032      */
16033     parent: false,
16034     
16035     /**
16036      * @cfg {String} order
16037      * Used to set the order in which elements are created (usefull for multiple tabs)
16038      */
16039     
16040     order : false,
16041     /**
16042      * @cfg {String} name
16043      * String to display while loading.
16044      */
16045     name : false,
16046     /**
16047      * @cfg {String} region
16048      * Region to render component to (defaults to center)
16049      */
16050     region : 'center',
16051     
16052     /**
16053      * @cfg {Array} items
16054      * A single item array - the first element is the root of the tree..
16055      * It's done this way to stay compatible with the Xtype system...
16056      */
16057     items : false,
16058     
16059     /**
16060      * @property _tree
16061      * The method that retuns the tree of parts that make up this compoennt 
16062      * @type {function}
16063      */
16064     _tree  : false,
16065     
16066      /**
16067      * render
16068      * render element to dom or tree
16069      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16070      */
16071     
16072     render : function(el)
16073     {
16074         
16075         el = el || false;
16076         var hp = this.parent ? 1 : 0;
16077         Roo.debug &&  Roo.log(this);
16078         
16079         var tree = this._tree ? this._tree() : this.tree();
16080
16081         
16082         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16083             // if parent is a '#.....' string, then let's use that..
16084             var ename = this.parent.substr(1);
16085             this.parent = false;
16086             Roo.debug && Roo.log(ename);
16087             switch (ename) {
16088                 case 'bootstrap-body':
16089                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16090                         // this is the BorderLayout standard?
16091                        this.parent = { el : true };
16092                        break;
16093                     }
16094                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16095                         // need to insert stuff...
16096                         this.parent =  {
16097                              el : new Roo.bootstrap.layout.Border({
16098                                  el : document.body, 
16099                      
16100                                  center: {
16101                                     titlebar: false,
16102                                     autoScroll:false,
16103                                     closeOnTab: true,
16104                                     tabPosition: 'top',
16105                                       //resizeTabs: true,
16106                                     alwaysShowTabs: true,
16107                                     hideTabs: false
16108                                      //minTabWidth: 140
16109                                  }
16110                              })
16111                         
16112                          };
16113                          break;
16114                     }
16115                          
16116                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16117                         this.parent = { el :  new  Roo.bootstrap.Body() };
16118                         Roo.debug && Roo.log("setting el to doc body");
16119                          
16120                     } else {
16121                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16122                     }
16123                     break;
16124                 case 'bootstrap':
16125                     this.parent = { el : true};
16126                     // fall through
16127                 default:
16128                     el = Roo.get(ename);
16129                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16130                         this.parent = { el : true};
16131                     }
16132                     
16133                     break;
16134             }
16135                 
16136             
16137             if (!el && !this.parent) {
16138                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16139                 return;
16140             }
16141         }
16142         
16143         Roo.debug && Roo.log("EL:");
16144         Roo.debug && Roo.log(el);
16145         Roo.debug && Roo.log("this.parent.el:");
16146         Roo.debug && Roo.log(this.parent.el);
16147         
16148
16149         // altertive root elements ??? - we need a better way to indicate these.
16150         var is_alt = Roo.XComponent.is_alt ||
16151                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16152                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16153                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16154         
16155         
16156         
16157         if (!this.parent && is_alt) {
16158             //el = Roo.get(document.body);
16159             this.parent = { el : true };
16160         }
16161             
16162             
16163         
16164         if (!this.parent) {
16165             
16166             Roo.debug && Roo.log("no parent - creating one");
16167             
16168             el = el ? Roo.get(el) : false;      
16169             
16170             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16171                 
16172                 this.parent =  {
16173                     el : new Roo.bootstrap.layout.Border({
16174                         el: el || document.body,
16175                     
16176                         center: {
16177                             titlebar: false,
16178                             autoScroll:false,
16179                             closeOnTab: true,
16180                             tabPosition: 'top',
16181                              //resizeTabs: true,
16182                             alwaysShowTabs: false,
16183                             hideTabs: true,
16184                             minTabWidth: 140,
16185                             overflow: 'visible'
16186                          }
16187                      })
16188                 };
16189             } else {
16190             
16191                 // it's a top level one..
16192                 this.parent =  {
16193                     el : new Roo.BorderLayout(el || document.body, {
16194                         center: {
16195                             titlebar: false,
16196                             autoScroll:false,
16197                             closeOnTab: true,
16198                             tabPosition: 'top',
16199                              //resizeTabs: true,
16200                             alwaysShowTabs: el && hp? false :  true,
16201                             hideTabs: el || !hp ? true :  false,
16202                             minTabWidth: 140
16203                          }
16204                     })
16205                 };
16206             }
16207         }
16208         
16209         if (!this.parent.el) {
16210                 // probably an old style ctor, which has been disabled.
16211                 return;
16212
16213         }
16214                 // The 'tree' method is  '_tree now' 
16215             
16216         tree.region = tree.region || this.region;
16217         var is_body = false;
16218         if (this.parent.el === true) {
16219             // bootstrap... - body..
16220             if (el) {
16221                 tree.el = el;
16222             }
16223             this.parent.el = Roo.factory(tree);
16224             is_body = true;
16225         }
16226         
16227         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16228         this.fireEvent('built', this);
16229         
16230         this.panel = this.el;
16231         this.layout = this.panel.layout;
16232         this.parentLayout = this.parent.layout  || false;  
16233          
16234     }
16235     
16236 });
16237
16238 Roo.apply(Roo.XComponent, {
16239     /**
16240      * @property  hideProgress
16241      * true to disable the building progress bar.. usefull on single page renders.
16242      * @type Boolean
16243      */
16244     hideProgress : false,
16245     /**
16246      * @property  buildCompleted
16247      * True when the builder has completed building the interface.
16248      * @type Boolean
16249      */
16250     buildCompleted : false,
16251      
16252     /**
16253      * @property  topModule
16254      * the upper most module - uses document.element as it's constructor.
16255      * @type Object
16256      */
16257      
16258     topModule  : false,
16259       
16260     /**
16261      * @property  modules
16262      * array of modules to be created by registration system.
16263      * @type {Array} of Roo.XComponent
16264      */
16265     
16266     modules : [],
16267     /**
16268      * @property  elmodules
16269      * array of modules to be created by which use #ID 
16270      * @type {Array} of Roo.XComponent
16271      */
16272      
16273     elmodules : [],
16274
16275      /**
16276      * @property  is_alt
16277      * Is an alternative Root - normally used by bootstrap or other systems,
16278      *    where the top element in the tree can wrap 'body' 
16279      * @type {boolean}  (default false)
16280      */
16281      
16282     is_alt : false,
16283     /**
16284      * @property  build_from_html
16285      * Build elements from html - used by bootstrap HTML stuff 
16286      *    - this is cleared after build is completed
16287      * @type {boolean}    (default false)
16288      */
16289      
16290     build_from_html : false,
16291     /**
16292      * Register components to be built later.
16293      *
16294      * This solves the following issues
16295      * - Building is not done on page load, but after an authentication process has occured.
16296      * - Interface elements are registered on page load
16297      * - Parent Interface elements may not be loaded before child, so this handles that..
16298      * 
16299      *
16300      * example:
16301      * 
16302      * MyApp.register({
16303           order : '000001',
16304           module : 'Pman.Tab.projectMgr',
16305           region : 'center',
16306           parent : 'Pman.layout',
16307           disabled : false,  // or use a function..
16308         })
16309      
16310      * * @param {Object} details about module
16311      */
16312     register : function(obj) {
16313                 
16314         Roo.XComponent.event.fireEvent('register', obj);
16315         switch(typeof(obj.disabled) ) {
16316                 
16317             case 'undefined':
16318                 break;
16319             
16320             case 'function':
16321                 if ( obj.disabled() ) {
16322                         return;
16323                 }
16324                 break;
16325             
16326             default:
16327                 if (obj.disabled) {
16328                         return;
16329                 }
16330                 break;
16331         }
16332                 
16333         this.modules.push(obj);
16334          
16335     },
16336     /**
16337      * convert a string to an object..
16338      * eg. 'AAA.BBB' -> finds AAA.BBB
16339
16340      */
16341     
16342     toObject : function(str)
16343     {
16344         if (!str || typeof(str) == 'object') {
16345             return str;
16346         }
16347         if (str.substring(0,1) == '#') {
16348             return str;
16349         }
16350
16351         var ar = str.split('.');
16352         var rt, o;
16353         rt = ar.shift();
16354             /** eval:var:o */
16355         try {
16356             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16357         } catch (e) {
16358             throw "Module not found : " + str;
16359         }
16360         
16361         if (o === false) {
16362             throw "Module not found : " + str;
16363         }
16364         Roo.each(ar, function(e) {
16365             if (typeof(o[e]) == 'undefined') {
16366                 throw "Module not found : " + str;
16367             }
16368             o = o[e];
16369         });
16370         
16371         return o;
16372         
16373     },
16374     
16375     
16376     /**
16377      * move modules into their correct place in the tree..
16378      * 
16379      */
16380     preBuild : function ()
16381     {
16382         var _t = this;
16383         Roo.each(this.modules , function (obj)
16384         {
16385             Roo.XComponent.event.fireEvent('beforebuild', obj);
16386             
16387             var opar = obj.parent;
16388             try { 
16389                 obj.parent = this.toObject(opar);
16390             } catch(e) {
16391                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16392                 return;
16393             }
16394             
16395             if (!obj.parent) {
16396                 Roo.debug && Roo.log("GOT top level module");
16397                 Roo.debug && Roo.log(obj);
16398                 obj.modules = new Roo.util.MixedCollection(false, 
16399                     function(o) { return o.order + '' }
16400                 );
16401                 this.topModule = obj;
16402                 return;
16403             }
16404                         // parent is a string (usually a dom element name..)
16405             if (typeof(obj.parent) == 'string') {
16406                 this.elmodules.push(obj);
16407                 return;
16408             }
16409             if (obj.parent.constructor != Roo.XComponent) {
16410                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16411             }
16412             if (!obj.parent.modules) {
16413                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16414                     function(o) { return o.order + '' }
16415                 );
16416             }
16417             if (obj.parent.disabled) {
16418                 obj.disabled = true;
16419             }
16420             obj.parent.modules.add(obj);
16421         }, this);
16422     },
16423     
16424      /**
16425      * make a list of modules to build.
16426      * @return {Array} list of modules. 
16427      */ 
16428     
16429     buildOrder : function()
16430     {
16431         var _this = this;
16432         var cmp = function(a,b) {   
16433             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16434         };
16435         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16436             throw "No top level modules to build";
16437         }
16438         
16439         // make a flat list in order of modules to build.
16440         var mods = this.topModule ? [ this.topModule ] : [];
16441                 
16442         
16443         // elmodules (is a list of DOM based modules )
16444         Roo.each(this.elmodules, function(e) {
16445             mods.push(e);
16446             if (!this.topModule &&
16447                 typeof(e.parent) == 'string' &&
16448                 e.parent.substring(0,1) == '#' &&
16449                 Roo.get(e.parent.substr(1))
16450                ) {
16451                 
16452                 _this.topModule = e;
16453             }
16454             
16455         });
16456
16457         
16458         // add modules to their parents..
16459         var addMod = function(m) {
16460             Roo.debug && Roo.log("build Order: add: " + m.name);
16461                 
16462             mods.push(m);
16463             if (m.modules && !m.disabled) {
16464                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16465                 m.modules.keySort('ASC',  cmp );
16466                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16467     
16468                 m.modules.each(addMod);
16469             } else {
16470                 Roo.debug && Roo.log("build Order: no child modules");
16471             }
16472             // not sure if this is used any more..
16473             if (m.finalize) {
16474                 m.finalize.name = m.name + " (clean up) ";
16475                 mods.push(m.finalize);
16476             }
16477             
16478         }
16479         if (this.topModule && this.topModule.modules) { 
16480             this.topModule.modules.keySort('ASC',  cmp );
16481             this.topModule.modules.each(addMod);
16482         } 
16483         return mods;
16484     },
16485     
16486      /**
16487      * Build the registered modules.
16488      * @param {Object} parent element.
16489      * @param {Function} optional method to call after module has been added.
16490      * 
16491      */ 
16492    
16493     build : function(opts) 
16494     {
16495         
16496         if (typeof(opts) != 'undefined') {
16497             Roo.apply(this,opts);
16498         }
16499         
16500         this.preBuild();
16501         var mods = this.buildOrder();
16502       
16503         //this.allmods = mods;
16504         //Roo.debug && Roo.log(mods);
16505         //return;
16506         if (!mods.length) { // should not happen
16507             throw "NO modules!!!";
16508         }
16509         
16510         
16511         var msg = "Building Interface...";
16512         // flash it up as modal - so we store the mask!?
16513         if (!this.hideProgress && Roo.MessageBox) {
16514             Roo.MessageBox.show({ title: 'loading' });
16515             Roo.MessageBox.show({
16516                title: "Please wait...",
16517                msg: msg,
16518                width:450,
16519                progress:true,
16520                closable:false,
16521                modal: false
16522               
16523             });
16524         }
16525         var total = mods.length;
16526         
16527         var _this = this;
16528         var progressRun = function() {
16529             if (!mods.length) {
16530                 Roo.debug && Roo.log('hide?');
16531                 if (!this.hideProgress && Roo.MessageBox) {
16532                     Roo.MessageBox.hide();
16533                 }
16534                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16535                 
16536                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16537                 
16538                 // THE END...
16539                 return false;   
16540             }
16541             
16542             var m = mods.shift();
16543             
16544             
16545             Roo.debug && Roo.log(m);
16546             // not sure if this is supported any more.. - modules that are are just function
16547             if (typeof(m) == 'function') { 
16548                 m.call(this);
16549                 return progressRun.defer(10, _this);
16550             } 
16551             
16552             
16553             msg = "Building Interface " + (total  - mods.length) + 
16554                     " of " + total + 
16555                     (m.name ? (' - ' + m.name) : '');
16556                         Roo.debug && Roo.log(msg);
16557             if (!_this.hideProgress &&  Roo.MessageBox) { 
16558                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16559             }
16560             
16561          
16562             // is the module disabled?
16563             var disabled = (typeof(m.disabled) == 'function') ?
16564                 m.disabled.call(m.module.disabled) : m.disabled;    
16565             
16566             
16567             if (disabled) {
16568                 return progressRun(); // we do not update the display!
16569             }
16570             
16571             // now build 
16572             
16573                         
16574                         
16575             m.render();
16576             // it's 10 on top level, and 1 on others??? why...
16577             return progressRun.defer(10, _this);
16578              
16579         }
16580         progressRun.defer(1, _this);
16581      
16582         
16583         
16584     },
16585         
16586         
16587         /**
16588          * Event Object.
16589          *
16590          *
16591          */
16592         event: false, 
16593     /**
16594          * wrapper for event.on - aliased later..  
16595          * Typically use to register a event handler for register:
16596          *
16597          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16598          *
16599          */
16600     on : false
16601    
16602     
16603     
16604 });
16605
16606 Roo.XComponent.event = new Roo.util.Observable({
16607                 events : { 
16608                         /**
16609                          * @event register
16610                          * Fires when an Component is registered,
16611                          * set the disable property on the Component to stop registration.
16612                          * @param {Roo.XComponent} c the component being registerd.
16613                          * 
16614                          */
16615                         'register' : true,
16616             /**
16617                          * @event beforebuild
16618                          * Fires before each Component is built
16619                          * can be used to apply permissions.
16620                          * @param {Roo.XComponent} c the component being registerd.
16621                          * 
16622                          */
16623                         'beforebuild' : true,
16624                         /**
16625                          * @event buildcomplete
16626                          * Fires on the top level element when all elements have been built
16627                          * @param {Roo.XComponent} the top level component.
16628                          */
16629                         'buildcomplete' : true
16630                         
16631                 }
16632 });
16633
16634 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16635  //
16636  /**
16637  * marked - a markdown parser
16638  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16639  * https://github.com/chjj/marked
16640  */
16641
16642
16643 /**
16644  *
16645  * Roo.Markdown - is a very crude wrapper around marked..
16646  *
16647  * usage:
16648  * 
16649  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16650  * 
16651  * Note: move the sample code to the bottom of this
16652  * file before uncommenting it.
16653  *
16654  */
16655
16656 Roo.Markdown = {};
16657 Roo.Markdown.toHtml = function(text) {
16658     
16659     var c = new Roo.Markdown.marked.setOptions({
16660             renderer: new Roo.Markdown.marked.Renderer(),
16661             gfm: true,
16662             tables: true,
16663             breaks: false,
16664             pedantic: false,
16665             sanitize: false,
16666             smartLists: true,
16667             smartypants: false
16668           });
16669     // A FEW HACKS!!?
16670     
16671     text = text.replace(/\\\n/g,' ');
16672     return Roo.Markdown.marked(text);
16673 };
16674 //
16675 // converter
16676 //
16677 // Wraps all "globals" so that the only thing
16678 // exposed is makeHtml().
16679 //
16680 (function() {
16681     
16682     /**
16683      * Block-Level Grammar
16684      */
16685     
16686     var block = {
16687       newline: /^\n+/,
16688       code: /^( {4}[^\n]+\n*)+/,
16689       fences: noop,
16690       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16691       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16692       nptable: noop,
16693       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16694       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16695       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16696       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16697       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16698       table: noop,
16699       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16700       text: /^[^\n]+/
16701     };
16702     
16703     block.bullet = /(?:[*+-]|\d+\.)/;
16704     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16705     block.item = replace(block.item, 'gm')
16706       (/bull/g, block.bullet)
16707       ();
16708     
16709     block.list = replace(block.list)
16710       (/bull/g, block.bullet)
16711       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16712       ('def', '\\n+(?=' + block.def.source + ')')
16713       ();
16714     
16715     block.blockquote = replace(block.blockquote)
16716       ('def', block.def)
16717       ();
16718     
16719     block._tag = '(?!(?:'
16720       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16721       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16722       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16723     
16724     block.html = replace(block.html)
16725       ('comment', /<!--[\s\S]*?-->/)
16726       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16727       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16728       (/tag/g, block._tag)
16729       ();
16730     
16731     block.paragraph = replace(block.paragraph)
16732       ('hr', block.hr)
16733       ('heading', block.heading)
16734       ('lheading', block.lheading)
16735       ('blockquote', block.blockquote)
16736       ('tag', '<' + block._tag)
16737       ('def', block.def)
16738       ();
16739     
16740     /**
16741      * Normal Block Grammar
16742      */
16743     
16744     block.normal = merge({}, block);
16745     
16746     /**
16747      * GFM Block Grammar
16748      */
16749     
16750     block.gfm = merge({}, block.normal, {
16751       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16752       paragraph: /^/,
16753       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16754     });
16755     
16756     block.gfm.paragraph = replace(block.paragraph)
16757       ('(?!', '(?!'
16758         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16759         + block.list.source.replace('\\1', '\\3') + '|')
16760       ();
16761     
16762     /**
16763      * GFM + Tables Block Grammar
16764      */
16765     
16766     block.tables = merge({}, block.gfm, {
16767       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16768       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16769     });
16770     
16771     /**
16772      * Block Lexer
16773      */
16774     
16775     function Lexer(options) {
16776       this.tokens = [];
16777       this.tokens.links = {};
16778       this.options = options || marked.defaults;
16779       this.rules = block.normal;
16780     
16781       if (this.options.gfm) {
16782         if (this.options.tables) {
16783           this.rules = block.tables;
16784         } else {
16785           this.rules = block.gfm;
16786         }
16787       }
16788     }
16789     
16790     /**
16791      * Expose Block Rules
16792      */
16793     
16794     Lexer.rules = block;
16795     
16796     /**
16797      * Static Lex Method
16798      */
16799     
16800     Lexer.lex = function(src, options) {
16801       var lexer = new Lexer(options);
16802       return lexer.lex(src);
16803     };
16804     
16805     /**
16806      * Preprocessing
16807      */
16808     
16809     Lexer.prototype.lex = function(src) {
16810       src = src
16811         .replace(/\r\n|\r/g, '\n')
16812         .replace(/\t/g, '    ')
16813         .replace(/\u00a0/g, ' ')
16814         .replace(/\u2424/g, '\n');
16815     
16816       return this.token(src, true);
16817     };
16818     
16819     /**
16820      * Lexing
16821      */
16822     
16823     Lexer.prototype.token = function(src, top, bq) {
16824       var src = src.replace(/^ +$/gm, '')
16825         , next
16826         , loose
16827         , cap
16828         , bull
16829         , b
16830         , item
16831         , space
16832         , i
16833         , l;
16834     
16835       while (src) {
16836         // newline
16837         if (cap = this.rules.newline.exec(src)) {
16838           src = src.substring(cap[0].length);
16839           if (cap[0].length > 1) {
16840             this.tokens.push({
16841               type: 'space'
16842             });
16843           }
16844         }
16845     
16846         // code
16847         if (cap = this.rules.code.exec(src)) {
16848           src = src.substring(cap[0].length);
16849           cap = cap[0].replace(/^ {4}/gm, '');
16850           this.tokens.push({
16851             type: 'code',
16852             text: !this.options.pedantic
16853               ? cap.replace(/\n+$/, '')
16854               : cap
16855           });
16856           continue;
16857         }
16858     
16859         // fences (gfm)
16860         if (cap = this.rules.fences.exec(src)) {
16861           src = src.substring(cap[0].length);
16862           this.tokens.push({
16863             type: 'code',
16864             lang: cap[2],
16865             text: cap[3] || ''
16866           });
16867           continue;
16868         }
16869     
16870         // heading
16871         if (cap = this.rules.heading.exec(src)) {
16872           src = src.substring(cap[0].length);
16873           this.tokens.push({
16874             type: 'heading',
16875             depth: cap[1].length,
16876             text: cap[2]
16877           });
16878           continue;
16879         }
16880     
16881         // table no leading pipe (gfm)
16882         if (top && (cap = this.rules.nptable.exec(src))) {
16883           src = src.substring(cap[0].length);
16884     
16885           item = {
16886             type: 'table',
16887             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16888             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16889             cells: cap[3].replace(/\n$/, '').split('\n')
16890           };
16891     
16892           for (i = 0; i < item.align.length; i++) {
16893             if (/^ *-+: *$/.test(item.align[i])) {
16894               item.align[i] = 'right';
16895             } else if (/^ *:-+: *$/.test(item.align[i])) {
16896               item.align[i] = 'center';
16897             } else if (/^ *:-+ *$/.test(item.align[i])) {
16898               item.align[i] = 'left';
16899             } else {
16900               item.align[i] = null;
16901             }
16902           }
16903     
16904           for (i = 0; i < item.cells.length; i++) {
16905             item.cells[i] = item.cells[i].split(/ *\| */);
16906           }
16907     
16908           this.tokens.push(item);
16909     
16910           continue;
16911         }
16912     
16913         // lheading
16914         if (cap = this.rules.lheading.exec(src)) {
16915           src = src.substring(cap[0].length);
16916           this.tokens.push({
16917             type: 'heading',
16918             depth: cap[2] === '=' ? 1 : 2,
16919             text: cap[1]
16920           });
16921           continue;
16922         }
16923     
16924         // hr
16925         if (cap = this.rules.hr.exec(src)) {
16926           src = src.substring(cap[0].length);
16927           this.tokens.push({
16928             type: 'hr'
16929           });
16930           continue;
16931         }
16932     
16933         // blockquote
16934         if (cap = this.rules.blockquote.exec(src)) {
16935           src = src.substring(cap[0].length);
16936     
16937           this.tokens.push({
16938             type: 'blockquote_start'
16939           });
16940     
16941           cap = cap[0].replace(/^ *> ?/gm, '');
16942     
16943           // Pass `top` to keep the current
16944           // "toplevel" state. This is exactly
16945           // how markdown.pl works.
16946           this.token(cap, top, true);
16947     
16948           this.tokens.push({
16949             type: 'blockquote_end'
16950           });
16951     
16952           continue;
16953         }
16954     
16955         // list
16956         if (cap = this.rules.list.exec(src)) {
16957           src = src.substring(cap[0].length);
16958           bull = cap[2];
16959     
16960           this.tokens.push({
16961             type: 'list_start',
16962             ordered: bull.length > 1
16963           });
16964     
16965           // Get each top-level item.
16966           cap = cap[0].match(this.rules.item);
16967     
16968           next = false;
16969           l = cap.length;
16970           i = 0;
16971     
16972           for (; i < l; i++) {
16973             item = cap[i];
16974     
16975             // Remove the list item's bullet
16976             // so it is seen as the next token.
16977             space = item.length;
16978             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16979     
16980             // Outdent whatever the
16981             // list item contains. Hacky.
16982             if (~item.indexOf('\n ')) {
16983               space -= item.length;
16984               item = !this.options.pedantic
16985                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16986                 : item.replace(/^ {1,4}/gm, '');
16987             }
16988     
16989             // Determine whether the next list item belongs here.
16990             // Backpedal if it does not belong in this list.
16991             if (this.options.smartLists && i !== l - 1) {
16992               b = block.bullet.exec(cap[i + 1])[0];
16993               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16994                 src = cap.slice(i + 1).join('\n') + src;
16995                 i = l - 1;
16996               }
16997             }
16998     
16999             // Determine whether item is loose or not.
17000             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17001             // for discount behavior.
17002             loose = next || /\n\n(?!\s*$)/.test(item);
17003             if (i !== l - 1) {
17004               next = item.charAt(item.length - 1) === '\n';
17005               if (!loose) { loose = next; }
17006             }
17007     
17008             this.tokens.push({
17009               type: loose
17010                 ? 'loose_item_start'
17011                 : 'list_item_start'
17012             });
17013     
17014             // Recurse.
17015             this.token(item, false, bq);
17016     
17017             this.tokens.push({
17018               type: 'list_item_end'
17019             });
17020           }
17021     
17022           this.tokens.push({
17023             type: 'list_end'
17024           });
17025     
17026           continue;
17027         }
17028     
17029         // html
17030         if (cap = this.rules.html.exec(src)) {
17031           src = src.substring(cap[0].length);
17032           this.tokens.push({
17033             type: this.options.sanitize
17034               ? 'paragraph'
17035               : 'html',
17036             pre: !this.options.sanitizer
17037               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17038             text: cap[0]
17039           });
17040           continue;
17041         }
17042     
17043         // def
17044         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17045           src = src.substring(cap[0].length);
17046           this.tokens.links[cap[1].toLowerCase()] = {
17047             href: cap[2],
17048             title: cap[3]
17049           };
17050           continue;
17051         }
17052     
17053         // table (gfm)
17054         if (top && (cap = this.rules.table.exec(src))) {
17055           src = src.substring(cap[0].length);
17056     
17057           item = {
17058             type: 'table',
17059             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17060             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17061             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17062           };
17063     
17064           for (i = 0; i < item.align.length; i++) {
17065             if (/^ *-+: *$/.test(item.align[i])) {
17066               item.align[i] = 'right';
17067             } else if (/^ *:-+: *$/.test(item.align[i])) {
17068               item.align[i] = 'center';
17069             } else if (/^ *:-+ *$/.test(item.align[i])) {
17070               item.align[i] = 'left';
17071             } else {
17072               item.align[i] = null;
17073             }
17074           }
17075     
17076           for (i = 0; i < item.cells.length; i++) {
17077             item.cells[i] = item.cells[i]
17078               .replace(/^ *\| *| *\| *$/g, '')
17079               .split(/ *\| */);
17080           }
17081     
17082           this.tokens.push(item);
17083     
17084           continue;
17085         }
17086     
17087         // top-level paragraph
17088         if (top && (cap = this.rules.paragraph.exec(src))) {
17089           src = src.substring(cap[0].length);
17090           this.tokens.push({
17091             type: 'paragraph',
17092             text: cap[1].charAt(cap[1].length - 1) === '\n'
17093               ? cap[1].slice(0, -1)
17094               : cap[1]
17095           });
17096           continue;
17097         }
17098     
17099         // text
17100         if (cap = this.rules.text.exec(src)) {
17101           // Top-level should never reach here.
17102           src = src.substring(cap[0].length);
17103           this.tokens.push({
17104             type: 'text',
17105             text: cap[0]
17106           });
17107           continue;
17108         }
17109     
17110         if (src) {
17111           throw new
17112             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17113         }
17114       }
17115     
17116       return this.tokens;
17117     };
17118     
17119     /**
17120      * Inline-Level Grammar
17121      */
17122     
17123     var inline = {
17124       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17125       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17126       url: noop,
17127       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17128       link: /^!?\[(inside)\]\(href\)/,
17129       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17130       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17131       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17132       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17133       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17134       br: /^ {2,}\n(?!\s*$)/,
17135       del: noop,
17136       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17137     };
17138     
17139     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17140     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17141     
17142     inline.link = replace(inline.link)
17143       ('inside', inline._inside)
17144       ('href', inline._href)
17145       ();
17146     
17147     inline.reflink = replace(inline.reflink)
17148       ('inside', inline._inside)
17149       ();
17150     
17151     /**
17152      * Normal Inline Grammar
17153      */
17154     
17155     inline.normal = merge({}, inline);
17156     
17157     /**
17158      * Pedantic Inline Grammar
17159      */
17160     
17161     inline.pedantic = merge({}, inline.normal, {
17162       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17163       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17164     });
17165     
17166     /**
17167      * GFM Inline Grammar
17168      */
17169     
17170     inline.gfm = merge({}, inline.normal, {
17171       escape: replace(inline.escape)('])', '~|])')(),
17172       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17173       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17174       text: replace(inline.text)
17175         (']|', '~]|')
17176         ('|', '|https?://|')
17177         ()
17178     });
17179     
17180     /**
17181      * GFM + Line Breaks Inline Grammar
17182      */
17183     
17184     inline.breaks = merge({}, inline.gfm, {
17185       br: replace(inline.br)('{2,}', '*')(),
17186       text: replace(inline.gfm.text)('{2,}', '*')()
17187     });
17188     
17189     /**
17190      * Inline Lexer & Compiler
17191      */
17192     
17193     function InlineLexer(links, options) {
17194       this.options = options || marked.defaults;
17195       this.links = links;
17196       this.rules = inline.normal;
17197       this.renderer = this.options.renderer || new Renderer;
17198       this.renderer.options = this.options;
17199     
17200       if (!this.links) {
17201         throw new
17202           Error('Tokens array requires a `links` property.');
17203       }
17204     
17205       if (this.options.gfm) {
17206         if (this.options.breaks) {
17207           this.rules = inline.breaks;
17208         } else {
17209           this.rules = inline.gfm;
17210         }
17211       } else if (this.options.pedantic) {
17212         this.rules = inline.pedantic;
17213       }
17214     }
17215     
17216     /**
17217      * Expose Inline Rules
17218      */
17219     
17220     InlineLexer.rules = inline;
17221     
17222     /**
17223      * Static Lexing/Compiling Method
17224      */
17225     
17226     InlineLexer.output = function(src, links, options) {
17227       var inline = new InlineLexer(links, options);
17228       return inline.output(src);
17229     };
17230     
17231     /**
17232      * Lexing/Compiling
17233      */
17234     
17235     InlineLexer.prototype.output = function(src) {
17236       var out = ''
17237         , link
17238         , text
17239         , href
17240         , cap;
17241     
17242       while (src) {
17243         // escape
17244         if (cap = this.rules.escape.exec(src)) {
17245           src = src.substring(cap[0].length);
17246           out += cap[1];
17247           continue;
17248         }
17249     
17250         // autolink
17251         if (cap = this.rules.autolink.exec(src)) {
17252           src = src.substring(cap[0].length);
17253           if (cap[2] === '@') {
17254             text = cap[1].charAt(6) === ':'
17255               ? this.mangle(cap[1].substring(7))
17256               : this.mangle(cap[1]);
17257             href = this.mangle('mailto:') + text;
17258           } else {
17259             text = escape(cap[1]);
17260             href = text;
17261           }
17262           out += this.renderer.link(href, null, text);
17263           continue;
17264         }
17265     
17266         // url (gfm)
17267         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17268           src = src.substring(cap[0].length);
17269           text = escape(cap[1]);
17270           href = text;
17271           out += this.renderer.link(href, null, text);
17272           continue;
17273         }
17274     
17275         // tag
17276         if (cap = this.rules.tag.exec(src)) {
17277           if (!this.inLink && /^<a /i.test(cap[0])) {
17278             this.inLink = true;
17279           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17280             this.inLink = false;
17281           }
17282           src = src.substring(cap[0].length);
17283           out += this.options.sanitize
17284             ? this.options.sanitizer
17285               ? this.options.sanitizer(cap[0])
17286               : escape(cap[0])
17287             : cap[0];
17288           continue;
17289         }
17290     
17291         // link
17292         if (cap = this.rules.link.exec(src)) {
17293           src = src.substring(cap[0].length);
17294           this.inLink = true;
17295           out += this.outputLink(cap, {
17296             href: cap[2],
17297             title: cap[3]
17298           });
17299           this.inLink = false;
17300           continue;
17301         }
17302     
17303         // reflink, nolink
17304         if ((cap = this.rules.reflink.exec(src))
17305             || (cap = this.rules.nolink.exec(src))) {
17306           src = src.substring(cap[0].length);
17307           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17308           link = this.links[link.toLowerCase()];
17309           if (!link || !link.href) {
17310             out += cap[0].charAt(0);
17311             src = cap[0].substring(1) + src;
17312             continue;
17313           }
17314           this.inLink = true;
17315           out += this.outputLink(cap, link);
17316           this.inLink = false;
17317           continue;
17318         }
17319     
17320         // strong
17321         if (cap = this.rules.strong.exec(src)) {
17322           src = src.substring(cap[0].length);
17323           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17324           continue;
17325         }
17326     
17327         // em
17328         if (cap = this.rules.em.exec(src)) {
17329           src = src.substring(cap[0].length);
17330           out += this.renderer.em(this.output(cap[2] || cap[1]));
17331           continue;
17332         }
17333     
17334         // code
17335         if (cap = this.rules.code.exec(src)) {
17336           src = src.substring(cap[0].length);
17337           out += this.renderer.codespan(escape(cap[2], true));
17338           continue;
17339         }
17340     
17341         // br
17342         if (cap = this.rules.br.exec(src)) {
17343           src = src.substring(cap[0].length);
17344           out += this.renderer.br();
17345           continue;
17346         }
17347     
17348         // del (gfm)
17349         if (cap = this.rules.del.exec(src)) {
17350           src = src.substring(cap[0].length);
17351           out += this.renderer.del(this.output(cap[1]));
17352           continue;
17353         }
17354     
17355         // text
17356         if (cap = this.rules.text.exec(src)) {
17357           src = src.substring(cap[0].length);
17358           out += this.renderer.text(escape(this.smartypants(cap[0])));
17359           continue;
17360         }
17361     
17362         if (src) {
17363           throw new
17364             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17365         }
17366       }
17367     
17368       return out;
17369     };
17370     
17371     /**
17372      * Compile Link
17373      */
17374     
17375     InlineLexer.prototype.outputLink = function(cap, link) {
17376       var href = escape(link.href)
17377         , title = link.title ? escape(link.title) : null;
17378     
17379       return cap[0].charAt(0) !== '!'
17380         ? this.renderer.link(href, title, this.output(cap[1]))
17381         : this.renderer.image(href, title, escape(cap[1]));
17382     };
17383     
17384     /**
17385      * Smartypants Transformations
17386      */
17387     
17388     InlineLexer.prototype.smartypants = function(text) {
17389       if (!this.options.smartypants)  { return text; }
17390       return text
17391         // em-dashes
17392         .replace(/---/g, '\u2014')
17393         // en-dashes
17394         .replace(/--/g, '\u2013')
17395         // opening singles
17396         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17397         // closing singles & apostrophes
17398         .replace(/'/g, '\u2019')
17399         // opening doubles
17400         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17401         // closing doubles
17402         .replace(/"/g, '\u201d')
17403         // ellipses
17404         .replace(/\.{3}/g, '\u2026');
17405     };
17406     
17407     /**
17408      * Mangle Links
17409      */
17410     
17411     InlineLexer.prototype.mangle = function(text) {
17412       if (!this.options.mangle) { return text; }
17413       var out = ''
17414         , l = text.length
17415         , i = 0
17416         , ch;
17417     
17418       for (; i < l; i++) {
17419         ch = text.charCodeAt(i);
17420         if (Math.random() > 0.5) {
17421           ch = 'x' + ch.toString(16);
17422         }
17423         out += '&#' + ch + ';';
17424       }
17425     
17426       return out;
17427     };
17428     
17429     /**
17430      * Renderer
17431      */
17432     
17433     function Renderer(options) {
17434       this.options = options || {};
17435     }
17436     
17437     Renderer.prototype.code = function(code, lang, escaped) {
17438       if (this.options.highlight) {
17439         var out = this.options.highlight(code, lang);
17440         if (out != null && out !== code) {
17441           escaped = true;
17442           code = out;
17443         }
17444       } else {
17445             // hack!!! - it's already escapeD?
17446             escaped = true;
17447       }
17448     
17449       if (!lang) {
17450         return '<pre><code>'
17451           + (escaped ? code : escape(code, true))
17452           + '\n</code></pre>';
17453       }
17454     
17455       return '<pre><code class="'
17456         + this.options.langPrefix
17457         + escape(lang, true)
17458         + '">'
17459         + (escaped ? code : escape(code, true))
17460         + '\n</code></pre>\n';
17461     };
17462     
17463     Renderer.prototype.blockquote = function(quote) {
17464       return '<blockquote>\n' + quote + '</blockquote>\n';
17465     };
17466     
17467     Renderer.prototype.html = function(html) {
17468       return html;
17469     };
17470     
17471     Renderer.prototype.heading = function(text, level, raw) {
17472       return '<h'
17473         + level
17474         + ' id="'
17475         + this.options.headerPrefix
17476         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17477         + '">'
17478         + text
17479         + '</h'
17480         + level
17481         + '>\n';
17482     };
17483     
17484     Renderer.prototype.hr = function() {
17485       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17486     };
17487     
17488     Renderer.prototype.list = function(body, ordered) {
17489       var type = ordered ? 'ol' : 'ul';
17490       return '<' + type + '>\n' + body + '</' + type + '>\n';
17491     };
17492     
17493     Renderer.prototype.listitem = function(text) {
17494       return '<li>' + text + '</li>\n';
17495     };
17496     
17497     Renderer.prototype.paragraph = function(text) {
17498       return '<p>' + text + '</p>\n';
17499     };
17500     
17501     Renderer.prototype.table = function(header, body) {
17502       return '<table class="table table-striped">\n'
17503         + '<thead>\n'
17504         + header
17505         + '</thead>\n'
17506         + '<tbody>\n'
17507         + body
17508         + '</tbody>\n'
17509         + '</table>\n';
17510     };
17511     
17512     Renderer.prototype.tablerow = function(content) {
17513       return '<tr>\n' + content + '</tr>\n';
17514     };
17515     
17516     Renderer.prototype.tablecell = function(content, flags) {
17517       var type = flags.header ? 'th' : 'td';
17518       var tag = flags.align
17519         ? '<' + type + ' style="text-align:' + flags.align + '">'
17520         : '<' + type + '>';
17521       return tag + content + '</' + type + '>\n';
17522     };
17523     
17524     // span level renderer
17525     Renderer.prototype.strong = function(text) {
17526       return '<strong>' + text + '</strong>';
17527     };
17528     
17529     Renderer.prototype.em = function(text) {
17530       return '<em>' + text + '</em>';
17531     };
17532     
17533     Renderer.prototype.codespan = function(text) {
17534       return '<code>' + text + '</code>';
17535     };
17536     
17537     Renderer.prototype.br = function() {
17538       return this.options.xhtml ? '<br/>' : '<br>';
17539     };
17540     
17541     Renderer.prototype.del = function(text) {
17542       return '<del>' + text + '</del>';
17543     };
17544     
17545     Renderer.prototype.link = function(href, title, text) {
17546       if (this.options.sanitize) {
17547         try {
17548           var prot = decodeURIComponent(unescape(href))
17549             .replace(/[^\w:]/g, '')
17550             .toLowerCase();
17551         } catch (e) {
17552           return '';
17553         }
17554         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17555           return '';
17556         }
17557       }
17558       var out = '<a href="' + href + '"';
17559       if (title) {
17560         out += ' title="' + title + '"';
17561       }
17562       out += '>' + text + '</a>';
17563       return out;
17564     };
17565     
17566     Renderer.prototype.image = function(href, title, text) {
17567       var out = '<img src="' + href + '" alt="' + text + '"';
17568       if (title) {
17569         out += ' title="' + title + '"';
17570       }
17571       out += this.options.xhtml ? '/>' : '>';
17572       return out;
17573     };
17574     
17575     Renderer.prototype.text = function(text) {
17576       return text;
17577     };
17578     
17579     /**
17580      * Parsing & Compiling
17581      */
17582     
17583     function Parser(options) {
17584       this.tokens = [];
17585       this.token = null;
17586       this.options = options || marked.defaults;
17587       this.options.renderer = this.options.renderer || new Renderer;
17588       this.renderer = this.options.renderer;
17589       this.renderer.options = this.options;
17590     }
17591     
17592     /**
17593      * Static Parse Method
17594      */
17595     
17596     Parser.parse = function(src, options, renderer) {
17597       var parser = new Parser(options, renderer);
17598       return parser.parse(src);
17599     };
17600     
17601     /**
17602      * Parse Loop
17603      */
17604     
17605     Parser.prototype.parse = function(src) {
17606       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17607       this.tokens = src.reverse();
17608     
17609       var out = '';
17610       while (this.next()) {
17611         out += this.tok();
17612       }
17613     
17614       return out;
17615     };
17616     
17617     /**
17618      * Next Token
17619      */
17620     
17621     Parser.prototype.next = function() {
17622       return this.token = this.tokens.pop();
17623     };
17624     
17625     /**
17626      * Preview Next Token
17627      */
17628     
17629     Parser.prototype.peek = function() {
17630       return this.tokens[this.tokens.length - 1] || 0;
17631     };
17632     
17633     /**
17634      * Parse Text Tokens
17635      */
17636     
17637     Parser.prototype.parseText = function() {
17638       var body = this.token.text;
17639     
17640       while (this.peek().type === 'text') {
17641         body += '\n' + this.next().text;
17642       }
17643     
17644       return this.inline.output(body);
17645     };
17646     
17647     /**
17648      * Parse Current Token
17649      */
17650     
17651     Parser.prototype.tok = function() {
17652       switch (this.token.type) {
17653         case 'space': {
17654           return '';
17655         }
17656         case 'hr': {
17657           return this.renderer.hr();
17658         }
17659         case 'heading': {
17660           return this.renderer.heading(
17661             this.inline.output(this.token.text),
17662             this.token.depth,
17663             this.token.text);
17664         }
17665         case 'code': {
17666           return this.renderer.code(this.token.text,
17667             this.token.lang,
17668             this.token.escaped);
17669         }
17670         case 'table': {
17671           var header = ''
17672             , body = ''
17673             , i
17674             , row
17675             , cell
17676             , flags
17677             , j;
17678     
17679           // header
17680           cell = '';
17681           for (i = 0; i < this.token.header.length; i++) {
17682             flags = { header: true, align: this.token.align[i] };
17683             cell += this.renderer.tablecell(
17684               this.inline.output(this.token.header[i]),
17685               { header: true, align: this.token.align[i] }
17686             );
17687           }
17688           header += this.renderer.tablerow(cell);
17689     
17690           for (i = 0; i < this.token.cells.length; i++) {
17691             row = this.token.cells[i];
17692     
17693             cell = '';
17694             for (j = 0; j < row.length; j++) {
17695               cell += this.renderer.tablecell(
17696                 this.inline.output(row[j]),
17697                 { header: false, align: this.token.align[j] }
17698               );
17699             }
17700     
17701             body += this.renderer.tablerow(cell);
17702           }
17703           return this.renderer.table(header, body);
17704         }
17705         case 'blockquote_start': {
17706           var body = '';
17707     
17708           while (this.next().type !== 'blockquote_end') {
17709             body += this.tok();
17710           }
17711     
17712           return this.renderer.blockquote(body);
17713         }
17714         case 'list_start': {
17715           var body = ''
17716             , ordered = this.token.ordered;
17717     
17718           while (this.next().type !== 'list_end') {
17719             body += this.tok();
17720           }
17721     
17722           return this.renderer.list(body, ordered);
17723         }
17724         case 'list_item_start': {
17725           var body = '';
17726     
17727           while (this.next().type !== 'list_item_end') {
17728             body += this.token.type === 'text'
17729               ? this.parseText()
17730               : this.tok();
17731           }
17732     
17733           return this.renderer.listitem(body);
17734         }
17735         case 'loose_item_start': {
17736           var body = '';
17737     
17738           while (this.next().type !== 'list_item_end') {
17739             body += this.tok();
17740           }
17741     
17742           return this.renderer.listitem(body);
17743         }
17744         case 'html': {
17745           var html = !this.token.pre && !this.options.pedantic
17746             ? this.inline.output(this.token.text)
17747             : this.token.text;
17748           return this.renderer.html(html);
17749         }
17750         case 'paragraph': {
17751           return this.renderer.paragraph(this.inline.output(this.token.text));
17752         }
17753         case 'text': {
17754           return this.renderer.paragraph(this.parseText());
17755         }
17756       }
17757     };
17758     
17759     /**
17760      * Helpers
17761      */
17762     
17763     function escape(html, encode) {
17764       return html
17765         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17766         .replace(/</g, '&lt;')
17767         .replace(/>/g, '&gt;')
17768         .replace(/"/g, '&quot;')
17769         .replace(/'/g, '&#39;');
17770     }
17771     
17772     function unescape(html) {
17773         // explicitly match decimal, hex, and named HTML entities 
17774       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17775         n = n.toLowerCase();
17776         if (n === 'colon') { return ':'; }
17777         if (n.charAt(0) === '#') {
17778           return n.charAt(1) === 'x'
17779             ? String.fromCharCode(parseInt(n.substring(2), 16))
17780             : String.fromCharCode(+n.substring(1));
17781         }
17782         return '';
17783       });
17784     }
17785     
17786     function replace(regex, opt) {
17787       regex = regex.source;
17788       opt = opt || '';
17789       return function self(name, val) {
17790         if (!name) { return new RegExp(regex, opt); }
17791         val = val.source || val;
17792         val = val.replace(/(^|[^\[])\^/g, '$1');
17793         regex = regex.replace(name, val);
17794         return self;
17795       };
17796     }
17797     
17798     function noop() {}
17799     noop.exec = noop;
17800     
17801     function merge(obj) {
17802       var i = 1
17803         , target
17804         , key;
17805     
17806       for (; i < arguments.length; i++) {
17807         target = arguments[i];
17808         for (key in target) {
17809           if (Object.prototype.hasOwnProperty.call(target, key)) {
17810             obj[key] = target[key];
17811           }
17812         }
17813       }
17814     
17815       return obj;
17816     }
17817     
17818     
17819     /**
17820      * Marked
17821      */
17822     
17823     function marked(src, opt, callback) {
17824       if (callback || typeof opt === 'function') {
17825         if (!callback) {
17826           callback = opt;
17827           opt = null;
17828         }
17829     
17830         opt = merge({}, marked.defaults, opt || {});
17831     
17832         var highlight = opt.highlight
17833           , tokens
17834           , pending
17835           , i = 0;
17836     
17837         try {
17838           tokens = Lexer.lex(src, opt)
17839         } catch (e) {
17840           return callback(e);
17841         }
17842     
17843         pending = tokens.length;
17844     
17845         var done = function(err) {
17846           if (err) {
17847             opt.highlight = highlight;
17848             return callback(err);
17849           }
17850     
17851           var out;
17852     
17853           try {
17854             out = Parser.parse(tokens, opt);
17855           } catch (e) {
17856             err = e;
17857           }
17858     
17859           opt.highlight = highlight;
17860     
17861           return err
17862             ? callback(err)
17863             : callback(null, out);
17864         };
17865     
17866         if (!highlight || highlight.length < 3) {
17867           return done();
17868         }
17869     
17870         delete opt.highlight;
17871     
17872         if (!pending) { return done(); }
17873     
17874         for (; i < tokens.length; i++) {
17875           (function(token) {
17876             if (token.type !== 'code') {
17877               return --pending || done();
17878             }
17879             return highlight(token.text, token.lang, function(err, code) {
17880               if (err) { return done(err); }
17881               if (code == null || code === token.text) {
17882                 return --pending || done();
17883               }
17884               token.text = code;
17885               token.escaped = true;
17886               --pending || done();
17887             });
17888           })(tokens[i]);
17889         }
17890     
17891         return;
17892       }
17893       try {
17894         if (opt) { opt = merge({}, marked.defaults, opt); }
17895         return Parser.parse(Lexer.lex(src, opt), opt);
17896       } catch (e) {
17897         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17898         if ((opt || marked.defaults).silent) {
17899           return '<p>An error occured:</p><pre>'
17900             + escape(e.message + '', true)
17901             + '</pre>';
17902         }
17903         throw e;
17904       }
17905     }
17906     
17907     /**
17908      * Options
17909      */
17910     
17911     marked.options =
17912     marked.setOptions = function(opt) {
17913       merge(marked.defaults, opt);
17914       return marked;
17915     };
17916     
17917     marked.defaults = {
17918       gfm: true,
17919       tables: true,
17920       breaks: false,
17921       pedantic: false,
17922       sanitize: false,
17923       sanitizer: null,
17924       mangle: true,
17925       smartLists: false,
17926       silent: false,
17927       highlight: null,
17928       langPrefix: 'lang-',
17929       smartypants: false,
17930       headerPrefix: '',
17931       renderer: new Renderer,
17932       xhtml: false
17933     };
17934     
17935     /**
17936      * Expose
17937      */
17938     
17939     marked.Parser = Parser;
17940     marked.parser = Parser.parse;
17941     
17942     marked.Renderer = Renderer;
17943     
17944     marked.Lexer = Lexer;
17945     marked.lexer = Lexer.lex;
17946     
17947     marked.InlineLexer = InlineLexer;
17948     marked.inlineLexer = InlineLexer.output;
17949     
17950     marked.parse = marked;
17951     
17952     Roo.Markdown.marked = marked;
17953
17954 })();/*
17955  * Based on:
17956  * Ext JS Library 1.1.1
17957  * Copyright(c) 2006-2007, Ext JS, LLC.
17958  *
17959  * Originally Released Under LGPL - original licence link has changed is not relivant.
17960  *
17961  * Fork - LGPL
17962  * <script type="text/javascript">
17963  */
17964
17965
17966
17967 /*
17968  * These classes are derivatives of the similarly named classes in the YUI Library.
17969  * The original license:
17970  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17971  * Code licensed under the BSD License:
17972  * http://developer.yahoo.net/yui/license.txt
17973  */
17974
17975 (function() {
17976
17977 var Event=Roo.EventManager;
17978 var Dom=Roo.lib.Dom;
17979
17980 /**
17981  * @class Roo.dd.DragDrop
17982  * @extends Roo.util.Observable
17983  * Defines the interface and base operation of items that that can be
17984  * dragged or can be drop targets.  It was designed to be extended, overriding
17985  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17986  * Up to three html elements can be associated with a DragDrop instance:
17987  * <ul>
17988  * <li>linked element: the element that is passed into the constructor.
17989  * This is the element which defines the boundaries for interaction with
17990  * other DragDrop objects.</li>
17991  * <li>handle element(s): The drag operation only occurs if the element that
17992  * was clicked matches a handle element.  By default this is the linked
17993  * element, but there are times that you will want only a portion of the
17994  * linked element to initiate the drag operation, and the setHandleElId()
17995  * method provides a way to define this.</li>
17996  * <li>drag element: this represents the element that would be moved along
17997  * with the cursor during a drag operation.  By default, this is the linked
17998  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17999  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18000  * </li>
18001  * </ul>
18002  * This class should not be instantiated until the onload event to ensure that
18003  * the associated elements are available.
18004  * The following would define a DragDrop obj that would interact with any
18005  * other DragDrop obj in the "group1" group:
18006  * <pre>
18007  *  dd = new Roo.dd.DragDrop("div1", "group1");
18008  * </pre>
18009  * Since none of the event handlers have been implemented, nothing would
18010  * actually happen if you were to run the code above.  Normally you would
18011  * override this class or one of the default implementations, but you can
18012  * also override the methods you want on an instance of the class...
18013  * <pre>
18014  *  dd.onDragDrop = function(e, id) {
18015  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18016  *  }
18017  * </pre>
18018  * @constructor
18019  * @param {String} id of the element that is linked to this instance
18020  * @param {String} sGroup the group of related DragDrop objects
18021  * @param {object} config an object containing configurable attributes
18022  *                Valid properties for DragDrop:
18023  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18024  */
18025 Roo.dd.DragDrop = function(id, sGroup, config) {
18026     if (id) {
18027         this.init(id, sGroup, config);
18028     }
18029     
18030 };
18031
18032 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18033
18034     /**
18035      * The id of the element associated with this object.  This is what we
18036      * refer to as the "linked element" because the size and position of
18037      * this element is used to determine when the drag and drop objects have
18038      * interacted.
18039      * @property id
18040      * @type String
18041      */
18042     id: null,
18043
18044     /**
18045      * Configuration attributes passed into the constructor
18046      * @property config
18047      * @type object
18048      */
18049     config: null,
18050
18051     /**
18052      * The id of the element that will be dragged.  By default this is same
18053      * as the linked element , but could be changed to another element. Ex:
18054      * Roo.dd.DDProxy
18055      * @property dragElId
18056      * @type String
18057      * @private
18058      */
18059     dragElId: null,
18060
18061     /**
18062      * the id of the element that initiates the drag operation.  By default
18063      * this is the linked element, but could be changed to be a child of this
18064      * element.  This lets us do things like only starting the drag when the
18065      * header element within the linked html element is clicked.
18066      * @property handleElId
18067      * @type String
18068      * @private
18069      */
18070     handleElId: null,
18071
18072     /**
18073      * An associative array of HTML tags that will be ignored if clicked.
18074      * @property invalidHandleTypes
18075      * @type {string: string}
18076      */
18077     invalidHandleTypes: null,
18078
18079     /**
18080      * An associative array of ids for elements that will be ignored if clicked
18081      * @property invalidHandleIds
18082      * @type {string: string}
18083      */
18084     invalidHandleIds: null,
18085
18086     /**
18087      * An indexted array of css class names for elements that will be ignored
18088      * if clicked.
18089      * @property invalidHandleClasses
18090      * @type string[]
18091      */
18092     invalidHandleClasses: null,
18093
18094     /**
18095      * The linked element's absolute X position at the time the drag was
18096      * started
18097      * @property startPageX
18098      * @type int
18099      * @private
18100      */
18101     startPageX: 0,
18102
18103     /**
18104      * The linked element's absolute X position at the time the drag was
18105      * started
18106      * @property startPageY
18107      * @type int
18108      * @private
18109      */
18110     startPageY: 0,
18111
18112     /**
18113      * The group defines a logical collection of DragDrop objects that are
18114      * related.  Instances only get events when interacting with other
18115      * DragDrop object in the same group.  This lets us define multiple
18116      * groups using a single DragDrop subclass if we want.
18117      * @property groups
18118      * @type {string: string}
18119      */
18120     groups: null,
18121
18122     /**
18123      * Individual drag/drop instances can be locked.  This will prevent
18124      * onmousedown start drag.
18125      * @property locked
18126      * @type boolean
18127      * @private
18128      */
18129     locked: false,
18130
18131     /**
18132      * Lock this instance
18133      * @method lock
18134      */
18135     lock: function() { this.locked = true; },
18136
18137     /**
18138      * Unlock this instace
18139      * @method unlock
18140      */
18141     unlock: function() { this.locked = false; },
18142
18143     /**
18144      * By default, all insances can be a drop target.  This can be disabled by
18145      * setting isTarget to false.
18146      * @method isTarget
18147      * @type boolean
18148      */
18149     isTarget: true,
18150
18151     /**
18152      * The padding configured for this drag and drop object for calculating
18153      * the drop zone intersection with this object.
18154      * @method padding
18155      * @type int[]
18156      */
18157     padding: null,
18158
18159     /**
18160      * Cached reference to the linked element
18161      * @property _domRef
18162      * @private
18163      */
18164     _domRef: null,
18165
18166     /**
18167      * Internal typeof flag
18168      * @property __ygDragDrop
18169      * @private
18170      */
18171     __ygDragDrop: true,
18172
18173     /**
18174      * Set to true when horizontal contraints are applied
18175      * @property constrainX
18176      * @type boolean
18177      * @private
18178      */
18179     constrainX: false,
18180
18181     /**
18182      * Set to true when vertical contraints are applied
18183      * @property constrainY
18184      * @type boolean
18185      * @private
18186      */
18187     constrainY: false,
18188
18189     /**
18190      * The left constraint
18191      * @property minX
18192      * @type int
18193      * @private
18194      */
18195     minX: 0,
18196
18197     /**
18198      * The right constraint
18199      * @property maxX
18200      * @type int
18201      * @private
18202      */
18203     maxX: 0,
18204
18205     /**
18206      * The up constraint
18207      * @property minY
18208      * @type int
18209      * @type int
18210      * @private
18211      */
18212     minY: 0,
18213
18214     /**
18215      * The down constraint
18216      * @property maxY
18217      * @type int
18218      * @private
18219      */
18220     maxY: 0,
18221
18222     /**
18223      * Maintain offsets when we resetconstraints.  Set to true when you want
18224      * the position of the element relative to its parent to stay the same
18225      * when the page changes
18226      *
18227      * @property maintainOffset
18228      * @type boolean
18229      */
18230     maintainOffset: false,
18231
18232     /**
18233      * Array of pixel locations the element will snap to if we specified a
18234      * horizontal graduation/interval.  This array is generated automatically
18235      * when you define a tick interval.
18236      * @property xTicks
18237      * @type int[]
18238      */
18239     xTicks: null,
18240
18241     /**
18242      * Array of pixel locations the element will snap to if we specified a
18243      * vertical graduation/interval.  This array is generated automatically
18244      * when you define a tick interval.
18245      * @property yTicks
18246      * @type int[]
18247      */
18248     yTicks: null,
18249
18250     /**
18251      * By default the drag and drop instance will only respond to the primary
18252      * button click (left button for a right-handed mouse).  Set to true to
18253      * allow drag and drop to start with any mouse click that is propogated
18254      * by the browser
18255      * @property primaryButtonOnly
18256      * @type boolean
18257      */
18258     primaryButtonOnly: true,
18259
18260     /**
18261      * The availabe property is false until the linked dom element is accessible.
18262      * @property available
18263      * @type boolean
18264      */
18265     available: false,
18266
18267     /**
18268      * By default, drags can only be initiated if the mousedown occurs in the
18269      * region the linked element is.  This is done in part to work around a
18270      * bug in some browsers that mis-report the mousedown if the previous
18271      * mouseup happened outside of the window.  This property is set to true
18272      * if outer handles are defined.
18273      *
18274      * @property hasOuterHandles
18275      * @type boolean
18276      * @default false
18277      */
18278     hasOuterHandles: false,
18279
18280     /**
18281      * Code that executes immediately before the startDrag event
18282      * @method b4StartDrag
18283      * @private
18284      */
18285     b4StartDrag: function(x, y) { },
18286
18287     /**
18288      * Abstract method called after a drag/drop object is clicked
18289      * and the drag or mousedown time thresholds have beeen met.
18290      * @method startDrag
18291      * @param {int} X click location
18292      * @param {int} Y click location
18293      */
18294     startDrag: function(x, y) { /* override this */ },
18295
18296     /**
18297      * Code that executes immediately before the onDrag event
18298      * @method b4Drag
18299      * @private
18300      */
18301     b4Drag: function(e) { },
18302
18303     /**
18304      * Abstract method called during the onMouseMove event while dragging an
18305      * object.
18306      * @method onDrag
18307      * @param {Event} e the mousemove event
18308      */
18309     onDrag: function(e) { /* override this */ },
18310
18311     /**
18312      * Abstract method called when this element fist begins hovering over
18313      * another DragDrop obj
18314      * @method onDragEnter
18315      * @param {Event} e the mousemove event
18316      * @param {String|DragDrop[]} id In POINT mode, the element
18317      * id this is hovering over.  In INTERSECT mode, an array of one or more
18318      * dragdrop items being hovered over.
18319      */
18320     onDragEnter: function(e, id) { /* override this */ },
18321
18322     /**
18323      * Code that executes immediately before the onDragOver event
18324      * @method b4DragOver
18325      * @private
18326      */
18327     b4DragOver: function(e) { },
18328
18329     /**
18330      * Abstract method called when this element is hovering over another
18331      * DragDrop obj
18332      * @method onDragOver
18333      * @param {Event} e the mousemove event
18334      * @param {String|DragDrop[]} id In POINT mode, the element
18335      * id this is hovering over.  In INTERSECT mode, an array of dd items
18336      * being hovered over.
18337      */
18338     onDragOver: function(e, id) { /* override this */ },
18339
18340     /**
18341      * Code that executes immediately before the onDragOut event
18342      * @method b4DragOut
18343      * @private
18344      */
18345     b4DragOut: function(e) { },
18346
18347     /**
18348      * Abstract method called when we are no longer hovering over an element
18349      * @method onDragOut
18350      * @param {Event} e the mousemove event
18351      * @param {String|DragDrop[]} id In POINT mode, the element
18352      * id this was hovering over.  In INTERSECT mode, an array of dd items
18353      * that the mouse is no longer over.
18354      */
18355     onDragOut: function(e, id) { /* override this */ },
18356
18357     /**
18358      * Code that executes immediately before the onDragDrop event
18359      * @method b4DragDrop
18360      * @private
18361      */
18362     b4DragDrop: function(e) { },
18363
18364     /**
18365      * Abstract method called when this item is dropped on another DragDrop
18366      * obj
18367      * @method onDragDrop
18368      * @param {Event} e the mouseup event
18369      * @param {String|DragDrop[]} id In POINT mode, the element
18370      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18371      * was dropped on.
18372      */
18373     onDragDrop: function(e, id) { /* override this */ },
18374
18375     /**
18376      * Abstract method called when this item is dropped on an area with no
18377      * drop target
18378      * @method onInvalidDrop
18379      * @param {Event} e the mouseup event
18380      */
18381     onInvalidDrop: function(e) { /* override this */ },
18382
18383     /**
18384      * Code that executes immediately before the endDrag event
18385      * @method b4EndDrag
18386      * @private
18387      */
18388     b4EndDrag: function(e) { },
18389
18390     /**
18391      * Fired when we are done dragging the object
18392      * @method endDrag
18393      * @param {Event} e the mouseup event
18394      */
18395     endDrag: function(e) { /* override this */ },
18396
18397     /**
18398      * Code executed immediately before the onMouseDown event
18399      * @method b4MouseDown
18400      * @param {Event} e the mousedown event
18401      * @private
18402      */
18403     b4MouseDown: function(e) {  },
18404
18405     /**
18406      * Event handler that fires when a drag/drop obj gets a mousedown
18407      * @method onMouseDown
18408      * @param {Event} e the mousedown event
18409      */
18410     onMouseDown: function(e) { /* override this */ },
18411
18412     /**
18413      * Event handler that fires when a drag/drop obj gets a mouseup
18414      * @method onMouseUp
18415      * @param {Event} e the mouseup event
18416      */
18417     onMouseUp: function(e) { /* override this */ },
18418
18419     /**
18420      * Override the onAvailable method to do what is needed after the initial
18421      * position was determined.
18422      * @method onAvailable
18423      */
18424     onAvailable: function () {
18425     },
18426
18427     /*
18428      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18429      * @type Object
18430      */
18431     defaultPadding : {left:0, right:0, top:0, bottom:0},
18432
18433     /*
18434      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18435  *
18436  * Usage:
18437  <pre><code>
18438  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18439                 { dragElId: "existingProxyDiv" });
18440  dd.startDrag = function(){
18441      this.constrainTo("parent-id");
18442  };
18443  </code></pre>
18444  * Or you can initalize it using the {@link Roo.Element} object:
18445  <pre><code>
18446  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18447      startDrag : function(){
18448          this.constrainTo("parent-id");
18449      }
18450  });
18451  </code></pre>
18452      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18453      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18454      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18455      * an object containing the sides to pad. For example: {right:10, bottom:10}
18456      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18457      */
18458     constrainTo : function(constrainTo, pad, inContent){
18459         if(typeof pad == "number"){
18460             pad = {left: pad, right:pad, top:pad, bottom:pad};
18461         }
18462         pad = pad || this.defaultPadding;
18463         var b = Roo.get(this.getEl()).getBox();
18464         var ce = Roo.get(constrainTo);
18465         var s = ce.getScroll();
18466         var c, cd = ce.dom;
18467         if(cd == document.body){
18468             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18469         }else{
18470             xy = ce.getXY();
18471             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18472         }
18473
18474
18475         var topSpace = b.y - c.y;
18476         var leftSpace = b.x - c.x;
18477
18478         this.resetConstraints();
18479         this.setXConstraint(leftSpace - (pad.left||0), // left
18480                 c.width - leftSpace - b.width - (pad.right||0) //right
18481         );
18482         this.setYConstraint(topSpace - (pad.top||0), //top
18483                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18484         );
18485     },
18486
18487     /**
18488      * Returns a reference to the linked element
18489      * @method getEl
18490      * @return {HTMLElement} the html element
18491      */
18492     getEl: function() {
18493         if (!this._domRef) {
18494             this._domRef = Roo.getDom(this.id);
18495         }
18496
18497         return this._domRef;
18498     },
18499
18500     /**
18501      * Returns a reference to the actual element to drag.  By default this is
18502      * the same as the html element, but it can be assigned to another
18503      * element. An example of this can be found in Roo.dd.DDProxy
18504      * @method getDragEl
18505      * @return {HTMLElement} the html element
18506      */
18507     getDragEl: function() {
18508         return Roo.getDom(this.dragElId);
18509     },
18510
18511     /**
18512      * Sets up the DragDrop object.  Must be called in the constructor of any
18513      * Roo.dd.DragDrop subclass
18514      * @method init
18515      * @param id the id of the linked element
18516      * @param {String} sGroup the group of related items
18517      * @param {object} config configuration attributes
18518      */
18519     init: function(id, sGroup, config) {
18520         this.initTarget(id, sGroup, config);
18521         if (!Roo.isTouch) {
18522             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18523         }
18524         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18525         // Event.on(this.id, "selectstart", Event.preventDefault);
18526     },
18527
18528     /**
18529      * Initializes Targeting functionality only... the object does not
18530      * get a mousedown handler.
18531      * @method initTarget
18532      * @param id the id of the linked element
18533      * @param {String} sGroup the group of related items
18534      * @param {object} config configuration attributes
18535      */
18536     initTarget: function(id, sGroup, config) {
18537
18538         // configuration attributes
18539         this.config = config || {};
18540
18541         // create a local reference to the drag and drop manager
18542         this.DDM = Roo.dd.DDM;
18543         // initialize the groups array
18544         this.groups = {};
18545
18546         // assume that we have an element reference instead of an id if the
18547         // parameter is not a string
18548         if (typeof id !== "string") {
18549             id = Roo.id(id);
18550         }
18551
18552         // set the id
18553         this.id = id;
18554
18555         // add to an interaction group
18556         this.addToGroup((sGroup) ? sGroup : "default");
18557
18558         // We don't want to register this as the handle with the manager
18559         // so we just set the id rather than calling the setter.
18560         this.handleElId = id;
18561
18562         // the linked element is the element that gets dragged by default
18563         this.setDragElId(id);
18564
18565         // by default, clicked anchors will not start drag operations.
18566         this.invalidHandleTypes = { A: "A" };
18567         this.invalidHandleIds = {};
18568         this.invalidHandleClasses = [];
18569
18570         this.applyConfig();
18571
18572         this.handleOnAvailable();
18573     },
18574
18575     /**
18576      * Applies the configuration parameters that were passed into the constructor.
18577      * This is supposed to happen at each level through the inheritance chain.  So
18578      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18579      * DragDrop in order to get all of the parameters that are available in
18580      * each object.
18581      * @method applyConfig
18582      */
18583     applyConfig: function() {
18584
18585         // configurable properties:
18586         //    padding, isTarget, maintainOffset, primaryButtonOnly
18587         this.padding           = this.config.padding || [0, 0, 0, 0];
18588         this.isTarget          = (this.config.isTarget !== false);
18589         this.maintainOffset    = (this.config.maintainOffset);
18590         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18591
18592     },
18593
18594     /**
18595      * Executed when the linked element is available
18596      * @method handleOnAvailable
18597      * @private
18598      */
18599     handleOnAvailable: function() {
18600         this.available = true;
18601         this.resetConstraints();
18602         this.onAvailable();
18603     },
18604
18605      /**
18606      * Configures the padding for the target zone in px.  Effectively expands
18607      * (or reduces) the virtual object size for targeting calculations.
18608      * Supports css-style shorthand; if only one parameter is passed, all sides
18609      * will have that padding, and if only two are passed, the top and bottom
18610      * will have the first param, the left and right the second.
18611      * @method setPadding
18612      * @param {int} iTop    Top pad
18613      * @param {int} iRight  Right pad
18614      * @param {int} iBot    Bot pad
18615      * @param {int} iLeft   Left pad
18616      */
18617     setPadding: function(iTop, iRight, iBot, iLeft) {
18618         // this.padding = [iLeft, iRight, iTop, iBot];
18619         if (!iRight && 0 !== iRight) {
18620             this.padding = [iTop, iTop, iTop, iTop];
18621         } else if (!iBot && 0 !== iBot) {
18622             this.padding = [iTop, iRight, iTop, iRight];
18623         } else {
18624             this.padding = [iTop, iRight, iBot, iLeft];
18625         }
18626     },
18627
18628     /**
18629      * Stores the initial placement of the linked element.
18630      * @method setInitialPosition
18631      * @param {int} diffX   the X offset, default 0
18632      * @param {int} diffY   the Y offset, default 0
18633      */
18634     setInitPosition: function(diffX, diffY) {
18635         var el = this.getEl();
18636
18637         if (!this.DDM.verifyEl(el)) {
18638             return;
18639         }
18640
18641         var dx = diffX || 0;
18642         var dy = diffY || 0;
18643
18644         var p = Dom.getXY( el );
18645
18646         this.initPageX = p[0] - dx;
18647         this.initPageY = p[1] - dy;
18648
18649         this.lastPageX = p[0];
18650         this.lastPageY = p[1];
18651
18652
18653         this.setStartPosition(p);
18654     },
18655
18656     /**
18657      * Sets the start position of the element.  This is set when the obj
18658      * is initialized, the reset when a drag is started.
18659      * @method setStartPosition
18660      * @param pos current position (from previous lookup)
18661      * @private
18662      */
18663     setStartPosition: function(pos) {
18664         var p = pos || Dom.getXY( this.getEl() );
18665         this.deltaSetXY = null;
18666
18667         this.startPageX = p[0];
18668         this.startPageY = p[1];
18669     },
18670
18671     /**
18672      * Add this instance to a group of related drag/drop objects.  All
18673      * instances belong to at least one group, and can belong to as many
18674      * groups as needed.
18675      * @method addToGroup
18676      * @param sGroup {string} the name of the group
18677      */
18678     addToGroup: function(sGroup) {
18679         this.groups[sGroup] = true;
18680         this.DDM.regDragDrop(this, sGroup);
18681     },
18682
18683     /**
18684      * Remove's this instance from the supplied interaction group
18685      * @method removeFromGroup
18686      * @param {string}  sGroup  The group to drop
18687      */
18688     removeFromGroup: function(sGroup) {
18689         if (this.groups[sGroup]) {
18690             delete this.groups[sGroup];
18691         }
18692
18693         this.DDM.removeDDFromGroup(this, sGroup);
18694     },
18695
18696     /**
18697      * Allows you to specify that an element other than the linked element
18698      * will be moved with the cursor during a drag
18699      * @method setDragElId
18700      * @param id {string} the id of the element that will be used to initiate the drag
18701      */
18702     setDragElId: function(id) {
18703         this.dragElId = id;
18704     },
18705
18706     /**
18707      * Allows you to specify a child of the linked element that should be
18708      * used to initiate the drag operation.  An example of this would be if
18709      * you have a content div with text and links.  Clicking anywhere in the
18710      * content area would normally start the drag operation.  Use this method
18711      * to specify that an element inside of the content div is the element
18712      * that starts the drag operation.
18713      * @method setHandleElId
18714      * @param id {string} the id of the element that will be used to
18715      * initiate the drag.
18716      */
18717     setHandleElId: function(id) {
18718         if (typeof id !== "string") {
18719             id = Roo.id(id);
18720         }
18721         this.handleElId = id;
18722         this.DDM.regHandle(this.id, id);
18723     },
18724
18725     /**
18726      * Allows you to set an element outside of the linked element as a drag
18727      * handle
18728      * @method setOuterHandleElId
18729      * @param id the id of the element that will be used to initiate the drag
18730      */
18731     setOuterHandleElId: function(id) {
18732         if (typeof id !== "string") {
18733             id = Roo.id(id);
18734         }
18735         Event.on(id, "mousedown",
18736                 this.handleMouseDown, this);
18737         this.setHandleElId(id);
18738
18739         this.hasOuterHandles = true;
18740     },
18741
18742     /**
18743      * Remove all drag and drop hooks for this element
18744      * @method unreg
18745      */
18746     unreg: function() {
18747         Event.un(this.id, "mousedown",
18748                 this.handleMouseDown);
18749         Event.un(this.id, "touchstart",
18750                 this.handleMouseDown);
18751         this._domRef = null;
18752         this.DDM._remove(this);
18753     },
18754
18755     destroy : function(){
18756         this.unreg();
18757     },
18758
18759     /**
18760      * Returns true if this instance is locked, or the drag drop mgr is locked
18761      * (meaning that all drag/drop is disabled on the page.)
18762      * @method isLocked
18763      * @return {boolean} true if this obj or all drag/drop is locked, else
18764      * false
18765      */
18766     isLocked: function() {
18767         return (this.DDM.isLocked() || this.locked);
18768     },
18769
18770     /**
18771      * Fired when this object is clicked
18772      * @method handleMouseDown
18773      * @param {Event} e
18774      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18775      * @private
18776      */
18777     handleMouseDown: function(e, oDD){
18778      
18779         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18780             //Roo.log('not touch/ button !=0');
18781             return;
18782         }
18783         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18784             return; // double touch..
18785         }
18786         
18787
18788         if (this.isLocked()) {
18789             //Roo.log('locked');
18790             return;
18791         }
18792
18793         this.DDM.refreshCache(this.groups);
18794 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18795         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18796         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18797             //Roo.log('no outer handes or not over target');
18798                 // do nothing.
18799         } else {
18800 //            Roo.log('check validator');
18801             if (this.clickValidator(e)) {
18802 //                Roo.log('validate success');
18803                 // set the initial element position
18804                 this.setStartPosition();
18805
18806
18807                 this.b4MouseDown(e);
18808                 this.onMouseDown(e);
18809
18810                 this.DDM.handleMouseDown(e, this);
18811
18812                 this.DDM.stopEvent(e);
18813             } else {
18814
18815
18816             }
18817         }
18818     },
18819
18820     clickValidator: function(e) {
18821         var target = e.getTarget();
18822         return ( this.isValidHandleChild(target) &&
18823                     (this.id == this.handleElId ||
18824                         this.DDM.handleWasClicked(target, this.id)) );
18825     },
18826
18827     /**
18828      * Allows you to specify a tag name that should not start a drag operation
18829      * when clicked.  This is designed to facilitate embedding links within a
18830      * drag handle that do something other than start the drag.
18831      * @method addInvalidHandleType
18832      * @param {string} tagName the type of element to exclude
18833      */
18834     addInvalidHandleType: function(tagName) {
18835         var type = tagName.toUpperCase();
18836         this.invalidHandleTypes[type] = type;
18837     },
18838
18839     /**
18840      * Lets you to specify an element id for a child of a drag handle
18841      * that should not initiate a drag
18842      * @method addInvalidHandleId
18843      * @param {string} id the element id of the element you wish to ignore
18844      */
18845     addInvalidHandleId: function(id) {
18846         if (typeof id !== "string") {
18847             id = Roo.id(id);
18848         }
18849         this.invalidHandleIds[id] = id;
18850     },
18851
18852     /**
18853      * Lets you specify a css class of elements that will not initiate a drag
18854      * @method addInvalidHandleClass
18855      * @param {string} cssClass the class of the elements you wish to ignore
18856      */
18857     addInvalidHandleClass: function(cssClass) {
18858         this.invalidHandleClasses.push(cssClass);
18859     },
18860
18861     /**
18862      * Unsets an excluded tag name set by addInvalidHandleType
18863      * @method removeInvalidHandleType
18864      * @param {string} tagName the type of element to unexclude
18865      */
18866     removeInvalidHandleType: function(tagName) {
18867         var type = tagName.toUpperCase();
18868         // this.invalidHandleTypes[type] = null;
18869         delete this.invalidHandleTypes[type];
18870     },
18871
18872     /**
18873      * Unsets an invalid handle id
18874      * @method removeInvalidHandleId
18875      * @param {string} id the id of the element to re-enable
18876      */
18877     removeInvalidHandleId: function(id) {
18878         if (typeof id !== "string") {
18879             id = Roo.id(id);
18880         }
18881         delete this.invalidHandleIds[id];
18882     },
18883
18884     /**
18885      * Unsets an invalid css class
18886      * @method removeInvalidHandleClass
18887      * @param {string} cssClass the class of the element(s) you wish to
18888      * re-enable
18889      */
18890     removeInvalidHandleClass: function(cssClass) {
18891         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18892             if (this.invalidHandleClasses[i] == cssClass) {
18893                 delete this.invalidHandleClasses[i];
18894             }
18895         }
18896     },
18897
18898     /**
18899      * Checks the tag exclusion list to see if this click should be ignored
18900      * @method isValidHandleChild
18901      * @param {HTMLElement} node the HTMLElement to evaluate
18902      * @return {boolean} true if this is a valid tag type, false if not
18903      */
18904     isValidHandleChild: function(node) {
18905
18906         var valid = true;
18907         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18908         var nodeName;
18909         try {
18910             nodeName = node.nodeName.toUpperCase();
18911         } catch(e) {
18912             nodeName = node.nodeName;
18913         }
18914         valid = valid && !this.invalidHandleTypes[nodeName];
18915         valid = valid && !this.invalidHandleIds[node.id];
18916
18917         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18918             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18919         }
18920
18921
18922         return valid;
18923
18924     },
18925
18926     /**
18927      * Create the array of horizontal tick marks if an interval was specified
18928      * in setXConstraint().
18929      * @method setXTicks
18930      * @private
18931      */
18932     setXTicks: function(iStartX, iTickSize) {
18933         this.xTicks = [];
18934         this.xTickSize = iTickSize;
18935
18936         var tickMap = {};
18937
18938         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18939             if (!tickMap[i]) {
18940                 this.xTicks[this.xTicks.length] = i;
18941                 tickMap[i] = true;
18942             }
18943         }
18944
18945         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18946             if (!tickMap[i]) {
18947                 this.xTicks[this.xTicks.length] = i;
18948                 tickMap[i] = true;
18949             }
18950         }
18951
18952         this.xTicks.sort(this.DDM.numericSort) ;
18953     },
18954
18955     /**
18956      * Create the array of vertical tick marks if an interval was specified in
18957      * setYConstraint().
18958      * @method setYTicks
18959      * @private
18960      */
18961     setYTicks: function(iStartY, iTickSize) {
18962         this.yTicks = [];
18963         this.yTickSize = iTickSize;
18964
18965         var tickMap = {};
18966
18967         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18968             if (!tickMap[i]) {
18969                 this.yTicks[this.yTicks.length] = i;
18970                 tickMap[i] = true;
18971             }
18972         }
18973
18974         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18975             if (!tickMap[i]) {
18976                 this.yTicks[this.yTicks.length] = i;
18977                 tickMap[i] = true;
18978             }
18979         }
18980
18981         this.yTicks.sort(this.DDM.numericSort) ;
18982     },
18983
18984     /**
18985      * By default, the element can be dragged any place on the screen.  Use
18986      * this method to limit the horizontal travel of the element.  Pass in
18987      * 0,0 for the parameters if you want to lock the drag to the y axis.
18988      * @method setXConstraint
18989      * @param {int} iLeft the number of pixels the element can move to the left
18990      * @param {int} iRight the number of pixels the element can move to the
18991      * right
18992      * @param {int} iTickSize optional parameter for specifying that the
18993      * element
18994      * should move iTickSize pixels at a time.
18995      */
18996     setXConstraint: function(iLeft, iRight, iTickSize) {
18997         this.leftConstraint = iLeft;
18998         this.rightConstraint = iRight;
18999
19000         this.minX = this.initPageX - iLeft;
19001         this.maxX = this.initPageX + iRight;
19002         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19003
19004         this.constrainX = true;
19005     },
19006
19007     /**
19008      * Clears any constraints applied to this instance.  Also clears ticks
19009      * since they can't exist independent of a constraint at this time.
19010      * @method clearConstraints
19011      */
19012     clearConstraints: function() {
19013         this.constrainX = false;
19014         this.constrainY = false;
19015         this.clearTicks();
19016     },
19017
19018     /**
19019      * Clears any tick interval defined for this instance
19020      * @method clearTicks
19021      */
19022     clearTicks: function() {
19023         this.xTicks = null;
19024         this.yTicks = null;
19025         this.xTickSize = 0;
19026         this.yTickSize = 0;
19027     },
19028
19029     /**
19030      * By default, the element can be dragged any place on the screen.  Set
19031      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19032      * parameters if you want to lock the drag to the x axis.
19033      * @method setYConstraint
19034      * @param {int} iUp the number of pixels the element can move up
19035      * @param {int} iDown the number of pixels the element can move down
19036      * @param {int} iTickSize optional parameter for specifying that the
19037      * element should move iTickSize pixels at a time.
19038      */
19039     setYConstraint: function(iUp, iDown, iTickSize) {
19040         this.topConstraint = iUp;
19041         this.bottomConstraint = iDown;
19042
19043         this.minY = this.initPageY - iUp;
19044         this.maxY = this.initPageY + iDown;
19045         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19046
19047         this.constrainY = true;
19048
19049     },
19050
19051     /**
19052      * resetConstraints must be called if you manually reposition a dd element.
19053      * @method resetConstraints
19054      * @param {boolean} maintainOffset
19055      */
19056     resetConstraints: function() {
19057
19058
19059         // Maintain offsets if necessary
19060         if (this.initPageX || this.initPageX === 0) {
19061             // figure out how much this thing has moved
19062             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19063             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19064
19065             this.setInitPosition(dx, dy);
19066
19067         // This is the first time we have detected the element's position
19068         } else {
19069             this.setInitPosition();
19070         }
19071
19072         if (this.constrainX) {
19073             this.setXConstraint( this.leftConstraint,
19074                                  this.rightConstraint,
19075                                  this.xTickSize        );
19076         }
19077
19078         if (this.constrainY) {
19079             this.setYConstraint( this.topConstraint,
19080                                  this.bottomConstraint,
19081                                  this.yTickSize         );
19082         }
19083     },
19084
19085     /**
19086      * Normally the drag element is moved pixel by pixel, but we can specify
19087      * that it move a number of pixels at a time.  This method resolves the
19088      * location when we have it set up like this.
19089      * @method getTick
19090      * @param {int} val where we want to place the object
19091      * @param {int[]} tickArray sorted array of valid points
19092      * @return {int} the closest tick
19093      * @private
19094      */
19095     getTick: function(val, tickArray) {
19096
19097         if (!tickArray) {
19098             // If tick interval is not defined, it is effectively 1 pixel,
19099             // so we return the value passed to us.
19100             return val;
19101         } else if (tickArray[0] >= val) {
19102             // The value is lower than the first tick, so we return the first
19103             // tick.
19104             return tickArray[0];
19105         } else {
19106             for (var i=0, len=tickArray.length; i<len; ++i) {
19107                 var next = i + 1;
19108                 if (tickArray[next] && tickArray[next] >= val) {
19109                     var diff1 = val - tickArray[i];
19110                     var diff2 = tickArray[next] - val;
19111                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19112                 }
19113             }
19114
19115             // The value is larger than the last tick, so we return the last
19116             // tick.
19117             return tickArray[tickArray.length - 1];
19118         }
19119     },
19120
19121     /**
19122      * toString method
19123      * @method toString
19124      * @return {string} string representation of the dd obj
19125      */
19126     toString: function() {
19127         return ("DragDrop " + this.id);
19128     }
19129
19130 });
19131
19132 })();
19133 /*
19134  * Based on:
19135  * Ext JS Library 1.1.1
19136  * Copyright(c) 2006-2007, Ext JS, LLC.
19137  *
19138  * Originally Released Under LGPL - original licence link has changed is not relivant.
19139  *
19140  * Fork - LGPL
19141  * <script type="text/javascript">
19142  */
19143
19144
19145 /**
19146  * The drag and drop utility provides a framework for building drag and drop
19147  * applications.  In addition to enabling drag and drop for specific elements,
19148  * the drag and drop elements are tracked by the manager class, and the
19149  * interactions between the various elements are tracked during the drag and
19150  * the implementing code is notified about these important moments.
19151  */
19152
19153 // Only load the library once.  Rewriting the manager class would orphan
19154 // existing drag and drop instances.
19155 if (!Roo.dd.DragDropMgr) {
19156
19157 /**
19158  * @class Roo.dd.DragDropMgr
19159  * DragDropMgr is a singleton that tracks the element interaction for
19160  * all DragDrop items in the window.  Generally, you will not call
19161  * this class directly, but it does have helper methods that could
19162  * be useful in your DragDrop implementations.
19163  * @singleton
19164  */
19165 Roo.dd.DragDropMgr = function() {
19166
19167     var Event = Roo.EventManager;
19168
19169     return {
19170
19171         /**
19172          * Two dimensional Array of registered DragDrop objects.  The first
19173          * dimension is the DragDrop item group, the second the DragDrop
19174          * object.
19175          * @property ids
19176          * @type {string: string}
19177          * @private
19178          * @static
19179          */
19180         ids: {},
19181
19182         /**
19183          * Array of element ids defined as drag handles.  Used to determine
19184          * if the element that generated the mousedown event is actually the
19185          * handle and not the html element itself.
19186          * @property handleIds
19187          * @type {string: string}
19188          * @private
19189          * @static
19190          */
19191         handleIds: {},
19192
19193         /**
19194          * the DragDrop object that is currently being dragged
19195          * @property dragCurrent
19196          * @type DragDrop
19197          * @private
19198          * @static
19199          **/
19200         dragCurrent: null,
19201
19202         /**
19203          * the DragDrop object(s) that are being hovered over
19204          * @property dragOvers
19205          * @type Array
19206          * @private
19207          * @static
19208          */
19209         dragOvers: {},
19210
19211         /**
19212          * the X distance between the cursor and the object being dragged
19213          * @property deltaX
19214          * @type int
19215          * @private
19216          * @static
19217          */
19218         deltaX: 0,
19219
19220         /**
19221          * the Y distance between the cursor and the object being dragged
19222          * @property deltaY
19223          * @type int
19224          * @private
19225          * @static
19226          */
19227         deltaY: 0,
19228
19229         /**
19230          * Flag to determine if we should prevent the default behavior of the
19231          * events we define. By default this is true, but this can be set to
19232          * false if you need the default behavior (not recommended)
19233          * @property preventDefault
19234          * @type boolean
19235          * @static
19236          */
19237         preventDefault: true,
19238
19239         /**
19240          * Flag to determine if we should stop the propagation of the events
19241          * we generate. This is true by default but you may want to set it to
19242          * false if the html element contains other features that require the
19243          * mouse click.
19244          * @property stopPropagation
19245          * @type boolean
19246          * @static
19247          */
19248         stopPropagation: true,
19249
19250         /**
19251          * Internal flag that is set to true when drag and drop has been
19252          * intialized
19253          * @property initialized
19254          * @private
19255          * @static
19256          */
19257         initalized: false,
19258
19259         /**
19260          * All drag and drop can be disabled.
19261          * @property locked
19262          * @private
19263          * @static
19264          */
19265         locked: false,
19266
19267         /**
19268          * Called the first time an element is registered.
19269          * @method init
19270          * @private
19271          * @static
19272          */
19273         init: function() {
19274             this.initialized = true;
19275         },
19276
19277         /**
19278          * In point mode, drag and drop interaction is defined by the
19279          * location of the cursor during the drag/drop
19280          * @property POINT
19281          * @type int
19282          * @static
19283          */
19284         POINT: 0,
19285
19286         /**
19287          * In intersect mode, drag and drop interactio nis defined by the
19288          * overlap of two or more drag and drop objects.
19289          * @property INTERSECT
19290          * @type int
19291          * @static
19292          */
19293         INTERSECT: 1,
19294
19295         /**
19296          * The current drag and drop mode.  Default: POINT
19297          * @property mode
19298          * @type int
19299          * @static
19300          */
19301         mode: 0,
19302
19303         /**
19304          * Runs method on all drag and drop objects
19305          * @method _execOnAll
19306          * @private
19307          * @static
19308          */
19309         _execOnAll: function(sMethod, args) {
19310             for (var i in this.ids) {
19311                 for (var j in this.ids[i]) {
19312                     var oDD = this.ids[i][j];
19313                     if (! this.isTypeOfDD(oDD)) {
19314                         continue;
19315                     }
19316                     oDD[sMethod].apply(oDD, args);
19317                 }
19318             }
19319         },
19320
19321         /**
19322          * Drag and drop initialization.  Sets up the global event handlers
19323          * @method _onLoad
19324          * @private
19325          * @static
19326          */
19327         _onLoad: function() {
19328
19329             this.init();
19330
19331             if (!Roo.isTouch) {
19332                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19333                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19334             }
19335             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19336             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19337             
19338             Event.on(window,   "unload",    this._onUnload, this, true);
19339             Event.on(window,   "resize",    this._onResize, this, true);
19340             // Event.on(window,   "mouseout",    this._test);
19341
19342         },
19343
19344         /**
19345          * Reset constraints on all drag and drop objs
19346          * @method _onResize
19347          * @private
19348          * @static
19349          */
19350         _onResize: function(e) {
19351             this._execOnAll("resetConstraints", []);
19352         },
19353
19354         /**
19355          * Lock all drag and drop functionality
19356          * @method lock
19357          * @static
19358          */
19359         lock: function() { this.locked = true; },
19360
19361         /**
19362          * Unlock all drag and drop functionality
19363          * @method unlock
19364          * @static
19365          */
19366         unlock: function() { this.locked = false; },
19367
19368         /**
19369          * Is drag and drop locked?
19370          * @method isLocked
19371          * @return {boolean} True if drag and drop is locked, false otherwise.
19372          * @static
19373          */
19374         isLocked: function() { return this.locked; },
19375
19376         /**
19377          * Location cache that is set for all drag drop objects when a drag is
19378          * initiated, cleared when the drag is finished.
19379          * @property locationCache
19380          * @private
19381          * @static
19382          */
19383         locationCache: {},
19384
19385         /**
19386          * Set useCache to false if you want to force object the lookup of each
19387          * drag and drop linked element constantly during a drag.
19388          * @property useCache
19389          * @type boolean
19390          * @static
19391          */
19392         useCache: true,
19393
19394         /**
19395          * The number of pixels that the mouse needs to move after the
19396          * mousedown before the drag is initiated.  Default=3;
19397          * @property clickPixelThresh
19398          * @type int
19399          * @static
19400          */
19401         clickPixelThresh: 3,
19402
19403         /**
19404          * The number of milliseconds after the mousedown event to initiate the
19405          * drag if we don't get a mouseup event. Default=1000
19406          * @property clickTimeThresh
19407          * @type int
19408          * @static
19409          */
19410         clickTimeThresh: 350,
19411
19412         /**
19413          * Flag that indicates that either the drag pixel threshold or the
19414          * mousdown time threshold has been met
19415          * @property dragThreshMet
19416          * @type boolean
19417          * @private
19418          * @static
19419          */
19420         dragThreshMet: false,
19421
19422         /**
19423          * Timeout used for the click time threshold
19424          * @property clickTimeout
19425          * @type Object
19426          * @private
19427          * @static
19428          */
19429         clickTimeout: null,
19430
19431         /**
19432          * The X position of the mousedown event stored for later use when a
19433          * drag threshold is met.
19434          * @property startX
19435          * @type int
19436          * @private
19437          * @static
19438          */
19439         startX: 0,
19440
19441         /**
19442          * The Y position of the mousedown event stored for later use when a
19443          * drag threshold is met.
19444          * @property startY
19445          * @type int
19446          * @private
19447          * @static
19448          */
19449         startY: 0,
19450
19451         /**
19452          * Each DragDrop instance must be registered with the DragDropMgr.
19453          * This is executed in DragDrop.init()
19454          * @method regDragDrop
19455          * @param {DragDrop} oDD the DragDrop object to register
19456          * @param {String} sGroup the name of the group this element belongs to
19457          * @static
19458          */
19459         regDragDrop: function(oDD, sGroup) {
19460             if (!this.initialized) { this.init(); }
19461
19462             if (!this.ids[sGroup]) {
19463                 this.ids[sGroup] = {};
19464             }
19465             this.ids[sGroup][oDD.id] = oDD;
19466         },
19467
19468         /**
19469          * Removes the supplied dd instance from the supplied group. Executed
19470          * by DragDrop.removeFromGroup, so don't call this function directly.
19471          * @method removeDDFromGroup
19472          * @private
19473          * @static
19474          */
19475         removeDDFromGroup: function(oDD, sGroup) {
19476             if (!this.ids[sGroup]) {
19477                 this.ids[sGroup] = {};
19478             }
19479
19480             var obj = this.ids[sGroup];
19481             if (obj && obj[oDD.id]) {
19482                 delete obj[oDD.id];
19483             }
19484         },
19485
19486         /**
19487          * Unregisters a drag and drop item.  This is executed in
19488          * DragDrop.unreg, use that method instead of calling this directly.
19489          * @method _remove
19490          * @private
19491          * @static
19492          */
19493         _remove: function(oDD) {
19494             for (var g in oDD.groups) {
19495                 if (g && this.ids[g][oDD.id]) {
19496                     delete this.ids[g][oDD.id];
19497                 }
19498             }
19499             delete this.handleIds[oDD.id];
19500         },
19501
19502         /**
19503          * Each DragDrop handle element must be registered.  This is done
19504          * automatically when executing DragDrop.setHandleElId()
19505          * @method regHandle
19506          * @param {String} sDDId the DragDrop id this element is a handle for
19507          * @param {String} sHandleId the id of the element that is the drag
19508          * handle
19509          * @static
19510          */
19511         regHandle: function(sDDId, sHandleId) {
19512             if (!this.handleIds[sDDId]) {
19513                 this.handleIds[sDDId] = {};
19514             }
19515             this.handleIds[sDDId][sHandleId] = sHandleId;
19516         },
19517
19518         /**
19519          * Utility function to determine if a given element has been
19520          * registered as a drag drop item.
19521          * @method isDragDrop
19522          * @param {String} id the element id to check
19523          * @return {boolean} true if this element is a DragDrop item,
19524          * false otherwise
19525          * @static
19526          */
19527         isDragDrop: function(id) {
19528             return ( this.getDDById(id) ) ? true : false;
19529         },
19530
19531         /**
19532          * Returns the drag and drop instances that are in all groups the
19533          * passed in instance belongs to.
19534          * @method getRelated
19535          * @param {DragDrop} p_oDD the obj to get related data for
19536          * @param {boolean} bTargetsOnly if true, only return targetable objs
19537          * @return {DragDrop[]} the related instances
19538          * @static
19539          */
19540         getRelated: function(p_oDD, bTargetsOnly) {
19541             var oDDs = [];
19542             for (var i in p_oDD.groups) {
19543                 for (j in this.ids[i]) {
19544                     var dd = this.ids[i][j];
19545                     if (! this.isTypeOfDD(dd)) {
19546                         continue;
19547                     }
19548                     if (!bTargetsOnly || dd.isTarget) {
19549                         oDDs[oDDs.length] = dd;
19550                     }
19551                 }
19552             }
19553
19554             return oDDs;
19555         },
19556
19557         /**
19558          * Returns true if the specified dd target is a legal target for
19559          * the specifice drag obj
19560          * @method isLegalTarget
19561          * @param {DragDrop} the drag obj
19562          * @param {DragDrop} the target
19563          * @return {boolean} true if the target is a legal target for the
19564          * dd obj
19565          * @static
19566          */
19567         isLegalTarget: function (oDD, oTargetDD) {
19568             var targets = this.getRelated(oDD, true);
19569             for (var i=0, len=targets.length;i<len;++i) {
19570                 if (targets[i].id == oTargetDD.id) {
19571                     return true;
19572                 }
19573             }
19574
19575             return false;
19576         },
19577
19578         /**
19579          * My goal is to be able to transparently determine if an object is
19580          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19581          * returns "object", oDD.constructor.toString() always returns
19582          * "DragDrop" and not the name of the subclass.  So for now it just
19583          * evaluates a well-known variable in DragDrop.
19584          * @method isTypeOfDD
19585          * @param {Object} the object to evaluate
19586          * @return {boolean} true if typeof oDD = DragDrop
19587          * @static
19588          */
19589         isTypeOfDD: function (oDD) {
19590             return (oDD && oDD.__ygDragDrop);
19591         },
19592
19593         /**
19594          * Utility function to determine if a given element has been
19595          * registered as a drag drop handle for the given Drag Drop object.
19596          * @method isHandle
19597          * @param {String} id the element id to check
19598          * @return {boolean} true if this element is a DragDrop handle, false
19599          * otherwise
19600          * @static
19601          */
19602         isHandle: function(sDDId, sHandleId) {
19603             return ( this.handleIds[sDDId] &&
19604                             this.handleIds[sDDId][sHandleId] );
19605         },
19606
19607         /**
19608          * Returns the DragDrop instance for a given id
19609          * @method getDDById
19610          * @param {String} id the id of the DragDrop object
19611          * @return {DragDrop} the drag drop object, null if it is not found
19612          * @static
19613          */
19614         getDDById: function(id) {
19615             for (var i in this.ids) {
19616                 if (this.ids[i][id]) {
19617                     return this.ids[i][id];
19618                 }
19619             }
19620             return null;
19621         },
19622
19623         /**
19624          * Fired after a registered DragDrop object gets the mousedown event.
19625          * Sets up the events required to track the object being dragged
19626          * @method handleMouseDown
19627          * @param {Event} e the event
19628          * @param oDD the DragDrop object being dragged
19629          * @private
19630          * @static
19631          */
19632         handleMouseDown: function(e, oDD) {
19633             if(Roo.QuickTips){
19634                 Roo.QuickTips.disable();
19635             }
19636             this.currentTarget = e.getTarget();
19637
19638             this.dragCurrent = oDD;
19639
19640             var el = oDD.getEl();
19641
19642             // track start position
19643             this.startX = e.getPageX();
19644             this.startY = e.getPageY();
19645
19646             this.deltaX = this.startX - el.offsetLeft;
19647             this.deltaY = this.startY - el.offsetTop;
19648
19649             this.dragThreshMet = false;
19650
19651             this.clickTimeout = setTimeout(
19652                     function() {
19653                         var DDM = Roo.dd.DDM;
19654                         DDM.startDrag(DDM.startX, DDM.startY);
19655                     },
19656                     this.clickTimeThresh );
19657         },
19658
19659         /**
19660          * Fired when either the drag pixel threshol or the mousedown hold
19661          * time threshold has been met.
19662          * @method startDrag
19663          * @param x {int} the X position of the original mousedown
19664          * @param y {int} the Y position of the original mousedown
19665          * @static
19666          */
19667         startDrag: function(x, y) {
19668             clearTimeout(this.clickTimeout);
19669             if (this.dragCurrent) {
19670                 this.dragCurrent.b4StartDrag(x, y);
19671                 this.dragCurrent.startDrag(x, y);
19672             }
19673             this.dragThreshMet = true;
19674         },
19675
19676         /**
19677          * Internal function to handle the mouseup event.  Will be invoked
19678          * from the context of the document.
19679          * @method handleMouseUp
19680          * @param {Event} e the event
19681          * @private
19682          * @static
19683          */
19684         handleMouseUp: function(e) {
19685
19686             if(Roo.QuickTips){
19687                 Roo.QuickTips.enable();
19688             }
19689             if (! this.dragCurrent) {
19690                 return;
19691             }
19692
19693             clearTimeout(this.clickTimeout);
19694
19695             if (this.dragThreshMet) {
19696                 this.fireEvents(e, true);
19697             } else {
19698             }
19699
19700             this.stopDrag(e);
19701
19702             this.stopEvent(e);
19703         },
19704
19705         /**
19706          * Utility to stop event propagation and event default, if these
19707          * features are turned on.
19708          * @method stopEvent
19709          * @param {Event} e the event as returned by this.getEvent()
19710          * @static
19711          */
19712         stopEvent: function(e){
19713             if(this.stopPropagation) {
19714                 e.stopPropagation();
19715             }
19716
19717             if (this.preventDefault) {
19718                 e.preventDefault();
19719             }
19720         },
19721
19722         /**
19723          * Internal function to clean up event handlers after the drag
19724          * operation is complete
19725          * @method stopDrag
19726          * @param {Event} e the event
19727          * @private
19728          * @static
19729          */
19730         stopDrag: function(e) {
19731             // Fire the drag end event for the item that was dragged
19732             if (this.dragCurrent) {
19733                 if (this.dragThreshMet) {
19734                     this.dragCurrent.b4EndDrag(e);
19735                     this.dragCurrent.endDrag(e);
19736                 }
19737
19738                 this.dragCurrent.onMouseUp(e);
19739             }
19740
19741             this.dragCurrent = null;
19742             this.dragOvers = {};
19743         },
19744
19745         /**
19746          * Internal function to handle the mousemove event.  Will be invoked
19747          * from the context of the html element.
19748          *
19749          * @TODO figure out what we can do about mouse events lost when the
19750          * user drags objects beyond the window boundary.  Currently we can
19751          * detect this in internet explorer by verifying that the mouse is
19752          * down during the mousemove event.  Firefox doesn't give us the
19753          * button state on the mousemove event.
19754          * @method handleMouseMove
19755          * @param {Event} e the event
19756          * @private
19757          * @static
19758          */
19759         handleMouseMove: function(e) {
19760             if (! this.dragCurrent) {
19761                 return true;
19762             }
19763
19764             // var button = e.which || e.button;
19765
19766             // check for IE mouseup outside of page boundary
19767             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19768                 this.stopEvent(e);
19769                 return this.handleMouseUp(e);
19770             }
19771
19772             if (!this.dragThreshMet) {
19773                 var diffX = Math.abs(this.startX - e.getPageX());
19774                 var diffY = Math.abs(this.startY - e.getPageY());
19775                 if (diffX > this.clickPixelThresh ||
19776                             diffY > this.clickPixelThresh) {
19777                     this.startDrag(this.startX, this.startY);
19778                 }
19779             }
19780
19781             if (this.dragThreshMet) {
19782                 this.dragCurrent.b4Drag(e);
19783                 this.dragCurrent.onDrag(e);
19784                 if(!this.dragCurrent.moveOnly){
19785                     this.fireEvents(e, false);
19786                 }
19787             }
19788
19789             this.stopEvent(e);
19790
19791             return true;
19792         },
19793
19794         /**
19795          * Iterates over all of the DragDrop elements to find ones we are
19796          * hovering over or dropping on
19797          * @method fireEvents
19798          * @param {Event} e the event
19799          * @param {boolean} isDrop is this a drop op or a mouseover op?
19800          * @private
19801          * @static
19802          */
19803         fireEvents: function(e, isDrop) {
19804             var dc = this.dragCurrent;
19805
19806             // If the user did the mouse up outside of the window, we could
19807             // get here even though we have ended the drag.
19808             if (!dc || dc.isLocked()) {
19809                 return;
19810             }
19811
19812             var pt = e.getPoint();
19813
19814             // cache the previous dragOver array
19815             var oldOvers = [];
19816
19817             var outEvts   = [];
19818             var overEvts  = [];
19819             var dropEvts  = [];
19820             var enterEvts = [];
19821
19822             // Check to see if the object(s) we were hovering over is no longer
19823             // being hovered over so we can fire the onDragOut event
19824             for (var i in this.dragOvers) {
19825
19826                 var ddo = this.dragOvers[i];
19827
19828                 if (! this.isTypeOfDD(ddo)) {
19829                     continue;
19830                 }
19831
19832                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19833                     outEvts.push( ddo );
19834                 }
19835
19836                 oldOvers[i] = true;
19837                 delete this.dragOvers[i];
19838             }
19839
19840             for (var sGroup in dc.groups) {
19841
19842                 if ("string" != typeof sGroup) {
19843                     continue;
19844                 }
19845
19846                 for (i in this.ids[sGroup]) {
19847                     var oDD = this.ids[sGroup][i];
19848                     if (! this.isTypeOfDD(oDD)) {
19849                         continue;
19850                     }
19851
19852                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19853                         if (this.isOverTarget(pt, oDD, this.mode)) {
19854                             // look for drop interactions
19855                             if (isDrop) {
19856                                 dropEvts.push( oDD );
19857                             // look for drag enter and drag over interactions
19858                             } else {
19859
19860                                 // initial drag over: dragEnter fires
19861                                 if (!oldOvers[oDD.id]) {
19862                                     enterEvts.push( oDD );
19863                                 // subsequent drag overs: dragOver fires
19864                                 } else {
19865                                     overEvts.push( oDD );
19866                                 }
19867
19868                                 this.dragOvers[oDD.id] = oDD;
19869                             }
19870                         }
19871                     }
19872                 }
19873             }
19874
19875             if (this.mode) {
19876                 if (outEvts.length) {
19877                     dc.b4DragOut(e, outEvts);
19878                     dc.onDragOut(e, outEvts);
19879                 }
19880
19881                 if (enterEvts.length) {
19882                     dc.onDragEnter(e, enterEvts);
19883                 }
19884
19885                 if (overEvts.length) {
19886                     dc.b4DragOver(e, overEvts);
19887                     dc.onDragOver(e, overEvts);
19888                 }
19889
19890                 if (dropEvts.length) {
19891                     dc.b4DragDrop(e, dropEvts);
19892                     dc.onDragDrop(e, dropEvts);
19893                 }
19894
19895             } else {
19896                 // fire dragout events
19897                 var len = 0;
19898                 for (i=0, len=outEvts.length; i<len; ++i) {
19899                     dc.b4DragOut(e, outEvts[i].id);
19900                     dc.onDragOut(e, outEvts[i].id);
19901                 }
19902
19903                 // fire enter events
19904                 for (i=0,len=enterEvts.length; i<len; ++i) {
19905                     // dc.b4DragEnter(e, oDD.id);
19906                     dc.onDragEnter(e, enterEvts[i].id);
19907                 }
19908
19909                 // fire over events
19910                 for (i=0,len=overEvts.length; i<len; ++i) {
19911                     dc.b4DragOver(e, overEvts[i].id);
19912                     dc.onDragOver(e, overEvts[i].id);
19913                 }
19914
19915                 // fire drop events
19916                 for (i=0, len=dropEvts.length; i<len; ++i) {
19917                     dc.b4DragDrop(e, dropEvts[i].id);
19918                     dc.onDragDrop(e, dropEvts[i].id);
19919                 }
19920
19921             }
19922
19923             // notify about a drop that did not find a target
19924             if (isDrop && !dropEvts.length) {
19925                 dc.onInvalidDrop(e);
19926             }
19927
19928         },
19929
19930         /**
19931          * Helper function for getting the best match from the list of drag
19932          * and drop objects returned by the drag and drop events when we are
19933          * in INTERSECT mode.  It returns either the first object that the
19934          * cursor is over, or the object that has the greatest overlap with
19935          * the dragged element.
19936          * @method getBestMatch
19937          * @param  {DragDrop[]} dds The array of drag and drop objects
19938          * targeted
19939          * @return {DragDrop}       The best single match
19940          * @static
19941          */
19942         getBestMatch: function(dds) {
19943             var winner = null;
19944             // Return null if the input is not what we expect
19945             //if (!dds || !dds.length || dds.length == 0) {
19946                // winner = null;
19947             // If there is only one item, it wins
19948             //} else if (dds.length == 1) {
19949
19950             var len = dds.length;
19951
19952             if (len == 1) {
19953                 winner = dds[0];
19954             } else {
19955                 // Loop through the targeted items
19956                 for (var i=0; i<len; ++i) {
19957                     var dd = dds[i];
19958                     // If the cursor is over the object, it wins.  If the
19959                     // cursor is over multiple matches, the first one we come
19960                     // to wins.
19961                     if (dd.cursorIsOver) {
19962                         winner = dd;
19963                         break;
19964                     // Otherwise the object with the most overlap wins
19965                     } else {
19966                         if (!winner ||
19967                             winner.overlap.getArea() < dd.overlap.getArea()) {
19968                             winner = dd;
19969                         }
19970                     }
19971                 }
19972             }
19973
19974             return winner;
19975         },
19976
19977         /**
19978          * Refreshes the cache of the top-left and bottom-right points of the
19979          * drag and drop objects in the specified group(s).  This is in the
19980          * format that is stored in the drag and drop instance, so typical
19981          * usage is:
19982          * <code>
19983          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19984          * </code>
19985          * Alternatively:
19986          * <code>
19987          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19988          * </code>
19989          * @TODO this really should be an indexed array.  Alternatively this
19990          * method could accept both.
19991          * @method refreshCache
19992          * @param {Object} groups an associative array of groups to refresh
19993          * @static
19994          */
19995         refreshCache: function(groups) {
19996             for (var sGroup in groups) {
19997                 if ("string" != typeof sGroup) {
19998                     continue;
19999                 }
20000                 for (var i in this.ids[sGroup]) {
20001                     var oDD = this.ids[sGroup][i];
20002
20003                     if (this.isTypeOfDD(oDD)) {
20004                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20005                         var loc = this.getLocation(oDD);
20006                         if (loc) {
20007                             this.locationCache[oDD.id] = loc;
20008                         } else {
20009                             delete this.locationCache[oDD.id];
20010                             // this will unregister the drag and drop object if
20011                             // the element is not in a usable state
20012                             // oDD.unreg();
20013                         }
20014                     }
20015                 }
20016             }
20017         },
20018
20019         /**
20020          * This checks to make sure an element exists and is in the DOM.  The
20021          * main purpose is to handle cases where innerHTML is used to remove
20022          * drag and drop objects from the DOM.  IE provides an 'unspecified
20023          * error' when trying to access the offsetParent of such an element
20024          * @method verifyEl
20025          * @param {HTMLElement} el the element to check
20026          * @return {boolean} true if the element looks usable
20027          * @static
20028          */
20029         verifyEl: function(el) {
20030             if (el) {
20031                 var parent;
20032                 if(Roo.isIE){
20033                     try{
20034                         parent = el.offsetParent;
20035                     }catch(e){}
20036                 }else{
20037                     parent = el.offsetParent;
20038                 }
20039                 if (parent) {
20040                     return true;
20041                 }
20042             }
20043
20044             return false;
20045         },
20046
20047         /**
20048          * Returns a Region object containing the drag and drop element's position
20049          * and size, including the padding configured for it
20050          * @method getLocation
20051          * @param {DragDrop} oDD the drag and drop object to get the
20052          *                       location for
20053          * @return {Roo.lib.Region} a Region object representing the total area
20054          *                             the element occupies, including any padding
20055          *                             the instance is configured for.
20056          * @static
20057          */
20058         getLocation: function(oDD) {
20059             if (! this.isTypeOfDD(oDD)) {
20060                 return null;
20061             }
20062
20063             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20064
20065             try {
20066                 pos= Roo.lib.Dom.getXY(el);
20067             } catch (e) { }
20068
20069             if (!pos) {
20070                 return null;
20071             }
20072
20073             x1 = pos[0];
20074             x2 = x1 + el.offsetWidth;
20075             y1 = pos[1];
20076             y2 = y1 + el.offsetHeight;
20077
20078             t = y1 - oDD.padding[0];
20079             r = x2 + oDD.padding[1];
20080             b = y2 + oDD.padding[2];
20081             l = x1 - oDD.padding[3];
20082
20083             return new Roo.lib.Region( t, r, b, l );
20084         },
20085
20086         /**
20087          * Checks the cursor location to see if it over the target
20088          * @method isOverTarget
20089          * @param {Roo.lib.Point} pt The point to evaluate
20090          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20091          * @return {boolean} true if the mouse is over the target
20092          * @private
20093          * @static
20094          */
20095         isOverTarget: function(pt, oTarget, intersect) {
20096             // use cache if available
20097             var loc = this.locationCache[oTarget.id];
20098             if (!loc || !this.useCache) {
20099                 loc = this.getLocation(oTarget);
20100                 this.locationCache[oTarget.id] = loc;
20101
20102             }
20103
20104             if (!loc) {
20105                 return false;
20106             }
20107
20108             oTarget.cursorIsOver = loc.contains( pt );
20109
20110             // DragDrop is using this as a sanity check for the initial mousedown
20111             // in this case we are done.  In POINT mode, if the drag obj has no
20112             // contraints, we are also done. Otherwise we need to evaluate the
20113             // location of the target as related to the actual location of the
20114             // dragged element.
20115             var dc = this.dragCurrent;
20116             if (!dc || !dc.getTargetCoord ||
20117                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20118                 return oTarget.cursorIsOver;
20119             }
20120
20121             oTarget.overlap = null;
20122
20123             // Get the current location of the drag element, this is the
20124             // location of the mouse event less the delta that represents
20125             // where the original mousedown happened on the element.  We
20126             // need to consider constraints and ticks as well.
20127             var pos = dc.getTargetCoord(pt.x, pt.y);
20128
20129             var el = dc.getDragEl();
20130             var curRegion = new Roo.lib.Region( pos.y,
20131                                                    pos.x + el.offsetWidth,
20132                                                    pos.y + el.offsetHeight,
20133                                                    pos.x );
20134
20135             var overlap = curRegion.intersect(loc);
20136
20137             if (overlap) {
20138                 oTarget.overlap = overlap;
20139                 return (intersect) ? true : oTarget.cursorIsOver;
20140             } else {
20141                 return false;
20142             }
20143         },
20144
20145         /**
20146          * unload event handler
20147          * @method _onUnload
20148          * @private
20149          * @static
20150          */
20151         _onUnload: function(e, me) {
20152             Roo.dd.DragDropMgr.unregAll();
20153         },
20154
20155         /**
20156          * Cleans up the drag and drop events and objects.
20157          * @method unregAll
20158          * @private
20159          * @static
20160          */
20161         unregAll: function() {
20162
20163             if (this.dragCurrent) {
20164                 this.stopDrag();
20165                 this.dragCurrent = null;
20166             }
20167
20168             this._execOnAll("unreg", []);
20169
20170             for (i in this.elementCache) {
20171                 delete this.elementCache[i];
20172             }
20173
20174             this.elementCache = {};
20175             this.ids = {};
20176         },
20177
20178         /**
20179          * A cache of DOM elements
20180          * @property elementCache
20181          * @private
20182          * @static
20183          */
20184         elementCache: {},
20185
20186         /**
20187          * Get the wrapper for the DOM element specified
20188          * @method getElWrapper
20189          * @param {String} id the id of the element to get
20190          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20191          * @private
20192          * @deprecated This wrapper isn't that useful
20193          * @static
20194          */
20195         getElWrapper: function(id) {
20196             var oWrapper = this.elementCache[id];
20197             if (!oWrapper || !oWrapper.el) {
20198                 oWrapper = this.elementCache[id] =
20199                     new this.ElementWrapper(Roo.getDom(id));
20200             }
20201             return oWrapper;
20202         },
20203
20204         /**
20205          * Returns the actual DOM element
20206          * @method getElement
20207          * @param {String} id the id of the elment to get
20208          * @return {Object} The element
20209          * @deprecated use Roo.getDom instead
20210          * @static
20211          */
20212         getElement: function(id) {
20213             return Roo.getDom(id);
20214         },
20215
20216         /**
20217          * Returns the style property for the DOM element (i.e.,
20218          * document.getElById(id).style)
20219          * @method getCss
20220          * @param {String} id the id of the elment to get
20221          * @return {Object} The style property of the element
20222          * @deprecated use Roo.getDom instead
20223          * @static
20224          */
20225         getCss: function(id) {
20226             var el = Roo.getDom(id);
20227             return (el) ? el.style : null;
20228         },
20229
20230         /**
20231          * Inner class for cached elements
20232          * @class DragDropMgr.ElementWrapper
20233          * @for DragDropMgr
20234          * @private
20235          * @deprecated
20236          */
20237         ElementWrapper: function(el) {
20238                 /**
20239                  * The element
20240                  * @property el
20241                  */
20242                 this.el = el || null;
20243                 /**
20244                  * The element id
20245                  * @property id
20246                  */
20247                 this.id = this.el && el.id;
20248                 /**
20249                  * A reference to the style property
20250                  * @property css
20251                  */
20252                 this.css = this.el && el.style;
20253             },
20254
20255         /**
20256          * Returns the X position of an html element
20257          * @method getPosX
20258          * @param el the element for which to get the position
20259          * @return {int} the X coordinate
20260          * @for DragDropMgr
20261          * @deprecated use Roo.lib.Dom.getX instead
20262          * @static
20263          */
20264         getPosX: function(el) {
20265             return Roo.lib.Dom.getX(el);
20266         },
20267
20268         /**
20269          * Returns the Y position of an html element
20270          * @method getPosY
20271          * @param el the element for which to get the position
20272          * @return {int} the Y coordinate
20273          * @deprecated use Roo.lib.Dom.getY instead
20274          * @static
20275          */
20276         getPosY: function(el) {
20277             return Roo.lib.Dom.getY(el);
20278         },
20279
20280         /**
20281          * Swap two nodes.  In IE, we use the native method, for others we
20282          * emulate the IE behavior
20283          * @method swapNode
20284          * @param n1 the first node to swap
20285          * @param n2 the other node to swap
20286          * @static
20287          */
20288         swapNode: function(n1, n2) {
20289             if (n1.swapNode) {
20290                 n1.swapNode(n2);
20291             } else {
20292                 var p = n2.parentNode;
20293                 var s = n2.nextSibling;
20294
20295                 if (s == n1) {
20296                     p.insertBefore(n1, n2);
20297                 } else if (n2 == n1.nextSibling) {
20298                     p.insertBefore(n2, n1);
20299                 } else {
20300                     n1.parentNode.replaceChild(n2, n1);
20301                     p.insertBefore(n1, s);
20302                 }
20303             }
20304         },
20305
20306         /**
20307          * Returns the current scroll position
20308          * @method getScroll
20309          * @private
20310          * @static
20311          */
20312         getScroll: function () {
20313             var t, l, dde=document.documentElement, db=document.body;
20314             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20315                 t = dde.scrollTop;
20316                 l = dde.scrollLeft;
20317             } else if (db) {
20318                 t = db.scrollTop;
20319                 l = db.scrollLeft;
20320             } else {
20321
20322             }
20323             return { top: t, left: l };
20324         },
20325
20326         /**
20327          * Returns the specified element style property
20328          * @method getStyle
20329          * @param {HTMLElement} el          the element
20330          * @param {string}      styleProp   the style property
20331          * @return {string} The value of the style property
20332          * @deprecated use Roo.lib.Dom.getStyle
20333          * @static
20334          */
20335         getStyle: function(el, styleProp) {
20336             return Roo.fly(el).getStyle(styleProp);
20337         },
20338
20339         /**
20340          * Gets the scrollTop
20341          * @method getScrollTop
20342          * @return {int} the document's scrollTop
20343          * @static
20344          */
20345         getScrollTop: function () { return this.getScroll().top; },
20346
20347         /**
20348          * Gets the scrollLeft
20349          * @method getScrollLeft
20350          * @return {int} the document's scrollTop
20351          * @static
20352          */
20353         getScrollLeft: function () { return this.getScroll().left; },
20354
20355         /**
20356          * Sets the x/y position of an element to the location of the
20357          * target element.
20358          * @method moveToEl
20359          * @param {HTMLElement} moveEl      The element to move
20360          * @param {HTMLElement} targetEl    The position reference element
20361          * @static
20362          */
20363         moveToEl: function (moveEl, targetEl) {
20364             var aCoord = Roo.lib.Dom.getXY(targetEl);
20365             Roo.lib.Dom.setXY(moveEl, aCoord);
20366         },
20367
20368         /**
20369          * Numeric array sort function
20370          * @method numericSort
20371          * @static
20372          */
20373         numericSort: function(a, b) { return (a - b); },
20374
20375         /**
20376          * Internal counter
20377          * @property _timeoutCount
20378          * @private
20379          * @static
20380          */
20381         _timeoutCount: 0,
20382
20383         /**
20384          * Trying to make the load order less important.  Without this we get
20385          * an error if this file is loaded before the Event Utility.
20386          * @method _addListeners
20387          * @private
20388          * @static
20389          */
20390         _addListeners: function() {
20391             var DDM = Roo.dd.DDM;
20392             if ( Roo.lib.Event && document ) {
20393                 DDM._onLoad();
20394             } else {
20395                 if (DDM._timeoutCount > 2000) {
20396                 } else {
20397                     setTimeout(DDM._addListeners, 10);
20398                     if (document && document.body) {
20399                         DDM._timeoutCount += 1;
20400                     }
20401                 }
20402             }
20403         },
20404
20405         /**
20406          * Recursively searches the immediate parent and all child nodes for
20407          * the handle element in order to determine wheter or not it was
20408          * clicked.
20409          * @method handleWasClicked
20410          * @param node the html element to inspect
20411          * @static
20412          */
20413         handleWasClicked: function(node, id) {
20414             if (this.isHandle(id, node.id)) {
20415                 return true;
20416             } else {
20417                 // check to see if this is a text node child of the one we want
20418                 var p = node.parentNode;
20419
20420                 while (p) {
20421                     if (this.isHandle(id, p.id)) {
20422                         return true;
20423                     } else {
20424                         p = p.parentNode;
20425                     }
20426                 }
20427             }
20428
20429             return false;
20430         }
20431
20432     };
20433
20434 }();
20435
20436 // shorter alias, save a few bytes
20437 Roo.dd.DDM = Roo.dd.DragDropMgr;
20438 Roo.dd.DDM._addListeners();
20439
20440 }/*
20441  * Based on:
20442  * Ext JS Library 1.1.1
20443  * Copyright(c) 2006-2007, Ext JS, LLC.
20444  *
20445  * Originally Released Under LGPL - original licence link has changed is not relivant.
20446  *
20447  * Fork - LGPL
20448  * <script type="text/javascript">
20449  */
20450
20451 /**
20452  * @class Roo.dd.DD
20453  * A DragDrop implementation where the linked element follows the
20454  * mouse cursor during a drag.
20455  * @extends Roo.dd.DragDrop
20456  * @constructor
20457  * @param {String} id the id of the linked element
20458  * @param {String} sGroup the group of related DragDrop items
20459  * @param {object} config an object containing configurable attributes
20460  *                Valid properties for DD:
20461  *                    scroll
20462  */
20463 Roo.dd.DD = function(id, sGroup, config) {
20464     if (id) {
20465         this.init(id, sGroup, config);
20466     }
20467 };
20468
20469 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20470
20471     /**
20472      * When set to true, the utility automatically tries to scroll the browser
20473      * window wehn a drag and drop element is dragged near the viewport boundary.
20474      * Defaults to true.
20475      * @property scroll
20476      * @type boolean
20477      */
20478     scroll: true,
20479
20480     /**
20481      * Sets the pointer offset to the distance between the linked element's top
20482      * left corner and the location the element was clicked
20483      * @method autoOffset
20484      * @param {int} iPageX the X coordinate of the click
20485      * @param {int} iPageY the Y coordinate of the click
20486      */
20487     autoOffset: function(iPageX, iPageY) {
20488         var x = iPageX - this.startPageX;
20489         var y = iPageY - this.startPageY;
20490         this.setDelta(x, y);
20491     },
20492
20493     /**
20494      * Sets the pointer offset.  You can call this directly to force the
20495      * offset to be in a particular location (e.g., pass in 0,0 to set it
20496      * to the center of the object)
20497      * @method setDelta
20498      * @param {int} iDeltaX the distance from the left
20499      * @param {int} iDeltaY the distance from the top
20500      */
20501     setDelta: function(iDeltaX, iDeltaY) {
20502         this.deltaX = iDeltaX;
20503         this.deltaY = iDeltaY;
20504     },
20505
20506     /**
20507      * Sets the drag element to the location of the mousedown or click event,
20508      * maintaining the cursor location relative to the location on the element
20509      * that was clicked.  Override this if you want to place the element in a
20510      * location other than where the cursor is.
20511      * @method setDragElPos
20512      * @param {int} iPageX the X coordinate of the mousedown or drag event
20513      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20514      */
20515     setDragElPos: function(iPageX, iPageY) {
20516         // the first time we do this, we are going to check to make sure
20517         // the element has css positioning
20518
20519         var el = this.getDragEl();
20520         this.alignElWithMouse(el, iPageX, iPageY);
20521     },
20522
20523     /**
20524      * Sets the element to the location of the mousedown or click event,
20525      * maintaining the cursor location relative to the location on the element
20526      * that was clicked.  Override this if you want to place the element in a
20527      * location other than where the cursor is.
20528      * @method alignElWithMouse
20529      * @param {HTMLElement} el the element to move
20530      * @param {int} iPageX the X coordinate of the mousedown or drag event
20531      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20532      */
20533     alignElWithMouse: function(el, iPageX, iPageY) {
20534         var oCoord = this.getTargetCoord(iPageX, iPageY);
20535         var fly = el.dom ? el : Roo.fly(el);
20536         if (!this.deltaSetXY) {
20537             var aCoord = [oCoord.x, oCoord.y];
20538             fly.setXY(aCoord);
20539             var newLeft = fly.getLeft(true);
20540             var newTop  = fly.getTop(true);
20541             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20542         } else {
20543             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20544         }
20545
20546         this.cachePosition(oCoord.x, oCoord.y);
20547         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20548         return oCoord;
20549     },
20550
20551     /**
20552      * Saves the most recent position so that we can reset the constraints and
20553      * tick marks on-demand.  We need to know this so that we can calculate the
20554      * number of pixels the element is offset from its original position.
20555      * @method cachePosition
20556      * @param iPageX the current x position (optional, this just makes it so we
20557      * don't have to look it up again)
20558      * @param iPageY the current y position (optional, this just makes it so we
20559      * don't have to look it up again)
20560      */
20561     cachePosition: function(iPageX, iPageY) {
20562         if (iPageX) {
20563             this.lastPageX = iPageX;
20564             this.lastPageY = iPageY;
20565         } else {
20566             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20567             this.lastPageX = aCoord[0];
20568             this.lastPageY = aCoord[1];
20569         }
20570     },
20571
20572     /**
20573      * Auto-scroll the window if the dragged object has been moved beyond the
20574      * visible window boundary.
20575      * @method autoScroll
20576      * @param {int} x the drag element's x position
20577      * @param {int} y the drag element's y position
20578      * @param {int} h the height of the drag element
20579      * @param {int} w the width of the drag element
20580      * @private
20581      */
20582     autoScroll: function(x, y, h, w) {
20583
20584         if (this.scroll) {
20585             // The client height
20586             var clientH = Roo.lib.Dom.getViewWidth();
20587
20588             // The client width
20589             var clientW = Roo.lib.Dom.getViewHeight();
20590
20591             // The amt scrolled down
20592             var st = this.DDM.getScrollTop();
20593
20594             // The amt scrolled right
20595             var sl = this.DDM.getScrollLeft();
20596
20597             // Location of the bottom of the element
20598             var bot = h + y;
20599
20600             // Location of the right of the element
20601             var right = w + x;
20602
20603             // The distance from the cursor to the bottom of the visible area,
20604             // adjusted so that we don't scroll if the cursor is beyond the
20605             // element drag constraints
20606             var toBot = (clientH + st - y - this.deltaY);
20607
20608             // The distance from the cursor to the right of the visible area
20609             var toRight = (clientW + sl - x - this.deltaX);
20610
20611
20612             // How close to the edge the cursor must be before we scroll
20613             // var thresh = (document.all) ? 100 : 40;
20614             var thresh = 40;
20615
20616             // How many pixels to scroll per autoscroll op.  This helps to reduce
20617             // clunky scrolling. IE is more sensitive about this ... it needs this
20618             // value to be higher.
20619             var scrAmt = (document.all) ? 80 : 30;
20620
20621             // Scroll down if we are near the bottom of the visible page and the
20622             // obj extends below the crease
20623             if ( bot > clientH && toBot < thresh ) {
20624                 window.scrollTo(sl, st + scrAmt);
20625             }
20626
20627             // Scroll up if the window is scrolled down and the top of the object
20628             // goes above the top border
20629             if ( y < st && st > 0 && y - st < thresh ) {
20630                 window.scrollTo(sl, st - scrAmt);
20631             }
20632
20633             // Scroll right if the obj is beyond the right border and the cursor is
20634             // near the border.
20635             if ( right > clientW && toRight < thresh ) {
20636                 window.scrollTo(sl + scrAmt, st);
20637             }
20638
20639             // Scroll left if the window has been scrolled to the right and the obj
20640             // extends past the left border
20641             if ( x < sl && sl > 0 && x - sl < thresh ) {
20642                 window.scrollTo(sl - scrAmt, st);
20643             }
20644         }
20645     },
20646
20647     /**
20648      * Finds the location the element should be placed if we want to move
20649      * it to where the mouse location less the click offset would place us.
20650      * @method getTargetCoord
20651      * @param {int} iPageX the X coordinate of the click
20652      * @param {int} iPageY the Y coordinate of the click
20653      * @return an object that contains the coordinates (Object.x and Object.y)
20654      * @private
20655      */
20656     getTargetCoord: function(iPageX, iPageY) {
20657
20658
20659         var x = iPageX - this.deltaX;
20660         var y = iPageY - this.deltaY;
20661
20662         if (this.constrainX) {
20663             if (x < this.minX) { x = this.minX; }
20664             if (x > this.maxX) { x = this.maxX; }
20665         }
20666
20667         if (this.constrainY) {
20668             if (y < this.minY) { y = this.minY; }
20669             if (y > this.maxY) { y = this.maxY; }
20670         }
20671
20672         x = this.getTick(x, this.xTicks);
20673         y = this.getTick(y, this.yTicks);
20674
20675
20676         return {x:x, y:y};
20677     },
20678
20679     /*
20680      * Sets up config options specific to this class. Overrides
20681      * Roo.dd.DragDrop, but all versions of this method through the
20682      * inheritance chain are called
20683      */
20684     applyConfig: function() {
20685         Roo.dd.DD.superclass.applyConfig.call(this);
20686         this.scroll = (this.config.scroll !== false);
20687     },
20688
20689     /*
20690      * Event that fires prior to the onMouseDown event.  Overrides
20691      * Roo.dd.DragDrop.
20692      */
20693     b4MouseDown: function(e) {
20694         // this.resetConstraints();
20695         this.autoOffset(e.getPageX(),
20696                             e.getPageY());
20697     },
20698
20699     /*
20700      * Event that fires prior to the onDrag event.  Overrides
20701      * Roo.dd.DragDrop.
20702      */
20703     b4Drag: function(e) {
20704         this.setDragElPos(e.getPageX(),
20705                             e.getPageY());
20706     },
20707
20708     toString: function() {
20709         return ("DD " + this.id);
20710     }
20711
20712     //////////////////////////////////////////////////////////////////////////
20713     // Debugging ygDragDrop events that can be overridden
20714     //////////////////////////////////////////////////////////////////////////
20715     /*
20716     startDrag: function(x, y) {
20717     },
20718
20719     onDrag: function(e) {
20720     },
20721
20722     onDragEnter: function(e, id) {
20723     },
20724
20725     onDragOver: function(e, id) {
20726     },
20727
20728     onDragOut: function(e, id) {
20729     },
20730
20731     onDragDrop: function(e, id) {
20732     },
20733
20734     endDrag: function(e) {
20735     }
20736
20737     */
20738
20739 });/*
20740  * Based on:
20741  * Ext JS Library 1.1.1
20742  * Copyright(c) 2006-2007, Ext JS, LLC.
20743  *
20744  * Originally Released Under LGPL - original licence link has changed is not relivant.
20745  *
20746  * Fork - LGPL
20747  * <script type="text/javascript">
20748  */
20749
20750 /**
20751  * @class Roo.dd.DDProxy
20752  * A DragDrop implementation that inserts an empty, bordered div into
20753  * the document that follows the cursor during drag operations.  At the time of
20754  * the click, the frame div is resized to the dimensions of the linked html
20755  * element, and moved to the exact location of the linked element.
20756  *
20757  * References to the "frame" element refer to the single proxy element that
20758  * was created to be dragged in place of all DDProxy elements on the
20759  * page.
20760  *
20761  * @extends Roo.dd.DD
20762  * @constructor
20763  * @param {String} id the id of the linked html element
20764  * @param {String} sGroup the group of related DragDrop objects
20765  * @param {object} config an object containing configurable attributes
20766  *                Valid properties for DDProxy in addition to those in DragDrop:
20767  *                   resizeFrame, centerFrame, dragElId
20768  */
20769 Roo.dd.DDProxy = function(id, sGroup, config) {
20770     if (id) {
20771         this.init(id, sGroup, config);
20772         this.initFrame();
20773     }
20774 };
20775
20776 /**
20777  * The default drag frame div id
20778  * @property Roo.dd.DDProxy.dragElId
20779  * @type String
20780  * @static
20781  */
20782 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20783
20784 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20785
20786     /**
20787      * By default we resize the drag frame to be the same size as the element
20788      * we want to drag (this is to get the frame effect).  We can turn it off
20789      * if we want a different behavior.
20790      * @property resizeFrame
20791      * @type boolean
20792      */
20793     resizeFrame: true,
20794
20795     /**
20796      * By default the frame is positioned exactly where the drag element is, so
20797      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20798      * you do not have constraints on the obj is to have the drag frame centered
20799      * around the cursor.  Set centerFrame to true for this effect.
20800      * @property centerFrame
20801      * @type boolean
20802      */
20803     centerFrame: false,
20804
20805     /**
20806      * Creates the proxy element if it does not yet exist
20807      * @method createFrame
20808      */
20809     createFrame: function() {
20810         var self = this;
20811         var body = document.body;
20812
20813         if (!body || !body.firstChild) {
20814             setTimeout( function() { self.createFrame(); }, 50 );
20815             return;
20816         }
20817
20818         var div = this.getDragEl();
20819
20820         if (!div) {
20821             div    = document.createElement("div");
20822             div.id = this.dragElId;
20823             var s  = div.style;
20824
20825             s.position   = "absolute";
20826             s.visibility = "hidden";
20827             s.cursor     = "move";
20828             s.border     = "2px solid #aaa";
20829             s.zIndex     = 999;
20830
20831             // appendChild can blow up IE if invoked prior to the window load event
20832             // while rendering a table.  It is possible there are other scenarios
20833             // that would cause this to happen as well.
20834             body.insertBefore(div, body.firstChild);
20835         }
20836     },
20837
20838     /**
20839      * Initialization for the drag frame element.  Must be called in the
20840      * constructor of all subclasses
20841      * @method initFrame
20842      */
20843     initFrame: function() {
20844         this.createFrame();
20845     },
20846
20847     applyConfig: function() {
20848         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20849
20850         this.resizeFrame = (this.config.resizeFrame !== false);
20851         this.centerFrame = (this.config.centerFrame);
20852         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20853     },
20854
20855     /**
20856      * Resizes the drag frame to the dimensions of the clicked object, positions
20857      * it over the object, and finally displays it
20858      * @method showFrame
20859      * @param {int} iPageX X click position
20860      * @param {int} iPageY Y click position
20861      * @private
20862      */
20863     showFrame: function(iPageX, iPageY) {
20864         var el = this.getEl();
20865         var dragEl = this.getDragEl();
20866         var s = dragEl.style;
20867
20868         this._resizeProxy();
20869
20870         if (this.centerFrame) {
20871             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20872                            Math.round(parseInt(s.height, 10)/2) );
20873         }
20874
20875         this.setDragElPos(iPageX, iPageY);
20876
20877         Roo.fly(dragEl).show();
20878     },
20879
20880     /**
20881      * The proxy is automatically resized to the dimensions of the linked
20882      * element when a drag is initiated, unless resizeFrame is set to false
20883      * @method _resizeProxy
20884      * @private
20885      */
20886     _resizeProxy: function() {
20887         if (this.resizeFrame) {
20888             var el = this.getEl();
20889             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20890         }
20891     },
20892
20893     // overrides Roo.dd.DragDrop
20894     b4MouseDown: function(e) {
20895         var x = e.getPageX();
20896         var y = e.getPageY();
20897         this.autoOffset(x, y);
20898         this.setDragElPos(x, y);
20899     },
20900
20901     // overrides Roo.dd.DragDrop
20902     b4StartDrag: function(x, y) {
20903         // show the drag frame
20904         this.showFrame(x, y);
20905     },
20906
20907     // overrides Roo.dd.DragDrop
20908     b4EndDrag: function(e) {
20909         Roo.fly(this.getDragEl()).hide();
20910     },
20911
20912     // overrides Roo.dd.DragDrop
20913     // By default we try to move the element to the last location of the frame.
20914     // This is so that the default behavior mirrors that of Roo.dd.DD.
20915     endDrag: function(e) {
20916
20917         var lel = this.getEl();
20918         var del = this.getDragEl();
20919
20920         // Show the drag frame briefly so we can get its position
20921         del.style.visibility = "";
20922
20923         this.beforeMove();
20924         // Hide the linked element before the move to get around a Safari
20925         // rendering bug.
20926         lel.style.visibility = "hidden";
20927         Roo.dd.DDM.moveToEl(lel, del);
20928         del.style.visibility = "hidden";
20929         lel.style.visibility = "";
20930
20931         this.afterDrag();
20932     },
20933
20934     beforeMove : function(){
20935
20936     },
20937
20938     afterDrag : function(){
20939
20940     },
20941
20942     toString: function() {
20943         return ("DDProxy " + this.id);
20944     }
20945
20946 });
20947 /*
20948  * Based on:
20949  * Ext JS Library 1.1.1
20950  * Copyright(c) 2006-2007, Ext JS, LLC.
20951  *
20952  * Originally Released Under LGPL - original licence link has changed is not relivant.
20953  *
20954  * Fork - LGPL
20955  * <script type="text/javascript">
20956  */
20957
20958  /**
20959  * @class Roo.dd.DDTarget
20960  * A DragDrop implementation that does not move, but can be a drop
20961  * target.  You would get the same result by simply omitting implementation
20962  * for the event callbacks, but this way we reduce the processing cost of the
20963  * event listener and the callbacks.
20964  * @extends Roo.dd.DragDrop
20965  * @constructor
20966  * @param {String} id the id of the element that is a drop target
20967  * @param {String} sGroup the group of related DragDrop objects
20968  * @param {object} config an object containing configurable attributes
20969  *                 Valid properties for DDTarget in addition to those in
20970  *                 DragDrop:
20971  *                    none
20972  */
20973 Roo.dd.DDTarget = function(id, sGroup, config) {
20974     if (id) {
20975         this.initTarget(id, sGroup, config);
20976     }
20977     if (config.listeners || config.events) { 
20978        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20979             listeners : config.listeners || {}, 
20980             events : config.events || {} 
20981         });    
20982     }
20983 };
20984
20985 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20986 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20987     toString: function() {
20988         return ("DDTarget " + this.id);
20989     }
20990 });
20991 /*
20992  * Based on:
20993  * Ext JS Library 1.1.1
20994  * Copyright(c) 2006-2007, Ext JS, LLC.
20995  *
20996  * Originally Released Under LGPL - original licence link has changed is not relivant.
20997  *
20998  * Fork - LGPL
20999  * <script type="text/javascript">
21000  */
21001  
21002
21003 /**
21004  * @class Roo.dd.ScrollManager
21005  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21006  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21007  * @singleton
21008  */
21009 Roo.dd.ScrollManager = function(){
21010     var ddm = Roo.dd.DragDropMgr;
21011     var els = {};
21012     var dragEl = null;
21013     var proc = {};
21014     
21015     
21016     
21017     var onStop = function(e){
21018         dragEl = null;
21019         clearProc();
21020     };
21021     
21022     var triggerRefresh = function(){
21023         if(ddm.dragCurrent){
21024              ddm.refreshCache(ddm.dragCurrent.groups);
21025         }
21026     };
21027     
21028     var doScroll = function(){
21029         if(ddm.dragCurrent){
21030             var dds = Roo.dd.ScrollManager;
21031             if(!dds.animate){
21032                 if(proc.el.scroll(proc.dir, dds.increment)){
21033                     triggerRefresh();
21034                 }
21035             }else{
21036                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21037             }
21038         }
21039     };
21040     
21041     var clearProc = function(){
21042         if(proc.id){
21043             clearInterval(proc.id);
21044         }
21045         proc.id = 0;
21046         proc.el = null;
21047         proc.dir = "";
21048     };
21049     
21050     var startProc = function(el, dir){
21051          Roo.log('scroll startproc');
21052         clearProc();
21053         proc.el = el;
21054         proc.dir = dir;
21055         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21056     };
21057     
21058     var onFire = function(e, isDrop){
21059        
21060         if(isDrop || !ddm.dragCurrent){ return; }
21061         var dds = Roo.dd.ScrollManager;
21062         if(!dragEl || dragEl != ddm.dragCurrent){
21063             dragEl = ddm.dragCurrent;
21064             // refresh regions on drag start
21065             dds.refreshCache();
21066         }
21067         
21068         var xy = Roo.lib.Event.getXY(e);
21069         var pt = new Roo.lib.Point(xy[0], xy[1]);
21070         for(var id in els){
21071             var el = els[id], r = el._region;
21072             if(r && r.contains(pt) && el.isScrollable()){
21073                 if(r.bottom - pt.y <= dds.thresh){
21074                     if(proc.el != el){
21075                         startProc(el, "down");
21076                     }
21077                     return;
21078                 }else if(r.right - pt.x <= dds.thresh){
21079                     if(proc.el != el){
21080                         startProc(el, "left");
21081                     }
21082                     return;
21083                 }else if(pt.y - r.top <= dds.thresh){
21084                     if(proc.el != el){
21085                         startProc(el, "up");
21086                     }
21087                     return;
21088                 }else if(pt.x - r.left <= dds.thresh){
21089                     if(proc.el != el){
21090                         startProc(el, "right");
21091                     }
21092                     return;
21093                 }
21094             }
21095         }
21096         clearProc();
21097     };
21098     
21099     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21100     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21101     
21102     return {
21103         /**
21104          * Registers new overflow element(s) to auto scroll
21105          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21106          */
21107         register : function(el){
21108             if(el instanceof Array){
21109                 for(var i = 0, len = el.length; i < len; i++) {
21110                         this.register(el[i]);
21111                 }
21112             }else{
21113                 el = Roo.get(el);
21114                 els[el.id] = el;
21115             }
21116             Roo.dd.ScrollManager.els = els;
21117         },
21118         
21119         /**
21120          * Unregisters overflow element(s) so they are no longer scrolled
21121          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21122          */
21123         unregister : function(el){
21124             if(el instanceof Array){
21125                 for(var i = 0, len = el.length; i < len; i++) {
21126                         this.unregister(el[i]);
21127                 }
21128             }else{
21129                 el = Roo.get(el);
21130                 delete els[el.id];
21131             }
21132         },
21133         
21134         /**
21135          * The number of pixels from the edge of a container the pointer needs to be to 
21136          * trigger scrolling (defaults to 25)
21137          * @type Number
21138          */
21139         thresh : 25,
21140         
21141         /**
21142          * The number of pixels to scroll in each scroll increment (defaults to 50)
21143          * @type Number
21144          */
21145         increment : 100,
21146         
21147         /**
21148          * The frequency of scrolls in milliseconds (defaults to 500)
21149          * @type Number
21150          */
21151         frequency : 500,
21152         
21153         /**
21154          * True to animate the scroll (defaults to true)
21155          * @type Boolean
21156          */
21157         animate: true,
21158         
21159         /**
21160          * The animation duration in seconds - 
21161          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21162          * @type Number
21163          */
21164         animDuration: .4,
21165         
21166         /**
21167          * Manually trigger a cache refresh.
21168          */
21169         refreshCache : function(){
21170             for(var id in els){
21171                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21172                     els[id]._region = els[id].getRegion();
21173                 }
21174             }
21175         }
21176     };
21177 }();/*
21178  * Based on:
21179  * Ext JS Library 1.1.1
21180  * Copyright(c) 2006-2007, Ext JS, LLC.
21181  *
21182  * Originally Released Under LGPL - original licence link has changed is not relivant.
21183  *
21184  * Fork - LGPL
21185  * <script type="text/javascript">
21186  */
21187  
21188
21189 /**
21190  * @class Roo.dd.Registry
21191  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21192  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21193  * @singleton
21194  */
21195 Roo.dd.Registry = function(){
21196     var elements = {}; 
21197     var handles = {}; 
21198     var autoIdSeed = 0;
21199
21200     var getId = function(el, autogen){
21201         if(typeof el == "string"){
21202             return el;
21203         }
21204         var id = el.id;
21205         if(!id && autogen !== false){
21206             id = "roodd-" + (++autoIdSeed);
21207             el.id = id;
21208         }
21209         return id;
21210     };
21211     
21212     return {
21213     /**
21214      * Register a drag drop element
21215      * @param {String|HTMLElement} element The id or DOM node to register
21216      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21217      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21218      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21219      * populated in the data object (if applicable):
21220      * <pre>
21221 Value      Description<br />
21222 ---------  ------------------------------------------<br />
21223 handles    Array of DOM nodes that trigger dragging<br />
21224            for the element being registered<br />
21225 isHandle   True if the element passed in triggers<br />
21226            dragging itself, else false
21227 </pre>
21228      */
21229         register : function(el, data){
21230             data = data || {};
21231             if(typeof el == "string"){
21232                 el = document.getElementById(el);
21233             }
21234             data.ddel = el;
21235             elements[getId(el)] = data;
21236             if(data.isHandle !== false){
21237                 handles[data.ddel.id] = data;
21238             }
21239             if(data.handles){
21240                 var hs = data.handles;
21241                 for(var i = 0, len = hs.length; i < len; i++){
21242                         handles[getId(hs[i])] = data;
21243                 }
21244             }
21245         },
21246
21247     /**
21248      * Unregister a drag drop element
21249      * @param {String|HTMLElement}  element The id or DOM node to unregister
21250      */
21251         unregister : function(el){
21252             var id = getId(el, false);
21253             var data = elements[id];
21254             if(data){
21255                 delete elements[id];
21256                 if(data.handles){
21257                     var hs = data.handles;
21258                     for(var i = 0, len = hs.length; i < len; i++){
21259                         delete handles[getId(hs[i], false)];
21260                     }
21261                 }
21262             }
21263         },
21264
21265     /**
21266      * Returns the handle registered for a DOM Node by id
21267      * @param {String|HTMLElement} id The DOM node or id to look up
21268      * @return {Object} handle The custom handle data
21269      */
21270         getHandle : function(id){
21271             if(typeof id != "string"){ // must be element?
21272                 id = id.id;
21273             }
21274             return handles[id];
21275         },
21276
21277     /**
21278      * Returns the handle that is registered for the DOM node that is the target of the event
21279      * @param {Event} e The event
21280      * @return {Object} handle The custom handle data
21281      */
21282         getHandleFromEvent : function(e){
21283             var t = Roo.lib.Event.getTarget(e);
21284             return t ? handles[t.id] : null;
21285         },
21286
21287     /**
21288      * Returns a custom data object that is registered for a DOM node by id
21289      * @param {String|HTMLElement} id The DOM node or id to look up
21290      * @return {Object} data The custom data
21291      */
21292         getTarget : function(id){
21293             if(typeof id != "string"){ // must be element?
21294                 id = id.id;
21295             }
21296             return elements[id];
21297         },
21298
21299     /**
21300      * Returns a custom data object that is registered for the DOM node that is the target of the event
21301      * @param {Event} e The event
21302      * @return {Object} data The custom data
21303      */
21304         getTargetFromEvent : function(e){
21305             var t = Roo.lib.Event.getTarget(e);
21306             return t ? elements[t.id] || handles[t.id] : null;
21307         }
21308     };
21309 }();/*
21310  * Based on:
21311  * Ext JS Library 1.1.1
21312  * Copyright(c) 2006-2007, Ext JS, LLC.
21313  *
21314  * Originally Released Under LGPL - original licence link has changed is not relivant.
21315  *
21316  * Fork - LGPL
21317  * <script type="text/javascript">
21318  */
21319  
21320
21321 /**
21322  * @class Roo.dd.StatusProxy
21323  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21324  * default drag proxy used by all Roo.dd components.
21325  * @constructor
21326  * @param {Object} config
21327  */
21328 Roo.dd.StatusProxy = function(config){
21329     Roo.apply(this, config);
21330     this.id = this.id || Roo.id();
21331     this.el = new Roo.Layer({
21332         dh: {
21333             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21334                 {tag: "div", cls: "x-dd-drop-icon"},
21335                 {tag: "div", cls: "x-dd-drag-ghost"}
21336             ]
21337         }, 
21338         shadow: !config || config.shadow !== false
21339     });
21340     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21341     this.dropStatus = this.dropNotAllowed;
21342 };
21343
21344 Roo.dd.StatusProxy.prototype = {
21345     /**
21346      * @cfg {String} dropAllowed
21347      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21348      */
21349     dropAllowed : "x-dd-drop-ok",
21350     /**
21351      * @cfg {String} dropNotAllowed
21352      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21353      */
21354     dropNotAllowed : "x-dd-drop-nodrop",
21355
21356     /**
21357      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21358      * over the current target element.
21359      * @param {String} cssClass The css class for the new drop status indicator image
21360      */
21361     setStatus : function(cssClass){
21362         cssClass = cssClass || this.dropNotAllowed;
21363         if(this.dropStatus != cssClass){
21364             this.el.replaceClass(this.dropStatus, cssClass);
21365             this.dropStatus = cssClass;
21366         }
21367     },
21368
21369     /**
21370      * Resets the status indicator to the default dropNotAllowed value
21371      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21372      */
21373     reset : function(clearGhost){
21374         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21375         this.dropStatus = this.dropNotAllowed;
21376         if(clearGhost){
21377             this.ghost.update("");
21378         }
21379     },
21380
21381     /**
21382      * Updates the contents of the ghost element
21383      * @param {String} html The html that will replace the current innerHTML of the ghost element
21384      */
21385     update : function(html){
21386         if(typeof html == "string"){
21387             this.ghost.update(html);
21388         }else{
21389             this.ghost.update("");
21390             html.style.margin = "0";
21391             this.ghost.dom.appendChild(html);
21392         }
21393         // ensure float = none set?? cant remember why though.
21394         var el = this.ghost.dom.firstChild;
21395                 if(el){
21396                         Roo.fly(el).setStyle('float', 'none');
21397                 }
21398     },
21399     
21400     /**
21401      * Returns the underlying proxy {@link Roo.Layer}
21402      * @return {Roo.Layer} el
21403     */
21404     getEl : function(){
21405         return this.el;
21406     },
21407
21408     /**
21409      * Returns the ghost element
21410      * @return {Roo.Element} el
21411      */
21412     getGhost : function(){
21413         return this.ghost;
21414     },
21415
21416     /**
21417      * Hides the proxy
21418      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21419      */
21420     hide : function(clear){
21421         this.el.hide();
21422         if(clear){
21423             this.reset(true);
21424         }
21425     },
21426
21427     /**
21428      * Stops the repair animation if it's currently running
21429      */
21430     stop : function(){
21431         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21432             this.anim.stop();
21433         }
21434     },
21435
21436     /**
21437      * Displays this proxy
21438      */
21439     show : function(){
21440         this.el.show();
21441     },
21442
21443     /**
21444      * Force the Layer to sync its shadow and shim positions to the element
21445      */
21446     sync : function(){
21447         this.el.sync();
21448     },
21449
21450     /**
21451      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21452      * invalid drop operation by the item being dragged.
21453      * @param {Array} xy The XY position of the element ([x, y])
21454      * @param {Function} callback The function to call after the repair is complete
21455      * @param {Object} scope The scope in which to execute the callback
21456      */
21457     repair : function(xy, callback, scope){
21458         this.callback = callback;
21459         this.scope = scope;
21460         if(xy && this.animRepair !== false){
21461             this.el.addClass("x-dd-drag-repair");
21462             this.el.hideUnders(true);
21463             this.anim = this.el.shift({
21464                 duration: this.repairDuration || .5,
21465                 easing: 'easeOut',
21466                 xy: xy,
21467                 stopFx: true,
21468                 callback: this.afterRepair,
21469                 scope: this
21470             });
21471         }else{
21472             this.afterRepair();
21473         }
21474     },
21475
21476     // private
21477     afterRepair : function(){
21478         this.hide(true);
21479         if(typeof this.callback == "function"){
21480             this.callback.call(this.scope || this);
21481         }
21482         this.callback = null;
21483         this.scope = null;
21484     }
21485 };/*
21486  * Based on:
21487  * Ext JS Library 1.1.1
21488  * Copyright(c) 2006-2007, Ext JS, LLC.
21489  *
21490  * Originally Released Under LGPL - original licence link has changed is not relivant.
21491  *
21492  * Fork - LGPL
21493  * <script type="text/javascript">
21494  */
21495
21496 /**
21497  * @class Roo.dd.DragSource
21498  * @extends Roo.dd.DDProxy
21499  * A simple class that provides the basic implementation needed to make any element draggable.
21500  * @constructor
21501  * @param {String/HTMLElement/Element} el The container element
21502  * @param {Object} config
21503  */
21504 Roo.dd.DragSource = function(el, config){
21505     this.el = Roo.get(el);
21506     this.dragData = {};
21507     
21508     Roo.apply(this, config);
21509     
21510     if(!this.proxy){
21511         this.proxy = new Roo.dd.StatusProxy();
21512     }
21513
21514     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21515           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21516     
21517     this.dragging = false;
21518 };
21519
21520 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21521     /**
21522      * @cfg {String} dropAllowed
21523      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21524      */
21525     dropAllowed : "x-dd-drop-ok",
21526     /**
21527      * @cfg {String} dropNotAllowed
21528      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21529      */
21530     dropNotAllowed : "x-dd-drop-nodrop",
21531
21532     /**
21533      * Returns the data object associated with this drag source
21534      * @return {Object} data An object containing arbitrary data
21535      */
21536     getDragData : function(e){
21537         return this.dragData;
21538     },
21539
21540     // private
21541     onDragEnter : function(e, id){
21542         var target = Roo.dd.DragDropMgr.getDDById(id);
21543         this.cachedTarget = target;
21544         if(this.beforeDragEnter(target, e, id) !== false){
21545             if(target.isNotifyTarget){
21546                 var status = target.notifyEnter(this, e, this.dragData);
21547                 this.proxy.setStatus(status);
21548             }else{
21549                 this.proxy.setStatus(this.dropAllowed);
21550             }
21551             
21552             if(this.afterDragEnter){
21553                 /**
21554                  * An empty function by default, but provided so that you can perform a custom action
21555                  * when the dragged item enters the drop target by providing an implementation.
21556                  * @param {Roo.dd.DragDrop} target The drop target
21557                  * @param {Event} e The event object
21558                  * @param {String} id The id of the dragged element
21559                  * @method afterDragEnter
21560                  */
21561                 this.afterDragEnter(target, e, id);
21562             }
21563         }
21564     },
21565
21566     /**
21567      * An empty function by default, but provided so that you can perform a custom action
21568      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21569      * @param {Roo.dd.DragDrop} target The drop target
21570      * @param {Event} e The event object
21571      * @param {String} id The id of the dragged element
21572      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21573      */
21574     beforeDragEnter : function(target, e, id){
21575         return true;
21576     },
21577
21578     // private
21579     alignElWithMouse: function() {
21580         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21581         this.proxy.sync();
21582     },
21583
21584     // private
21585     onDragOver : function(e, id){
21586         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21587         if(this.beforeDragOver(target, e, id) !== false){
21588             if(target.isNotifyTarget){
21589                 var status = target.notifyOver(this, e, this.dragData);
21590                 this.proxy.setStatus(status);
21591             }
21592
21593             if(this.afterDragOver){
21594                 /**
21595                  * An empty function by default, but provided so that you can perform a custom action
21596                  * while the dragged item is over the drop target by providing an implementation.
21597                  * @param {Roo.dd.DragDrop} target The drop target
21598                  * @param {Event} e The event object
21599                  * @param {String} id The id of the dragged element
21600                  * @method afterDragOver
21601                  */
21602                 this.afterDragOver(target, e, id);
21603             }
21604         }
21605     },
21606
21607     /**
21608      * An empty function by default, but provided so that you can perform a custom action
21609      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21610      * @param {Roo.dd.DragDrop} target The drop target
21611      * @param {Event} e The event object
21612      * @param {String} id The id of the dragged element
21613      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21614      */
21615     beforeDragOver : function(target, e, id){
21616         return true;
21617     },
21618
21619     // private
21620     onDragOut : function(e, id){
21621         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21622         if(this.beforeDragOut(target, e, id) !== false){
21623             if(target.isNotifyTarget){
21624                 target.notifyOut(this, e, this.dragData);
21625             }
21626             this.proxy.reset();
21627             if(this.afterDragOut){
21628                 /**
21629                  * An empty function by default, but provided so that you can perform a custom action
21630                  * after the dragged item is dragged out of the target without dropping.
21631                  * @param {Roo.dd.DragDrop} target The drop target
21632                  * @param {Event} e The event object
21633                  * @param {String} id The id of the dragged element
21634                  * @method afterDragOut
21635                  */
21636                 this.afterDragOut(target, e, id);
21637             }
21638         }
21639         this.cachedTarget = null;
21640     },
21641
21642     /**
21643      * An empty function by default, but provided so that you can perform a custom action before the dragged
21644      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21645      * @param {Roo.dd.DragDrop} target The drop target
21646      * @param {Event} e The event object
21647      * @param {String} id The id of the dragged element
21648      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21649      */
21650     beforeDragOut : function(target, e, id){
21651         return true;
21652     },
21653     
21654     // private
21655     onDragDrop : function(e, id){
21656         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21657         if(this.beforeDragDrop(target, e, id) !== false){
21658             if(target.isNotifyTarget){
21659                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21660                     this.onValidDrop(target, e, id);
21661                 }else{
21662                     this.onInvalidDrop(target, e, id);
21663                 }
21664             }else{
21665                 this.onValidDrop(target, e, id);
21666             }
21667             
21668             if(this.afterDragDrop){
21669                 /**
21670                  * An empty function by default, but provided so that you can perform a custom action
21671                  * after a valid drag drop has occurred by providing an implementation.
21672                  * @param {Roo.dd.DragDrop} target The drop target
21673                  * @param {Event} e The event object
21674                  * @param {String} id The id of the dropped element
21675                  * @method afterDragDrop
21676                  */
21677                 this.afterDragDrop(target, e, id);
21678             }
21679         }
21680         delete this.cachedTarget;
21681     },
21682
21683     /**
21684      * An empty function by default, but provided so that you can perform a custom action before the dragged
21685      * item is dropped onto the target and optionally cancel the onDragDrop.
21686      * @param {Roo.dd.DragDrop} target The drop target
21687      * @param {Event} e The event object
21688      * @param {String} id The id of the dragged element
21689      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21690      */
21691     beforeDragDrop : function(target, e, id){
21692         return true;
21693     },
21694
21695     // private
21696     onValidDrop : function(target, e, id){
21697         this.hideProxy();
21698         if(this.afterValidDrop){
21699             /**
21700              * An empty function by default, but provided so that you can perform a custom action
21701              * after a valid drop has occurred by providing an implementation.
21702              * @param {Object} target The target DD 
21703              * @param {Event} e The event object
21704              * @param {String} id The id of the dropped element
21705              * @method afterInvalidDrop
21706              */
21707             this.afterValidDrop(target, e, id);
21708         }
21709     },
21710
21711     // private
21712     getRepairXY : function(e, data){
21713         return this.el.getXY();  
21714     },
21715
21716     // private
21717     onInvalidDrop : function(target, e, id){
21718         this.beforeInvalidDrop(target, e, id);
21719         if(this.cachedTarget){
21720             if(this.cachedTarget.isNotifyTarget){
21721                 this.cachedTarget.notifyOut(this, e, this.dragData);
21722             }
21723             this.cacheTarget = null;
21724         }
21725         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21726
21727         if(this.afterInvalidDrop){
21728             /**
21729              * An empty function by default, but provided so that you can perform a custom action
21730              * after an invalid drop has occurred by providing an implementation.
21731              * @param {Event} e The event object
21732              * @param {String} id The id of the dropped element
21733              * @method afterInvalidDrop
21734              */
21735             this.afterInvalidDrop(e, id);
21736         }
21737     },
21738
21739     // private
21740     afterRepair : function(){
21741         if(Roo.enableFx){
21742             this.el.highlight(this.hlColor || "c3daf9");
21743         }
21744         this.dragging = false;
21745     },
21746
21747     /**
21748      * An empty function by default, but provided so that you can perform a custom action after an invalid
21749      * drop has occurred.
21750      * @param {Roo.dd.DragDrop} target The drop target
21751      * @param {Event} e The event object
21752      * @param {String} id The id of the dragged element
21753      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21754      */
21755     beforeInvalidDrop : function(target, e, id){
21756         return true;
21757     },
21758
21759     // private
21760     handleMouseDown : function(e){
21761         if(this.dragging) {
21762             return;
21763         }
21764         var data = this.getDragData(e);
21765         if(data && this.onBeforeDrag(data, e) !== false){
21766             this.dragData = data;
21767             this.proxy.stop();
21768             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21769         } 
21770     },
21771
21772     /**
21773      * An empty function by default, but provided so that you can perform a custom action before the initial
21774      * drag event begins and optionally cancel it.
21775      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21776      * @param {Event} e The event object
21777      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21778      */
21779     onBeforeDrag : function(data, e){
21780         return true;
21781     },
21782
21783     /**
21784      * An empty function by default, but provided so that you can perform a custom action once the initial
21785      * drag event has begun.  The drag cannot be canceled from this function.
21786      * @param {Number} x The x position of the click on the dragged object
21787      * @param {Number} y The y position of the click on the dragged object
21788      */
21789     onStartDrag : Roo.emptyFn,
21790
21791     // private - YUI override
21792     startDrag : function(x, y){
21793         this.proxy.reset();
21794         this.dragging = true;
21795         this.proxy.update("");
21796         this.onInitDrag(x, y);
21797         this.proxy.show();
21798     },
21799
21800     // private
21801     onInitDrag : function(x, y){
21802         var clone = this.el.dom.cloneNode(true);
21803         clone.id = Roo.id(); // prevent duplicate ids
21804         this.proxy.update(clone);
21805         this.onStartDrag(x, y);
21806         return true;
21807     },
21808
21809     /**
21810      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21811      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21812      */
21813     getProxy : function(){
21814         return this.proxy;  
21815     },
21816
21817     /**
21818      * Hides the drag source's {@link Roo.dd.StatusProxy}
21819      */
21820     hideProxy : function(){
21821         this.proxy.hide();  
21822         this.proxy.reset(true);
21823         this.dragging = false;
21824     },
21825
21826     // private
21827     triggerCacheRefresh : function(){
21828         Roo.dd.DDM.refreshCache(this.groups);
21829     },
21830
21831     // private - override to prevent hiding
21832     b4EndDrag: function(e) {
21833     },
21834
21835     // private - override to prevent moving
21836     endDrag : function(e){
21837         this.onEndDrag(this.dragData, e);
21838     },
21839
21840     // private
21841     onEndDrag : function(data, e){
21842     },
21843     
21844     // private - pin to cursor
21845     autoOffset : function(x, y) {
21846         this.setDelta(-12, -20);
21847     }    
21848 });/*
21849  * Based on:
21850  * Ext JS Library 1.1.1
21851  * Copyright(c) 2006-2007, Ext JS, LLC.
21852  *
21853  * Originally Released Under LGPL - original licence link has changed is not relivant.
21854  *
21855  * Fork - LGPL
21856  * <script type="text/javascript">
21857  */
21858
21859
21860 /**
21861  * @class Roo.dd.DropTarget
21862  * @extends Roo.dd.DDTarget
21863  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21864  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21865  * @constructor
21866  * @param {String/HTMLElement/Element} el The container element
21867  * @param {Object} config
21868  */
21869 Roo.dd.DropTarget = function(el, config){
21870     this.el = Roo.get(el);
21871     
21872     var listeners = false; ;
21873     if (config && config.listeners) {
21874         listeners= config.listeners;
21875         delete config.listeners;
21876     }
21877     Roo.apply(this, config);
21878     
21879     if(this.containerScroll){
21880         Roo.dd.ScrollManager.register(this.el);
21881     }
21882     this.addEvents( {
21883          /**
21884          * @scope Roo.dd.DropTarget
21885          */
21886          
21887          /**
21888          * @event enter
21889          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21890          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21891          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21892          * 
21893          * IMPORTANT : it should set this.overClass and this.dropAllowed
21894          * 
21895          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21896          * @param {Event} e The event
21897          * @param {Object} data An object containing arbitrary data supplied by the drag source
21898          */
21899         "enter" : true,
21900         
21901          /**
21902          * @event over
21903          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21904          * This method will be called on every mouse movement while the drag source is over the drop target.
21905          * This default implementation simply returns the dropAllowed config value.
21906          * 
21907          * IMPORTANT : it should set this.dropAllowed
21908          * 
21909          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21910          * @param {Event} e The event
21911          * @param {Object} data An object containing arbitrary data supplied by the drag source
21912          
21913          */
21914         "over" : true,
21915         /**
21916          * @event out
21917          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21918          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21919          * overClass (if any) from the drop element.
21920          * 
21921          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21922          * @param {Event} e The event
21923          * @param {Object} data An object containing arbitrary data supplied by the drag source
21924          */
21925          "out" : true,
21926          
21927         /**
21928          * @event drop
21929          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21930          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21931          * implementation that does something to process the drop event and returns true so that the drag source's
21932          * repair action does not run.
21933          * 
21934          * IMPORTANT : it should set this.success
21935          * 
21936          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21937          * @param {Event} e The event
21938          * @param {Object} data An object containing arbitrary data supplied by the drag source
21939         */
21940          "drop" : true
21941     });
21942             
21943      
21944     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21945         this.el.dom, 
21946         this.ddGroup || this.group,
21947         {
21948             isTarget: true,
21949             listeners : listeners || {} 
21950            
21951         
21952         }
21953     );
21954
21955 };
21956
21957 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21958     /**
21959      * @cfg {String} overClass
21960      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21961      */
21962      /**
21963      * @cfg {String} ddGroup
21964      * The drag drop group to handle drop events for
21965      */
21966      
21967     /**
21968      * @cfg {String} dropAllowed
21969      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21970      */
21971     dropAllowed : "x-dd-drop-ok",
21972     /**
21973      * @cfg {String} dropNotAllowed
21974      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21975      */
21976     dropNotAllowed : "x-dd-drop-nodrop",
21977     /**
21978      * @cfg {boolean} success
21979      * set this after drop listener.. 
21980      */
21981     success : false,
21982     /**
21983      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21984      * if the drop point is valid for over/enter..
21985      */
21986     valid : false,
21987     // private
21988     isTarget : true,
21989
21990     // private
21991     isNotifyTarget : true,
21992     
21993     /**
21994      * @hide
21995      */
21996     notifyEnter : function(dd, e, data)
21997     {
21998         this.valid = true;
21999         this.fireEvent('enter', dd, e, data);
22000         if(this.overClass){
22001             this.el.addClass(this.overClass);
22002         }
22003         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22004             this.valid ? this.dropAllowed : this.dropNotAllowed
22005         );
22006     },
22007
22008     /**
22009      * @hide
22010      */
22011     notifyOver : function(dd, e, data)
22012     {
22013         this.valid = true;
22014         this.fireEvent('over', dd, e, data);
22015         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22016             this.valid ? this.dropAllowed : this.dropNotAllowed
22017         );
22018     },
22019
22020     /**
22021      * @hide
22022      */
22023     notifyOut : function(dd, e, data)
22024     {
22025         this.fireEvent('out', dd, e, data);
22026         if(this.overClass){
22027             this.el.removeClass(this.overClass);
22028         }
22029     },
22030
22031     /**
22032      * @hide
22033      */
22034     notifyDrop : function(dd, e, data)
22035     {
22036         this.success = false;
22037         this.fireEvent('drop', dd, e, data);
22038         return this.success;
22039     }
22040 });/*
22041  * Based on:
22042  * Ext JS Library 1.1.1
22043  * Copyright(c) 2006-2007, Ext JS, LLC.
22044  *
22045  * Originally Released Under LGPL - original licence link has changed is not relivant.
22046  *
22047  * Fork - LGPL
22048  * <script type="text/javascript">
22049  */
22050
22051
22052 /**
22053  * @class Roo.dd.DragZone
22054  * @extends Roo.dd.DragSource
22055  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22056  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22057  * @constructor
22058  * @param {String/HTMLElement/Element} el The container element
22059  * @param {Object} config
22060  */
22061 Roo.dd.DragZone = function(el, config){
22062     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22063     if(this.containerScroll){
22064         Roo.dd.ScrollManager.register(this.el);
22065     }
22066 };
22067
22068 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22069     /**
22070      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22071      * for auto scrolling during drag operations.
22072      */
22073     /**
22074      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22075      * method after a failed drop (defaults to "c3daf9" - light blue)
22076      */
22077
22078     /**
22079      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22080      * for a valid target to drag based on the mouse down. Override this method
22081      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22082      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22083      * @param {EventObject} e The mouse down event
22084      * @return {Object} The dragData
22085      */
22086     getDragData : function(e){
22087         return Roo.dd.Registry.getHandleFromEvent(e);
22088     },
22089     
22090     /**
22091      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22092      * this.dragData.ddel
22093      * @param {Number} x The x position of the click on the dragged object
22094      * @param {Number} y The y position of the click on the dragged object
22095      * @return {Boolean} true to continue the drag, false to cancel
22096      */
22097     onInitDrag : function(x, y){
22098         this.proxy.update(this.dragData.ddel.cloneNode(true));
22099         this.onStartDrag(x, y);
22100         return true;
22101     },
22102     
22103     /**
22104      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22105      */
22106     afterRepair : function(){
22107         if(Roo.enableFx){
22108             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22109         }
22110         this.dragging = false;
22111     },
22112
22113     /**
22114      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22115      * the XY of this.dragData.ddel
22116      * @param {EventObject} e The mouse up event
22117      * @return {Array} The xy location (e.g. [100, 200])
22118      */
22119     getRepairXY : function(e){
22120         return Roo.Element.fly(this.dragData.ddel).getXY();  
22121     }
22122 });/*
22123  * Based on:
22124  * Ext JS Library 1.1.1
22125  * Copyright(c) 2006-2007, Ext JS, LLC.
22126  *
22127  * Originally Released Under LGPL - original licence link has changed is not relivant.
22128  *
22129  * Fork - LGPL
22130  * <script type="text/javascript">
22131  */
22132 /**
22133  * @class Roo.dd.DropZone
22134  * @extends Roo.dd.DropTarget
22135  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22136  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22137  * @constructor
22138  * @param {String/HTMLElement/Element} el The container element
22139  * @param {Object} config
22140  */
22141 Roo.dd.DropZone = function(el, config){
22142     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22143 };
22144
22145 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22146     /**
22147      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22148      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22149      * provide your own custom lookup.
22150      * @param {Event} e The event
22151      * @return {Object} data The custom data
22152      */
22153     getTargetFromEvent : function(e){
22154         return Roo.dd.Registry.getTargetFromEvent(e);
22155     },
22156
22157     /**
22158      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22159      * that it has registered.  This method has no default implementation and should be overridden to provide
22160      * node-specific processing if necessary.
22161      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22162      * {@link #getTargetFromEvent} for this node)
22163      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22164      * @param {Event} e The event
22165      * @param {Object} data An object containing arbitrary data supplied by the drag source
22166      */
22167     onNodeEnter : function(n, dd, e, data){
22168         
22169     },
22170
22171     /**
22172      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22173      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22174      * overridden to provide the proper feedback.
22175      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22176      * {@link #getTargetFromEvent} for this node)
22177      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22178      * @param {Event} e The event
22179      * @param {Object} data An object containing arbitrary data supplied by the drag source
22180      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22181      * underlying {@link Roo.dd.StatusProxy} can be updated
22182      */
22183     onNodeOver : function(n, dd, e, data){
22184         return this.dropAllowed;
22185     },
22186
22187     /**
22188      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22189      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22190      * node-specific processing if necessary.
22191      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22192      * {@link #getTargetFromEvent} for this node)
22193      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22194      * @param {Event} e The event
22195      * @param {Object} data An object containing arbitrary data supplied by the drag source
22196      */
22197     onNodeOut : function(n, dd, e, data){
22198         
22199     },
22200
22201     /**
22202      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22203      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22204      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22205      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22206      * {@link #getTargetFromEvent} for this node)
22207      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22208      * @param {Event} e The event
22209      * @param {Object} data An object containing arbitrary data supplied by the drag source
22210      * @return {Boolean} True if the drop was valid, else false
22211      */
22212     onNodeDrop : function(n, dd, e, data){
22213         return false;
22214     },
22215
22216     /**
22217      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22218      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22219      * it should be overridden to provide the proper feedback if necessary.
22220      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22221      * @param {Event} e The event
22222      * @param {Object} data An object containing arbitrary data supplied by the drag source
22223      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22224      * underlying {@link Roo.dd.StatusProxy} can be updated
22225      */
22226     onContainerOver : function(dd, e, data){
22227         return this.dropNotAllowed;
22228     },
22229
22230     /**
22231      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22232      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22233      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22234      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22235      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22236      * @param {Event} e The event
22237      * @param {Object} data An object containing arbitrary data supplied by the drag source
22238      * @return {Boolean} True if the drop was valid, else false
22239      */
22240     onContainerDrop : function(dd, e, data){
22241         return false;
22242     },
22243
22244     /**
22245      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22246      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22247      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22248      * you should override this method and provide a custom implementation.
22249      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22250      * @param {Event} e The event
22251      * @param {Object} data An object containing arbitrary data supplied by the drag source
22252      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22253      * underlying {@link Roo.dd.StatusProxy} can be updated
22254      */
22255     notifyEnter : function(dd, e, data){
22256         return this.dropNotAllowed;
22257     },
22258
22259     /**
22260      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22261      * This method will be called on every mouse movement while the drag source is over the drop zone.
22262      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22263      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22264      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22265      * registered node, it will call {@link #onContainerOver}.
22266      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22267      * @param {Event} e The event
22268      * @param {Object} data An object containing arbitrary data supplied by the drag source
22269      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22270      * underlying {@link Roo.dd.StatusProxy} can be updated
22271      */
22272     notifyOver : function(dd, e, data){
22273         var n = this.getTargetFromEvent(e);
22274         if(!n){ // not over valid drop target
22275             if(this.lastOverNode){
22276                 this.onNodeOut(this.lastOverNode, dd, e, data);
22277                 this.lastOverNode = null;
22278             }
22279             return this.onContainerOver(dd, e, data);
22280         }
22281         if(this.lastOverNode != n){
22282             if(this.lastOverNode){
22283                 this.onNodeOut(this.lastOverNode, dd, e, data);
22284             }
22285             this.onNodeEnter(n, dd, e, data);
22286             this.lastOverNode = n;
22287         }
22288         return this.onNodeOver(n, dd, e, data);
22289     },
22290
22291     /**
22292      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22293      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22294      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22295      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22296      * @param {Event} e The event
22297      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22298      */
22299     notifyOut : function(dd, e, data){
22300         if(this.lastOverNode){
22301             this.onNodeOut(this.lastOverNode, dd, e, data);
22302             this.lastOverNode = null;
22303         }
22304     },
22305
22306     /**
22307      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22308      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22309      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22310      * otherwise it will call {@link #onContainerDrop}.
22311      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22312      * @param {Event} e The event
22313      * @param {Object} data An object containing arbitrary data supplied by the drag source
22314      * @return {Boolean} True if the drop was valid, else false
22315      */
22316     notifyDrop : function(dd, e, data){
22317         if(this.lastOverNode){
22318             this.onNodeOut(this.lastOverNode, dd, e, data);
22319             this.lastOverNode = null;
22320         }
22321         var n = this.getTargetFromEvent(e);
22322         return n ?
22323             this.onNodeDrop(n, dd, e, data) :
22324             this.onContainerDrop(dd, e, data);
22325     },
22326
22327     // private
22328     triggerCacheRefresh : function(){
22329         Roo.dd.DDM.refreshCache(this.groups);
22330     }  
22331 });