sync
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @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         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         }
672         
673     });
674
675
676 })();
677
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
680                 "Roo.app", "Roo.ux",
681                 "Roo.bootstrap",
682                 "Roo.bootstrap.dash");
683 /*
684  * Based on:
685  * Ext JS Library 1.1.1
686  * Copyright(c) 2006-2007, Ext JS, LLC.
687  *
688  * Originally Released Under LGPL - original licence link has changed is not relivant.
689  *
690  * Fork - LGPL
691  * <script type="text/javascript">
692  */
693
694 (function() {    
695     // wrappedn so fnCleanup is not in global scope...
696     if(Roo.isIE) {
697         function fnCleanUp() {
698             var p = Function.prototype;
699             delete p.createSequence;
700             delete p.defer;
701             delete p.createDelegate;
702             delete p.createCallback;
703             delete p.createInterceptor;
704
705             window.detachEvent("onunload", fnCleanUp);
706         }
707         window.attachEvent("onunload", fnCleanUp);
708     }
709 })();
710
711
712 /**
713  * @class Function
714  * These functions are available on every Function object (any JavaScript function).
715  */
716 Roo.apply(Function.prototype, {
717      /**
718      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720      * Will create a function that is bound to those 2 args.
721      * @return {Function} The new function
722     */
723     createCallback : function(/*args...*/){
724         // make args available, in function below
725         var args = arguments;
726         var method = this;
727         return function() {
728             return method.apply(window, args);
729         };
730     },
731
732     /**
733      * Creates a delegate (callback) that sets the scope to obj.
734      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735      * Will create a function that is automatically scoped to this.
736      * @param {Object} obj (optional) The object for which the scope is set
737      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739      *                                             if a number the args are inserted at the specified position
740      * @return {Function} The new function
741      */
742     createDelegate : function(obj, args, appendArgs){
743         var method = this;
744         return function() {
745             var callArgs = args || arguments;
746             if(appendArgs === true){
747                 callArgs = Array.prototype.slice.call(arguments, 0);
748                 callArgs = callArgs.concat(args);
749             }else if(typeof appendArgs == "number"){
750                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
753             }
754             return method.apply(obj || window, callArgs);
755         };
756     },
757
758     /**
759      * Calls this function after the number of millseconds specified.
760      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761      * @param {Object} obj (optional) The object for which the scope is set
762      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764      *                                             if a number the args are inserted at the specified position
765      * @return {Number} The timeout id that can be used with clearTimeout
766      */
767     defer : function(millis, obj, args, appendArgs){
768         var fn = this.createDelegate(obj, args, appendArgs);
769         if(millis){
770             return setTimeout(fn, millis);
771         }
772         fn();
773         return 0;
774     },
775     /**
776      * Create a combined function call sequence of the original function + the passed function.
777      * The resulting function returns the results of the original function.
778      * The passed fcn is called with the parameters of the original function
779      * @param {Function} fcn The function to sequence
780      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781      * @return {Function} The new function
782      */
783     createSequence : function(fcn, scope){
784         if(typeof fcn != "function"){
785             return this;
786         }
787         var method = this;
788         return function() {
789             var retval = method.apply(this || window, arguments);
790             fcn.apply(scope || this || window, arguments);
791             return retval;
792         };
793     },
794
795     /**
796      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797      * The resulting function returns the results of the original function.
798      * The passed fcn is called with the parameters of the original function.
799      * @addon
800      * @param {Function} fcn The function to call before the original
801      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802      * @return {Function} The new function
803      */
804     createInterceptor : function(fcn, scope){
805         if(typeof fcn != "function"){
806             return this;
807         }
808         var method = this;
809         return function() {
810             fcn.target = this;
811             fcn.method = method;
812             if(fcn.apply(scope || this || window, arguments) === false){
813                 return;
814             }
815             return method.apply(this || window, arguments);
816         };
817     }
818 });
819 /*
820  * Based on:
821  * Ext JS Library 1.1.1
822  * Copyright(c) 2006-2007, Ext JS, LLC.
823  *
824  * Originally Released Under LGPL - original licence link has changed is not relivant.
825  *
826  * Fork - LGPL
827  * <script type="text/javascript">
828  */
829
830 Roo.applyIf(String, {
831     
832     /** @scope String */
833     
834     /**
835      * Escapes the passed string for ' and \
836      * @param {String} string The string to escape
837      * @return {String} The escaped string
838      * @static
839      */
840     escape : function(string) {
841         return string.replace(/('|\\)/g, "\\$1");
842     },
843
844     /**
845      * Pads the left side of a string with a specified character.  This is especially useful
846      * for normalizing number and date strings.  Example usage:
847      * <pre><code>
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
850 </code></pre>
851      * @param {String} string The original string
852      * @param {Number} size The total length of the output string
853      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854      * @return {String} The padded string
855      * @static
856      */
857     leftPad : function (val, size, ch) {
858         var result = new String(val);
859         if(ch === null || ch === undefined || ch === '') {
860             ch = " ";
861         }
862         while (result.length < size) {
863             result = ch + result;
864         }
865         return result;
866     },
867
868     /**
869      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
870      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
871      * <pre><code>
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
875 </code></pre>
876      * @param {String} string The tokenized string to be formatted
877      * @param {String} value1 The value to replace token {0}
878      * @param {String} value2 Etc...
879      * @return {String} The formatted string
880      * @static
881      */
882     format : function(format){
883         var args = Array.prototype.slice.call(arguments, 1);
884         return format.replace(/\{(\d+)\}/g, function(m, i){
885             return Roo.util.Format.htmlEncode(args[i]);
886         });
887     }
888 });
889
890 /**
891  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
892  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
893  * they are already different, the first value passed in is returned.  Note that this method returns the new value
894  * but does not change the current string.
895  * <pre><code>
896 // alternate sort directions
897 sort = sort.toggle('ASC', 'DESC');
898
899 // instead of conditional logic:
900 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
901 </code></pre>
902  * @param {String} value The value to compare to the current string
903  * @param {String} other The new value to use if the string already equals the first value passed in
904  * @return {String} The new value
905  */
906  
907 String.prototype.toggle = function(value, other){
908     return this == value ? other : value;
909 };/*
910  * Based on:
911  * Ext JS Library 1.1.1
912  * Copyright(c) 2006-2007, Ext JS, LLC.
913  *
914  * Originally Released Under LGPL - original licence link has changed is not relivant.
915  *
916  * Fork - LGPL
917  * <script type="text/javascript">
918  */
919
920  /**
921  * @class Number
922  */
923 Roo.applyIf(Number.prototype, {
924     /**
925      * Checks whether or not the current number is within a desired range.  If the number is already within the
926      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
927      * exceeded.  Note that this method returns the constrained value but does not change the current number.
928      * @param {Number} min The minimum number in the range
929      * @param {Number} max The maximum number in the range
930      * @return {Number} The constrained value if outside the range, otherwise the current value
931      */
932     constrain : function(min, max){
933         return Math.min(Math.max(this, min), max);
934     }
935 });/*
936  * Based on:
937  * Ext JS Library 1.1.1
938  * Copyright(c) 2006-2007, Ext JS, LLC.
939  *
940  * Originally Released Under LGPL - original licence link has changed is not relivant.
941  *
942  * Fork - LGPL
943  * <script type="text/javascript">
944  */
945  /**
946  * @class Array
947  */
948 Roo.applyIf(Array.prototype, {
949     /**
950      * 
951      * Checks whether or not the specified object exists in the array.
952      * @param {Object} o The object to check for
953      * @return {Number} The index of o in the array (or -1 if it is not found)
954      */
955     indexOf : function(o){
956        for (var i = 0, len = this.length; i < len; i++){
957               if(this[i] == o) { return i; }
958        }
959            return -1;
960     },
961
962     /**
963      * Removes the specified object from the array.  If the object is not found nothing happens.
964      * @param {Object} o The object to remove
965      */
966     remove : function(o){
967        var index = this.indexOf(o);
968        if(index != -1){
969            this.splice(index, 1);
970        }
971     },
972     /**
973      * Map (JS 1.6 compatibility)
974      * @param {Function} function  to call
975      */
976     map : function(fun )
977     {
978         var len = this.length >>> 0;
979         if (typeof fun != "function") {
980             throw new TypeError();
981         }
982         var res = new Array(len);
983         var thisp = arguments[1];
984         for (var i = 0; i < len; i++)
985         {
986             if (i in this) {
987                 res[i] = fun.call(thisp, this[i], i, this);
988             }
989         }
990
991         return res;
992     }
993     
994 });
995
996
997  
998 /*
999  * Based on:
1000  * Ext JS Library 1.1.1
1001  * Copyright(c) 2006-2007, Ext JS, LLC.
1002  *
1003  * Originally Released Under LGPL - original licence link has changed is not relivant.
1004  *
1005  * Fork - LGPL
1006  * <script type="text/javascript">
1007  */
1008
1009 /**
1010  * @class Date
1011  *
1012  * The date parsing and format syntax is a subset of
1013  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1014  * supported will provide results equivalent to their PHP versions.
1015  *
1016  * Following is the list of all currently supported formats:
1017  *<pre>
1018 Sample date:
1019 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1020
1021 Format  Output      Description
1022 ------  ----------  --------------------------------------------------------------
1023   d      10         Day of the month, 2 digits with leading zeros
1024   D      Wed        A textual representation of a day, three letters
1025   j      10         Day of the month without leading zeros
1026   l      Wednesday  A full textual representation of the day of the week
1027   S      th         English ordinal day of month suffix, 2 chars (use with j)
1028   w      3          Numeric representation of the day of the week
1029   z      9          The julian date, or day of the year (0-365)
1030   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1031   F      January    A full textual representation of the month
1032   m      01         Numeric representation of a month, with leading zeros
1033   M      Jan        Month name abbreviation, three letters
1034   n      1          Numeric representation of a month, without leading zeros
1035   t      31         Number of days in the given month
1036   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1037   Y      2007       A full numeric representation of a year, 4 digits
1038   y      07         A two digit representation of a year
1039   a      pm         Lowercase Ante meridiem and Post meridiem
1040   A      PM         Uppercase Ante meridiem and Post meridiem
1041   g      3          12-hour format of an hour without leading zeros
1042   G      15         24-hour format of an hour without leading zeros
1043   h      03         12-hour format of an hour with leading zeros
1044   H      15         24-hour format of an hour with leading zeros
1045   i      05         Minutes with leading zeros
1046   s      01         Seconds, with leading zeros
1047   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1048   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1049   T      CST        Timezone setting of the machine running the code
1050   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1051 </pre>
1052  *
1053  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1054  * <pre><code>
1055 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1056 document.write(dt.format('Y-m-d'));                         //2007-01-10
1057 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1058 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
1059  </code></pre>
1060  *
1061  * Here are some standard date/time patterns that you might find helpful.  They
1062  * are not part of the source of Date.js, but to use them you can simply copy this
1063  * block of code into any script that is included after Date.js and they will also become
1064  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1065  * <pre><code>
1066 Date.patterns = {
1067     ISO8601Long:"Y-m-d H:i:s",
1068     ISO8601Short:"Y-m-d",
1069     ShortDate: "n/j/Y",
1070     LongDate: "l, F d, Y",
1071     FullDateTime: "l, F d, Y g:i:s A",
1072     MonthDay: "F d",
1073     ShortTime: "g:i A",
1074     LongTime: "g:i:s A",
1075     SortableDateTime: "Y-m-d\\TH:i:s",
1076     UniversalSortableDateTime: "Y-m-d H:i:sO",
1077     YearMonth: "F, Y"
1078 };
1079 </code></pre>
1080  *
1081  * Example usage:
1082  * <pre><code>
1083 var dt = new Date();
1084 document.write(dt.format(Date.patterns.ShortDate));
1085  </code></pre>
1086  */
1087
1088 /*
1089  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1090  * They generate precompiled functions from date formats instead of parsing and
1091  * processing the pattern every time you format a date.  These functions are available
1092  * on every Date object (any javascript function).
1093  *
1094  * The original article and download are here:
1095  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096  *
1097  */
1098  
1099  
1100  // was in core
1101 /**
1102  Returns the number of milliseconds between this date and date
1103  @param {Date} date (optional) Defaults to now
1104  @return {Number} The diff in milliseconds
1105  @member Date getElapsed
1106  */
1107 Date.prototype.getElapsed = function(date) {
1108         return Math.abs((date || new Date()).getTime()-this.getTime());
1109 };
1110 // was in date file..
1111
1112
1113 // private
1114 Date.parseFunctions = {count:0};
1115 // private
1116 Date.parseRegexes = [];
1117 // private
1118 Date.formatFunctions = {count:0};
1119
1120 // private
1121 Date.prototype.dateFormat = function(format) {
1122     if (Date.formatFunctions[format] == null) {
1123         Date.createNewFormat(format);
1124     }
1125     var func = Date.formatFunctions[format];
1126     return this[func]();
1127 };
1128
1129
1130 /**
1131  * Formats a date given the supplied format string
1132  * @param {String} format The format string
1133  * @return {String} The formatted date
1134  * @method
1135  */
1136 Date.prototype.format = Date.prototype.dateFormat;
1137
1138 // private
1139 Date.createNewFormat = function(format) {
1140     var funcName = "format" + Date.formatFunctions.count++;
1141     Date.formatFunctions[format] = funcName;
1142     var code = "Date.prototype." + funcName + " = function(){return ";
1143     var special = false;
1144     var ch = '';
1145     for (var i = 0; i < format.length; ++i) {
1146         ch = format.charAt(i);
1147         if (!special && ch == "\\") {
1148             special = true;
1149         }
1150         else if (special) {
1151             special = false;
1152             code += "'" + String.escape(ch) + "' + ";
1153         }
1154         else {
1155             code += Date.getFormatCode(ch);
1156         }
1157     }
1158     /** eval:var:zzzzzzzzzzzzz */
1159     eval(code.substring(0, code.length - 3) + ";}");
1160 };
1161
1162 // private
1163 Date.getFormatCode = function(character) {
1164     switch (character) {
1165     case "d":
1166         return "String.leftPad(this.getDate(), 2, '0') + ";
1167     case "D":
1168         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1169     case "j":
1170         return "this.getDate() + ";
1171     case "l":
1172         return "Date.dayNames[this.getDay()] + ";
1173     case "S":
1174         return "this.getSuffix() + ";
1175     case "w":
1176         return "this.getDay() + ";
1177     case "z":
1178         return "this.getDayOfYear() + ";
1179     case "W":
1180         return "this.getWeekOfYear() + ";
1181     case "F":
1182         return "Date.monthNames[this.getMonth()] + ";
1183     case "m":
1184         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1185     case "M":
1186         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1187     case "n":
1188         return "(this.getMonth() + 1) + ";
1189     case "t":
1190         return "this.getDaysInMonth() + ";
1191     case "L":
1192         return "(this.isLeapYear() ? 1 : 0) + ";
1193     case "Y":
1194         return "this.getFullYear() + ";
1195     case "y":
1196         return "('' + this.getFullYear()).substring(2, 4) + ";
1197     case "a":
1198         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1199     case "A":
1200         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1201     case "g":
1202         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1203     case "G":
1204         return "this.getHours() + ";
1205     case "h":
1206         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1207     case "H":
1208         return "String.leftPad(this.getHours(), 2, '0') + ";
1209     case "i":
1210         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1211     case "s":
1212         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1213     case "O":
1214         return "this.getGMTOffset() + ";
1215     case "P":
1216         return "this.getGMTColonOffset() + ";
1217     case "T":
1218         return "this.getTimezone() + ";
1219     case "Z":
1220         return "(this.getTimezoneOffset() * -60) + ";
1221     default:
1222         return "'" + String.escape(character) + "' + ";
1223     }
1224 };
1225
1226 /**
1227  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1228  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1229  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1230  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1231  * string or the parse operation will fail.
1232  * Example Usage:
1233 <pre><code>
1234 //dt = Fri May 25 2007 (current date)
1235 var dt = new Date();
1236
1237 //dt = Thu May 25 2006 (today's month/day in 2006)
1238 dt = Date.parseDate("2006", "Y");
1239
1240 //dt = Sun Jan 15 2006 (all date parts specified)
1241 dt = Date.parseDate("2006-1-15", "Y-m-d");
1242
1243 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1244 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1245 </code></pre>
1246  * @param {String} input The unparsed date as a string
1247  * @param {String} format The format the date is in
1248  * @return {Date} The parsed date
1249  * @static
1250  */
1251 Date.parseDate = function(input, format) {
1252     if (Date.parseFunctions[format] == null) {
1253         Date.createParser(format);
1254     }
1255     var func = Date.parseFunctions[format];
1256     return Date[func](input);
1257 };
1258 /**
1259  * @private
1260  */
1261
1262 Date.createParser = function(format) {
1263     var funcName = "parse" + Date.parseFunctions.count++;
1264     var regexNum = Date.parseRegexes.length;
1265     var currentGroup = 1;
1266     Date.parseFunctions[format] = funcName;
1267
1268     var code = "Date." + funcName + " = function(input){\n"
1269         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1270         + "var d = new Date();\n"
1271         + "y = d.getFullYear();\n"
1272         + "m = d.getMonth();\n"
1273         + "d = d.getDate();\n"
1274         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1275         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1276         + "if (results && results.length > 0) {";
1277     var regex = "";
1278
1279     var special = false;
1280     var ch = '';
1281     for (var i = 0; i < format.length; ++i) {
1282         ch = format.charAt(i);
1283         if (!special && ch == "\\") {
1284             special = true;
1285         }
1286         else if (special) {
1287             special = false;
1288             regex += String.escape(ch);
1289         }
1290         else {
1291             var obj = Date.formatCodeToRegex(ch, currentGroup);
1292             currentGroup += obj.g;
1293             regex += obj.s;
1294             if (obj.g && obj.c) {
1295                 code += obj.c;
1296             }
1297         }
1298     }
1299
1300     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1301         + "{v = new Date(y, m, d, h, i, s);}\n"
1302         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1303         + "{v = new Date(y, m, d, h, i);}\n"
1304         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1305         + "{v = new Date(y, m, d, h);}\n"
1306         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1307         + "{v = new Date(y, m, d);}\n"
1308         + "else if (y >= 0 && m >= 0)\n"
1309         + "{v = new Date(y, m);}\n"
1310         + "else if (y >= 0)\n"
1311         + "{v = new Date(y);}\n"
1312         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1313         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1314         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1315         + ";}";
1316
1317     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1318     /** eval:var:zzzzzzzzzzzzz */
1319     eval(code);
1320 };
1321
1322 // private
1323 Date.formatCodeToRegex = function(character, currentGroup) {
1324     switch (character) {
1325     case "D":
1326         return {g:0,
1327         c:null,
1328         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1329     case "j":
1330         return {g:1,
1331             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1332             s:"(\\d{1,2})"}; // day of month without leading zeroes
1333     case "d":
1334         return {g:1,
1335             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1336             s:"(\\d{2})"}; // day of month with leading zeroes
1337     case "l":
1338         return {g:0,
1339             c:null,
1340             s:"(?:" + Date.dayNames.join("|") + ")"};
1341     case "S":
1342         return {g:0,
1343             c:null,
1344             s:"(?:st|nd|rd|th)"};
1345     case "w":
1346         return {g:0,
1347             c:null,
1348             s:"\\d"};
1349     case "z":
1350         return {g:0,
1351             c:null,
1352             s:"(?:\\d{1,3})"};
1353     case "W":
1354         return {g:0,
1355             c:null,
1356             s:"(?:\\d{2})"};
1357     case "F":
1358         return {g:1,
1359             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1360             s:"(" + Date.monthNames.join("|") + ")"};
1361     case "M":
1362         return {g:1,
1363             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1364             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1365     case "n":
1366         return {g:1,
1367             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1368             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1369     case "m":
1370         return {g:1,
1371             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1372             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1373     case "t":
1374         return {g:0,
1375             c:null,
1376             s:"\\d{1,2}"};
1377     case "L":
1378         return {g:0,
1379             c:null,
1380             s:"(?:1|0)"};
1381     case "Y":
1382         return {g:1,
1383             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{4})"};
1385     case "y":
1386         return {g:1,
1387             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1388                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1389             s:"(\\d{1,2})"};
1390     case "a":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'am') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(am|pm)"};
1396     case "A":
1397         return {g:1,
1398             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1399                 + "if (h == 12) { h = 0; }\n"
1400                 + "} else { if (h < 12) { h += 12; }}",
1401             s:"(AM|PM)"};
1402     case "g":
1403     case "G":
1404         return {g:1,
1405             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1406             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1407     case "h":
1408     case "H":
1409         return {g:1,
1410             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1411             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1412     case "i":
1413         return {g:1,
1414             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1415             s:"(\\d{2})"};
1416     case "s":
1417         return {g:1,
1418             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1419             s:"(\\d{2})"};
1420     case "O":
1421         return {g:1,
1422             c:[
1423                 "o = results[", currentGroup, "];\n",
1424                 "var sn = o.substring(0,1);\n", // get + / - sign
1425                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1426                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1427                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1428                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429             ].join(""),
1430             s:"([+\-]\\d{2,4})"};
1431     
1432     
1433     case "P":
1434         return {g:1,
1435                 c:[
1436                    "o = results[", currentGroup, "];\n",
1437                    "var sn = o.substring(0,1);\n",
1438                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1439                    "var mn = o.substring(4,6) % 60;\n",
1440                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1441                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1442             ].join(""),
1443             s:"([+\-]\\d{4})"};
1444     case "T":
1445         return {g:0,
1446             c:null,
1447             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1448     case "Z":
1449         return {g:1,
1450             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1451                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1452             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1453     default:
1454         return {g:0,
1455             c:null,
1456             s:String.escape(character)};
1457     }
1458 };
1459
1460 /**
1461  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1462  * @return {String} The abbreviated timezone name (e.g. 'CST')
1463  */
1464 Date.prototype.getTimezone = function() {
1465     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1466 };
1467
1468 /**
1469  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1470  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1471  */
1472 Date.prototype.getGMTOffset = function() {
1473     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1474         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1475         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1476 };
1477
1478 /**
1479  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1480  * @return {String} 2-characters representing hours and 2-characters representing minutes
1481  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1482  */
1483 Date.prototype.getGMTColonOffset = function() {
1484         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1485                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1486                 + ":"
1487                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1488 }
1489
1490 /**
1491  * Get the numeric day number of the year, adjusted for leap year.
1492  * @return {Number} 0 through 364 (365 in leap years)
1493  */
1494 Date.prototype.getDayOfYear = function() {
1495     var num = 0;
1496     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1497     for (var i = 0; i < this.getMonth(); ++i) {
1498         num += Date.daysInMonth[i];
1499     }
1500     return num + this.getDate() - 1;
1501 };
1502
1503 /**
1504  * Get the string representation of the numeric week number of the year
1505  * (equivalent to the format specifier 'W').
1506  * @return {String} '00' through '52'
1507  */
1508 Date.prototype.getWeekOfYear = function() {
1509     // Skip to Thursday of this week
1510     var now = this.getDayOfYear() + (4 - this.getDay());
1511     // Find the first Thursday of the year
1512     var jan1 = new Date(this.getFullYear(), 0, 1);
1513     var then = (7 - jan1.getDay() + 4);
1514     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1515 };
1516
1517 /**
1518  * Whether or not the current date is in a leap year.
1519  * @return {Boolean} True if the current date is in a leap year, else false
1520  */
1521 Date.prototype.isLeapYear = function() {
1522     var year = this.getFullYear();
1523     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1524 };
1525
1526 /**
1527  * Get the first day of the current month, adjusted for leap year.  The returned value
1528  * is the numeric day index within the week (0-6) which can be used in conjunction with
1529  * the {@link #monthNames} array to retrieve the textual day name.
1530  * Example:
1531  *<pre><code>
1532 var dt = new Date('1/10/2007');
1533 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1534 </code></pre>
1535  * @return {Number} The day number (0-6)
1536  */
1537 Date.prototype.getFirstDayOfMonth = function() {
1538     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1539     return (day < 0) ? (day + 7) : day;
1540 };
1541
1542 /**
1543  * Get the last day of the current month, adjusted for leap year.  The returned value
1544  * is the numeric day index within the week (0-6) which can be used in conjunction with
1545  * the {@link #monthNames} array to retrieve the textual day name.
1546  * Example:
1547  *<pre><code>
1548 var dt = new Date('1/10/2007');
1549 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1550 </code></pre>
1551  * @return {Number} The day number (0-6)
1552  */
1553 Date.prototype.getLastDayOfMonth = function() {
1554     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1555     return (day < 0) ? (day + 7) : day;
1556 };
1557
1558
1559 /**
1560  * Get the first date of this date's month
1561  * @return {Date}
1562  */
1563 Date.prototype.getFirstDateOfMonth = function() {
1564     return new Date(this.getFullYear(), this.getMonth(), 1);
1565 };
1566
1567 /**
1568  * Get the last date of this date's month
1569  * @return {Date}
1570  */
1571 Date.prototype.getLastDateOfMonth = function() {
1572     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1573 };
1574 /**
1575  * Get the number of days in the current month, adjusted for leap year.
1576  * @return {Number} The number of days in the month
1577  */
1578 Date.prototype.getDaysInMonth = function() {
1579     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1580     return Date.daysInMonth[this.getMonth()];
1581 };
1582
1583 /**
1584  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1585  * @return {String} 'st, 'nd', 'rd' or 'th'
1586  */
1587 Date.prototype.getSuffix = function() {
1588     switch (this.getDate()) {
1589         case 1:
1590         case 21:
1591         case 31:
1592             return "st";
1593         case 2:
1594         case 22:
1595             return "nd";
1596         case 3:
1597         case 23:
1598             return "rd";
1599         default:
1600             return "th";
1601     }
1602 };
1603
1604 // private
1605 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1606
1607 /**
1608  * An array of textual month names.
1609  * Override these values for international dates, for example...
1610  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611  * @type Array
1612  * @static
1613  */
1614 Date.monthNames =
1615    ["January",
1616     "February",
1617     "March",
1618     "April",
1619     "May",
1620     "June",
1621     "July",
1622     "August",
1623     "September",
1624     "October",
1625     "November",
1626     "December"];
1627
1628 /**
1629  * An array of textual day names.
1630  * Override these values for international dates, for example...
1631  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632  * @type Array
1633  * @static
1634  */
1635 Date.dayNames =
1636    ["Sunday",
1637     "Monday",
1638     "Tuesday",
1639     "Wednesday",
1640     "Thursday",
1641     "Friday",
1642     "Saturday"];
1643
1644 // private
1645 Date.y2kYear = 50;
1646 // private
1647 Date.monthNumbers = {
1648     Jan:0,
1649     Feb:1,
1650     Mar:2,
1651     Apr:3,
1652     May:4,
1653     Jun:5,
1654     Jul:6,
1655     Aug:7,
1656     Sep:8,
1657     Oct:9,
1658     Nov:10,
1659     Dec:11};
1660
1661 /**
1662  * Creates and returns a new Date instance with the exact same date value as the called instance.
1663  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1664  * variable will also be changed.  When the intention is to create a new variable that will not
1665  * modify the original instance, you should create a clone.
1666  *
1667  * Example of correctly cloning a date:
1668  * <pre><code>
1669 //wrong way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig;
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 05 2006'!
1674
1675 //correct way:
1676 var orig = new Date('10/1/2006');
1677 var copy = orig.clone();
1678 copy.setDate(5);
1679 document.write(orig);  //returns 'Thu Oct 01 2006'
1680 </code></pre>
1681  * @return {Date} The new Date instance
1682  */
1683 Date.prototype.clone = function() {
1684         return new Date(this.getTime());
1685 };
1686
1687 /**
1688  * Clears any time information from this date
1689  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1690  @return {Date} this or the clone
1691  */
1692 Date.prototype.clearTime = function(clone){
1693     if(clone){
1694         return this.clone().clearTime();
1695     }
1696     this.setHours(0);
1697     this.setMinutes(0);
1698     this.setSeconds(0);
1699     this.setMilliseconds(0);
1700     return this;
1701 };
1702
1703 // private
1704 // safari setMonth is broken -- check that this is only donw once...
1705 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1706     Date.brokenSetMonth = Date.prototype.setMonth;
1707         Date.prototype.setMonth = function(num){
1708                 if(num <= -1){
1709                         var n = Math.ceil(-num);
1710                         var back_year = Math.ceil(n/12);
1711                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1712                         this.setFullYear(this.getFullYear() - back_year);
1713                         return Date.brokenSetMonth.call(this, month);
1714                 } else {
1715                         return Date.brokenSetMonth.apply(this, arguments);
1716                 }
1717         };
1718 }
1719
1720 /** Date interval constant 
1721 * @static 
1722 * @type String */
1723 Date.MILLI = "ms";
1724 /** Date interval constant 
1725 * @static 
1726 * @type String */
1727 Date.SECOND = "s";
1728 /** Date interval constant 
1729 * @static 
1730 * @type String */
1731 Date.MINUTE = "mi";
1732 /** Date interval constant 
1733 * @static 
1734 * @type String */
1735 Date.HOUR = "h";
1736 /** Date interval constant 
1737 * @static 
1738 * @type String */
1739 Date.DAY = "d";
1740 /** Date interval constant 
1741 * @static 
1742 * @type String */
1743 Date.MONTH = "mo";
1744 /** Date interval constant 
1745 * @static 
1746 * @type String */
1747 Date.YEAR = "y";
1748
1749 /**
1750  * Provides a convenient method of performing basic date arithmetic.  This method
1751  * does not modify the Date instance being called - it creates and returns
1752  * a new Date instance containing the resulting date value.
1753  *
1754  * Examples:
1755  * <pre><code>
1756 //Basic usage:
1757 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1758 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1759
1760 //Negative values will subtract correctly:
1761 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1762 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1763
1764 //You can even chain several calls together in one line!
1765 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1766 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1767  </code></pre>
1768  *
1769  * @param {String} interval   A valid date interval enum value
1770  * @param {Number} value      The amount to add to the current date
1771  * @return {Date} The new Date instance
1772  */
1773 Date.prototype.add = function(interval, value){
1774   var d = this.clone();
1775   if (!interval || value === 0) { return d; }
1776   switch(interval.toLowerCase()){
1777     case Date.MILLI:
1778       d.setMilliseconds(this.getMilliseconds() + value);
1779       break;
1780     case Date.SECOND:
1781       d.setSeconds(this.getSeconds() + value);
1782       break;
1783     case Date.MINUTE:
1784       d.setMinutes(this.getMinutes() + value);
1785       break;
1786     case Date.HOUR:
1787       d.setHours(this.getHours() + value);
1788       break;
1789     case Date.DAY:
1790       d.setDate(this.getDate() + value);
1791       break;
1792     case Date.MONTH:
1793       var day = this.getDate();
1794       if(day > 28){
1795           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1796       }
1797       d.setDate(day);
1798       d.setMonth(this.getMonth() + value);
1799       break;
1800     case Date.YEAR:
1801       d.setFullYear(this.getFullYear() + value);
1802       break;
1803   }
1804   return d;
1805 };
1806 /*
1807  * Based on:
1808  * Ext JS Library 1.1.1
1809  * Copyright(c) 2006-2007, Ext JS, LLC.
1810  *
1811  * Originally Released Under LGPL - original licence link has changed is not relivant.
1812  *
1813  * Fork - LGPL
1814  * <script type="text/javascript">
1815  */
1816
1817 /**
1818  * @class Roo.lib.Dom
1819  * @static
1820  * 
1821  * Dom utils (from YIU afaik)
1822  * 
1823  **/
1824 Roo.lib.Dom = {
1825     /**
1826      * Get the view width
1827      * @param {Boolean} full True will get the full document, otherwise it's the view width
1828      * @return {Number} The width
1829      */
1830      
1831     getViewWidth : function(full) {
1832         return full ? this.getDocumentWidth() : this.getViewportWidth();
1833     },
1834     /**
1835      * Get the view height
1836      * @param {Boolean} full True will get the full document, otherwise it's the view height
1837      * @return {Number} The height
1838      */
1839     getViewHeight : function(full) {
1840         return full ? this.getDocumentHeight() : this.getViewportHeight();
1841     },
1842
1843     getDocumentHeight: function() {
1844         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1845         return Math.max(scrollHeight, this.getViewportHeight());
1846     },
1847
1848     getDocumentWidth: function() {
1849         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1850         return Math.max(scrollWidth, this.getViewportWidth());
1851     },
1852
1853     getViewportHeight: function() {
1854         var height = self.innerHeight;
1855         var mode = document.compatMode;
1856
1857         if ((mode || Roo.isIE) && !Roo.isOpera) {
1858             height = (mode == "CSS1Compat") ?
1859                      document.documentElement.clientHeight :
1860                      document.body.clientHeight;
1861         }
1862
1863         return height;
1864     },
1865
1866     getViewportWidth: function() {
1867         var width = self.innerWidth;
1868         var mode = document.compatMode;
1869
1870         if (mode || Roo.isIE) {
1871             width = (mode == "CSS1Compat") ?
1872                     document.documentElement.clientWidth :
1873                     document.body.clientWidth;
1874         }
1875         return width;
1876     },
1877
1878     isAncestor : function(p, c) {
1879         p = Roo.getDom(p);
1880         c = Roo.getDom(c);
1881         if (!p || !c) {
1882             return false;
1883         }
1884
1885         if (p.contains && !Roo.isSafari) {
1886             return p.contains(c);
1887         } else if (p.compareDocumentPosition) {
1888             return !!(p.compareDocumentPosition(c) & 16);
1889         } else {
1890             var parent = c.parentNode;
1891             while (parent) {
1892                 if (parent == p) {
1893                     return true;
1894                 }
1895                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1896                     return false;
1897                 }
1898                 parent = parent.parentNode;
1899             }
1900             return false;
1901         }
1902     },
1903
1904     getRegion : function(el) {
1905         return Roo.lib.Region.getRegion(el);
1906     },
1907
1908     getY : function(el) {
1909         return this.getXY(el)[1];
1910     },
1911
1912     getX : function(el) {
1913         return this.getXY(el)[0];
1914     },
1915
1916     getXY : function(el) {
1917         var p, pe, b, scroll, bd = document.body;
1918         el = Roo.getDom(el);
1919         var fly = Roo.lib.AnimBase.fly;
1920         if (el.getBoundingClientRect) {
1921             b = el.getBoundingClientRect();
1922             scroll = fly(document).getScroll();
1923             return [b.left + scroll.left, b.top + scroll.top];
1924         }
1925         var x = 0, y = 0;
1926
1927         p = el;
1928
1929         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930
1931         while (p) {
1932
1933             x += p.offsetLeft;
1934             y += p.offsetTop;
1935
1936             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937                 hasAbsolute = true;
1938             }
1939
1940             if (Roo.isGecko) {
1941                 pe = fly(p);
1942
1943                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1944                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945
1946
1947                 x += bl;
1948                 y += bt;
1949
1950
1951                 if (p != el && pe.getStyle('overflow') != 'visible') {
1952                     x += bl;
1953                     y += bt;
1954                 }
1955             }
1956             p = p.offsetParent;
1957         }
1958
1959         if (Roo.isSafari && hasAbsolute) {
1960             x -= bd.offsetLeft;
1961             y -= bd.offsetTop;
1962         }
1963
1964         if (Roo.isGecko && !hasAbsolute) {
1965             var dbd = fly(bd);
1966             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1967             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1968         }
1969
1970         p = el.parentNode;
1971         while (p && p != bd) {
1972             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1973                 x -= p.scrollLeft;
1974                 y -= p.scrollTop;
1975             }
1976             p = p.parentNode;
1977         }
1978         return [x, y];
1979     },
1980  
1981   
1982
1983
1984     setXY : function(el, xy) {
1985         el = Roo.fly(el, '_setXY');
1986         el.position();
1987         var pts = el.translatePoints(xy);
1988         if (xy[0] !== false) {
1989             el.dom.style.left = pts.left + "px";
1990         }
1991         if (xy[1] !== false) {
1992             el.dom.style.top = pts.top + "px";
1993         }
1994     },
1995
1996     setX : function(el, x) {
1997         this.setXY(el, [x, false]);
1998     },
1999
2000     setY : function(el, y) {
2001         this.setXY(el, [false, y]);
2002     }
2003 };
2004 /*
2005  * Portions of this file are based on pieces of Yahoo User Interface Library
2006  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2007  * YUI licensed under the BSD License:
2008  * http://developer.yahoo.net/yui/license.txt
2009  * <script type="text/javascript">
2010  *
2011  */
2012
2013 Roo.lib.Event = function() {
2014     var loadComplete = false;
2015     var listeners = [];
2016     var unloadListeners = [];
2017     var retryCount = 0;
2018     var onAvailStack = [];
2019     var counter = 0;
2020     var lastError = null;
2021
2022     return {
2023         POLL_RETRYS: 200,
2024         POLL_INTERVAL: 20,
2025         EL: 0,
2026         TYPE: 1,
2027         FN: 2,
2028         WFN: 3,
2029         OBJ: 3,
2030         ADJ_SCOPE: 4,
2031         _interval: null,
2032
2033         startInterval: function() {
2034             if (!this._interval) {
2035                 var self = this;
2036                 var callback = function() {
2037                     self._tryPreloadAttach();
2038                 };
2039                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2040
2041             }
2042         },
2043
2044         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2045             onAvailStack.push({ id:         p_id,
2046                 fn:         p_fn,
2047                 obj:        p_obj,
2048                 override:   p_override,
2049                 checkReady: false    });
2050
2051             retryCount = this.POLL_RETRYS;
2052             this.startInterval();
2053         },
2054
2055
2056         addListener: function(el, eventName, fn) {
2057             el = Roo.getDom(el);
2058             if (!el || !fn) {
2059                 return false;
2060             }
2061
2062             if ("unload" == eventName) {
2063                 unloadListeners[unloadListeners.length] =
2064                 [el, eventName, fn];
2065                 return true;
2066             }
2067
2068             var wrappedFn = function(e) {
2069                 return fn(Roo.lib.Event.getEvent(e));
2070             };
2071
2072             var li = [el, eventName, fn, wrappedFn];
2073
2074             var index = listeners.length;
2075             listeners[index] = li;
2076
2077             this.doAdd(el, eventName, wrappedFn, false);
2078             return true;
2079
2080         },
2081
2082
2083         removeListener: function(el, eventName, fn) {
2084             var i, len;
2085
2086             el = Roo.getDom(el);
2087
2088             if(!fn) {
2089                 return this.purgeElement(el, false, eventName);
2090             }
2091
2092
2093             if ("unload" == eventName) {
2094
2095                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2096                     var li = unloadListeners[i];
2097                     if (li &&
2098                         li[0] == el &&
2099                         li[1] == eventName &&
2100                         li[2] == fn) {
2101                         unloadListeners.splice(i, 1);
2102                         return true;
2103                     }
2104                 }
2105
2106                 return false;
2107             }
2108
2109             var cacheItem = null;
2110
2111
2112             var index = arguments[3];
2113
2114             if ("undefined" == typeof index) {
2115                 index = this._getCacheIndex(el, eventName, fn);
2116             }
2117
2118             if (index >= 0) {
2119                 cacheItem = listeners[index];
2120             }
2121
2122             if (!el || !cacheItem) {
2123                 return false;
2124             }
2125
2126             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2127
2128             delete listeners[index][this.WFN];
2129             delete listeners[index][this.FN];
2130             listeners.splice(index, 1);
2131
2132             return true;
2133
2134         },
2135
2136
2137         getTarget: function(ev, resolveTextNode) {
2138             ev = ev.browserEvent || ev;
2139             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2140             var t = ev.target || ev.srcElement;
2141             return this.resolveTextNode(t);
2142         },
2143
2144
2145         resolveTextNode: function(node) {
2146             if (Roo.isSafari && node && 3 == node.nodeType) {
2147                 return node.parentNode;
2148             } else {
2149                 return node;
2150             }
2151         },
2152
2153
2154         getPageX: function(ev) {
2155             ev = ev.browserEvent || ev;
2156             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2157             var x = ev.pageX;
2158             if (!x && 0 !== x) {
2159                 x = ev.clientX || 0;
2160
2161                 if (Roo.isIE) {
2162                     x += this.getScroll()[1];
2163                 }
2164             }
2165
2166             return x;
2167         },
2168
2169
2170         getPageY: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2173             var y = ev.pageY;
2174             if (!y && 0 !== y) {
2175                 y = ev.clientY || 0;
2176
2177                 if (Roo.isIE) {
2178                     y += this.getScroll()[0];
2179                 }
2180             }
2181
2182
2183             return y;
2184         },
2185
2186
2187         getXY: function(ev) {
2188             ev = ev.browserEvent || ev;
2189             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2190             return [this.getPageX(ev), this.getPageY(ev)];
2191         },
2192
2193
2194         getRelatedTarget: function(ev) {
2195             ev = ev.browserEvent || ev;
2196             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2197             var t = ev.relatedTarget;
2198             if (!t) {
2199                 if (ev.type == "mouseout") {
2200                     t = ev.toElement;
2201                 } else if (ev.type == "mouseover") {
2202                     t = ev.fromElement;
2203                 }
2204             }
2205
2206             return this.resolveTextNode(t);
2207         },
2208
2209
2210         getTime: function(ev) {
2211             ev = ev.browserEvent || ev;
2212             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2213             if (!ev.time) {
2214                 var t = new Date().getTime();
2215                 try {
2216                     ev.time = t;
2217                 } catch(ex) {
2218                     this.lastError = ex;
2219                     return t;
2220                 }
2221             }
2222
2223             return ev.time;
2224         },
2225
2226
2227         stopEvent: function(ev) {
2228             this.stopPropagation(ev);
2229             this.preventDefault(ev);
2230         },
2231
2232
2233         stopPropagation: function(ev) {
2234             ev = ev.browserEvent || ev;
2235             if (ev.stopPropagation) {
2236                 ev.stopPropagation();
2237             } else {
2238                 ev.cancelBubble = true;
2239             }
2240         },
2241
2242
2243         preventDefault: function(ev) {
2244             ev = ev.browserEvent || ev;
2245             if(ev.preventDefault) {
2246                 ev.preventDefault();
2247             } else {
2248                 ev.returnValue = false;
2249             }
2250         },
2251
2252
2253         getEvent: function(e) {
2254             var ev = e || window.event;
2255             if (!ev) {
2256                 var c = this.getEvent.caller;
2257                 while (c) {
2258                     ev = c.arguments[0];
2259                     if (ev && Event == ev.constructor) {
2260                         break;
2261                     }
2262                     c = c.caller;
2263                 }
2264             }
2265             return ev;
2266         },
2267
2268
2269         getCharCode: function(ev) {
2270             ev = ev.browserEvent || ev;
2271             return ev.charCode || ev.keyCode || 0;
2272         },
2273
2274
2275         _getCacheIndex: function(el, eventName, fn) {
2276             for (var i = 0,len = listeners.length; i < len; ++i) {
2277                 var li = listeners[i];
2278                 if (li &&
2279                     li[this.FN] == fn &&
2280                     li[this.EL] == el &&
2281                     li[this.TYPE] == eventName) {
2282                     return i;
2283                 }
2284             }
2285
2286             return -1;
2287         },
2288
2289
2290         elCache: {},
2291
2292
2293         getEl: function(id) {
2294             return document.getElementById(id);
2295         },
2296
2297
2298         clearCache: function() {
2299         },
2300
2301
2302         _load: function(e) {
2303             loadComplete = true;
2304             var EU = Roo.lib.Event;
2305
2306
2307             if (Roo.isIE) {
2308                 EU.doRemove(window, "load", EU._load);
2309             }
2310         },
2311
2312
2313         _tryPreloadAttach: function() {
2314
2315             if (this.locked) {
2316                 return false;
2317             }
2318
2319             this.locked = true;
2320
2321
2322             var tryAgain = !loadComplete;
2323             if (!tryAgain) {
2324                 tryAgain = (retryCount > 0);
2325             }
2326
2327
2328             var notAvail = [];
2329             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2330                 var item = onAvailStack[i];
2331                 if (item) {
2332                     var el = this.getEl(item.id);
2333
2334                     if (el) {
2335                         if (!item.checkReady ||
2336                             loadComplete ||
2337                             el.nextSibling ||
2338                             (document && document.body)) {
2339
2340                             var scope = el;
2341                             if (item.override) {
2342                                 if (item.override === true) {
2343                                     scope = item.obj;
2344                                 } else {
2345                                     scope = item.override;
2346                                 }
2347                             }
2348                             item.fn.call(scope, item.obj);
2349                             onAvailStack[i] = null;
2350                         }
2351                     } else {
2352                         notAvail.push(item);
2353                     }
2354                 }
2355             }
2356
2357             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2358
2359             if (tryAgain) {
2360
2361                 this.startInterval();
2362             } else {
2363                 clearInterval(this._interval);
2364                 this._interval = null;
2365             }
2366
2367             this.locked = false;
2368
2369             return true;
2370
2371         },
2372
2373
2374         purgeElement: function(el, recurse, eventName) {
2375             var elListeners = this.getListeners(el, eventName);
2376             if (elListeners) {
2377                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2378                     var l = elListeners[i];
2379                     this.removeListener(el, l.type, l.fn);
2380                 }
2381             }
2382
2383             if (recurse && el && el.childNodes) {
2384                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2385                     this.purgeElement(el.childNodes[i], recurse, eventName);
2386                 }
2387             }
2388         },
2389
2390
2391         getListeners: function(el, eventName) {
2392             var results = [], searchLists;
2393             if (!eventName) {
2394                 searchLists = [listeners, unloadListeners];
2395             } else if (eventName == "unload") {
2396                 searchLists = [unloadListeners];
2397             } else {
2398                 searchLists = [listeners];
2399             }
2400
2401             for (var j = 0; j < searchLists.length; ++j) {
2402                 var searchList = searchLists[j];
2403                 if (searchList && searchList.length > 0) {
2404                     for (var i = 0,len = searchList.length; i < len; ++i) {
2405                         var l = searchList[i];
2406                         if (l && l[this.EL] === el &&
2407                             (!eventName || eventName === l[this.TYPE])) {
2408                             results.push({
2409                                 type:   l[this.TYPE],
2410                                 fn:     l[this.FN],
2411                                 obj:    l[this.OBJ],
2412                                 adjust: l[this.ADJ_SCOPE],
2413                                 index:  i
2414                             });
2415                         }
2416                     }
2417                 }
2418             }
2419
2420             return (results.length) ? results : null;
2421         },
2422
2423
2424         _unload: function(e) {
2425
2426             var EU = Roo.lib.Event, i, j, l, len, index;
2427
2428             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2429                 l = unloadListeners[i];
2430                 if (l) {
2431                     var scope = window;
2432                     if (l[EU.ADJ_SCOPE]) {
2433                         if (l[EU.ADJ_SCOPE] === true) {
2434                             scope = l[EU.OBJ];
2435                         } else {
2436                             scope = l[EU.ADJ_SCOPE];
2437                         }
2438                     }
2439                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2440                     unloadListeners[i] = null;
2441                     l = null;
2442                     scope = null;
2443                 }
2444             }
2445
2446             unloadListeners = null;
2447
2448             if (listeners && listeners.length > 0) {
2449                 j = listeners.length;
2450                 while (j) {
2451                     index = j - 1;
2452                     l = listeners[index];
2453                     if (l) {
2454                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2455                                 l[EU.FN], index);
2456                     }
2457                     j = j - 1;
2458                 }
2459                 l = null;
2460
2461                 EU.clearCache();
2462             }
2463
2464             EU.doRemove(window, "unload", EU._unload);
2465
2466         },
2467
2468
2469         getScroll: function() {
2470             var dd = document.documentElement, db = document.body;
2471             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2472                 return [dd.scrollTop, dd.scrollLeft];
2473             } else if (db) {
2474                 return [db.scrollTop, db.scrollLeft];
2475             } else {
2476                 return [0, 0];
2477             }
2478         },
2479
2480
2481         doAdd: function () {
2482             if (window.addEventListener) {
2483                 return function(el, eventName, fn, capture) {
2484                     el.addEventListener(eventName, fn, (capture));
2485                 };
2486             } else if (window.attachEvent) {
2487                 return function(el, eventName, fn, capture) {
2488                     el.attachEvent("on" + eventName, fn);
2489                 };
2490             } else {
2491                 return function() {
2492                 };
2493             }
2494         }(),
2495
2496
2497         doRemove: function() {
2498             if (window.removeEventListener) {
2499                 return function (el, eventName, fn, capture) {
2500                     el.removeEventListener(eventName, fn, (capture));
2501                 };
2502             } else if (window.detachEvent) {
2503                 return function (el, eventName, fn) {
2504                     el.detachEvent("on" + eventName, fn);
2505                 };
2506             } else {
2507                 return function() {
2508                 };
2509             }
2510         }()
2511     };
2512     
2513 }();
2514 (function() {     
2515    
2516     var E = Roo.lib.Event;
2517     E.on = E.addListener;
2518     E.un = E.removeListener;
2519
2520     if (document && document.body) {
2521         E._load();
2522     } else {
2523         E.doAdd(window, "load", E._load);
2524     }
2525     E.doAdd(window, "unload", E._unload);
2526     E._tryPreloadAttach();
2527 })();
2528
2529 /*
2530  * Portions of this file are based on pieces of Yahoo User Interface Library
2531  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2532  * YUI licensed under the BSD License:
2533  * http://developer.yahoo.net/yui/license.txt
2534  * <script type="text/javascript">
2535  *
2536  */
2537
2538 (function() {
2539     /**
2540      * @class Roo.lib.Ajax
2541      *
2542      */
2543     Roo.lib.Ajax = {
2544         /**
2545          * @static 
2546          */
2547         request : function(method, uri, cb, data, options) {
2548             if(options){
2549                 var hs = options.headers;
2550                 if(hs){
2551                     for(var h in hs){
2552                         if(hs.hasOwnProperty(h)){
2553                             this.initHeader(h, hs[h], false);
2554                         }
2555                     }
2556                 }
2557                 if(options.xmlData){
2558                     this.initHeader('Content-Type', 'text/xml', false);
2559                     method = 'POST';
2560                     data = options.xmlData;
2561                 }
2562             }
2563
2564             return this.asyncRequest(method, uri, cb, data);
2565         },
2566
2567         serializeForm : function(form) {
2568             if(typeof form == 'string') {
2569                 form = (document.getElementById(form) || document.forms[form]);
2570             }
2571
2572             var el, name, val, disabled, data = '', hasSubmit = false;
2573             for (var i = 0; i < form.elements.length; i++) {
2574                 el = form.elements[i];
2575                 disabled = form.elements[i].disabled;
2576                 name = form.elements[i].name;
2577                 val = form.elements[i].value;
2578
2579                 if (!disabled && name){
2580                     switch (el.type)
2581                             {
2582                         case 'select-one':
2583                         case 'select-multiple':
2584                             for (var j = 0; j < el.options.length; j++) {
2585                                 if (el.options[j].selected) {
2586                                     if (Roo.isIE) {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                     else {
2590                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2591                                     }
2592                                 }
2593                             }
2594                             break;
2595                         case 'radio':
2596                         case 'checkbox':
2597                             if (el.checked) {
2598                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599                             }
2600                             break;
2601                         case 'file':
2602
2603                         case undefined:
2604
2605                         case 'reset':
2606
2607                         case 'button':
2608
2609                             break;
2610                         case 'submit':
2611                             if(hasSubmit == false) {
2612                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2613                                 hasSubmit = true;
2614                             }
2615                             break;
2616                         default:
2617                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2618                             break;
2619                     }
2620                 }
2621             }
2622             data = data.substr(0, data.length - 1);
2623             return data;
2624         },
2625
2626         headers:{},
2627
2628         hasHeaders:false,
2629
2630         useDefaultHeader:true,
2631
2632         defaultPostHeader:'application/x-www-form-urlencoded',
2633
2634         useDefaultXhrHeader:true,
2635
2636         defaultXhrHeader:'XMLHttpRequest',
2637
2638         hasDefaultHeaders:true,
2639
2640         defaultHeaders:{},
2641
2642         poll:{},
2643
2644         timeout:{},
2645
2646         pollInterval:50,
2647
2648         transactionId:0,
2649
2650         setProgId:function(id)
2651         {
2652             this.activeX.unshift(id);
2653         },
2654
2655         setDefaultPostHeader:function(b)
2656         {
2657             this.useDefaultHeader = b;
2658         },
2659
2660         setDefaultXhrHeader:function(b)
2661         {
2662             this.useDefaultXhrHeader = b;
2663         },
2664
2665         setPollingInterval:function(i)
2666         {
2667             if (typeof i == 'number' && isFinite(i)) {
2668                 this.pollInterval = i;
2669             }
2670         },
2671
2672         createXhrObject:function(transactionId)
2673         {
2674             var obj,http;
2675             try
2676             {
2677
2678                 http = new XMLHttpRequest();
2679
2680                 obj = { conn:http, tId:transactionId };
2681             }
2682             catch(e)
2683             {
2684                 for (var i = 0; i < this.activeX.length; ++i) {
2685                     try
2686                     {
2687
2688                         http = new ActiveXObject(this.activeX[i]);
2689
2690                         obj = { conn:http, tId:transactionId };
2691                         break;
2692                     }
2693                     catch(e) {
2694                     }
2695                 }
2696             }
2697             finally
2698             {
2699                 return obj;
2700             }
2701         },
2702
2703         getConnectionObject:function()
2704         {
2705             var o;
2706             var tId = this.transactionId;
2707
2708             try
2709             {
2710                 o = this.createXhrObject(tId);
2711                 if (o) {
2712                     this.transactionId++;
2713                 }
2714             }
2715             catch(e) {
2716             }
2717             finally
2718             {
2719                 return o;
2720             }
2721         },
2722
2723         asyncRequest:function(method, uri, callback, postData)
2724         {
2725             var o = this.getConnectionObject();
2726
2727             if (!o) {
2728                 return null;
2729             }
2730             else {
2731                 o.conn.open(method, uri, true);
2732
2733                 if (this.useDefaultXhrHeader) {
2734                     if (!this.defaultHeaders['X-Requested-With']) {
2735                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2736                     }
2737                 }
2738
2739                 if(postData && this.useDefaultHeader){
2740                     this.initHeader('Content-Type', this.defaultPostHeader);
2741                 }
2742
2743                  if (this.hasDefaultHeaders || this.hasHeaders) {
2744                     this.setHeader(o);
2745                 }
2746
2747                 this.handleReadyState(o, callback);
2748                 o.conn.send(postData || null);
2749
2750                 return o;
2751             }
2752         },
2753
2754         handleReadyState:function(o, callback)
2755         {
2756             var oConn = this;
2757
2758             if (callback && callback.timeout) {
2759                 
2760                 this.timeout[o.tId] = window.setTimeout(function() {
2761                     oConn.abort(o, callback, true);
2762                 }, callback.timeout);
2763             }
2764
2765             this.poll[o.tId] = window.setInterval(
2766                     function() {
2767                         if (o.conn && o.conn.readyState == 4) {
2768                             window.clearInterval(oConn.poll[o.tId]);
2769                             delete oConn.poll[o.tId];
2770
2771                             if(callback && callback.timeout) {
2772                                 window.clearTimeout(oConn.timeout[o.tId]);
2773                                 delete oConn.timeout[o.tId];
2774                             }
2775
2776                             oConn.handleTransactionResponse(o, callback);
2777                         }
2778                     }
2779                     , this.pollInterval);
2780         },
2781
2782         handleTransactionResponse:function(o, callback, isAbort)
2783         {
2784
2785             if (!callback) {
2786                 this.releaseObject(o);
2787                 return;
2788             }
2789
2790             var httpStatus, responseObject;
2791
2792             try
2793             {
2794                 if (o.conn.status !== undefined && o.conn.status != 0) {
2795                     httpStatus = o.conn.status;
2796                 }
2797                 else {
2798                     httpStatus = 13030;
2799                 }
2800             }
2801             catch(e) {
2802
2803
2804                 httpStatus = 13030;
2805             }
2806
2807             if (httpStatus >= 200 && httpStatus < 300) {
2808                 responseObject = this.createResponseObject(o, callback.argument);
2809                 if (callback.success) {
2810                     if (!callback.scope) {
2811                         callback.success(responseObject);
2812                     }
2813                     else {
2814
2815
2816                         callback.success.apply(callback.scope, [responseObject]);
2817                     }
2818                 }
2819             }
2820             else {
2821                 switch (httpStatus) {
2822
2823                     case 12002:
2824                     case 12029:
2825                     case 12030:
2826                     case 12031:
2827                     case 12152:
2828                     case 13030:
2829                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2830                         if (callback.failure) {
2831                             if (!callback.scope) {
2832                                 callback.failure(responseObject);
2833                             }
2834                             else {
2835                                 callback.failure.apply(callback.scope, [responseObject]);
2836                             }
2837                         }
2838                         break;
2839                     default:
2840                         responseObject = this.createResponseObject(o, callback.argument);
2841                         if (callback.failure) {
2842                             if (!callback.scope) {
2843                                 callback.failure(responseObject);
2844                             }
2845                             else {
2846                                 callback.failure.apply(callback.scope, [responseObject]);
2847                             }
2848                         }
2849                 }
2850             }
2851
2852             this.releaseObject(o);
2853             responseObject = null;
2854         },
2855
2856         createResponseObject:function(o, callbackArg)
2857         {
2858             var obj = {};
2859             var headerObj = {};
2860
2861             try
2862             {
2863                 var headerStr = o.conn.getAllResponseHeaders();
2864                 var header = headerStr.split('\n');
2865                 for (var i = 0; i < header.length; i++) {
2866                     var delimitPos = header[i].indexOf(':');
2867                     if (delimitPos != -1) {
2868                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2869                     }
2870                 }
2871             }
2872             catch(e) {
2873             }
2874
2875             obj.tId = o.tId;
2876             obj.status = o.conn.status;
2877             obj.statusText = o.conn.statusText;
2878             obj.getResponseHeader = headerObj;
2879             obj.getAllResponseHeaders = headerStr;
2880             obj.responseText = o.conn.responseText;
2881             obj.responseXML = o.conn.responseXML;
2882
2883             if (typeof callbackArg !== undefined) {
2884                 obj.argument = callbackArg;
2885             }
2886
2887             return obj;
2888         },
2889
2890         createExceptionObject:function(tId, callbackArg, isAbort)
2891         {
2892             var COMM_CODE = 0;
2893             var COMM_ERROR = 'communication failure';
2894             var ABORT_CODE = -1;
2895             var ABORT_ERROR = 'transaction aborted';
2896
2897             var obj = {};
2898
2899             obj.tId = tId;
2900             if (isAbort) {
2901                 obj.status = ABORT_CODE;
2902                 obj.statusText = ABORT_ERROR;
2903             }
2904             else {
2905                 obj.status = COMM_CODE;
2906                 obj.statusText = COMM_ERROR;
2907             }
2908
2909             if (callbackArg) {
2910                 obj.argument = callbackArg;
2911             }
2912
2913             return obj;
2914         },
2915
2916         initHeader:function(label, value, isDefault)
2917         {
2918             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2919
2920             if (headerObj[label] === undefined) {
2921                 headerObj[label] = value;
2922             }
2923             else {
2924
2925
2926                 headerObj[label] = value + "," + headerObj[label];
2927             }
2928
2929             if (isDefault) {
2930                 this.hasDefaultHeaders = true;
2931             }
2932             else {
2933                 this.hasHeaders = true;
2934             }
2935         },
2936
2937
2938         setHeader:function(o)
2939         {
2940             if (this.hasDefaultHeaders) {
2941                 for (var prop in this.defaultHeaders) {
2942                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2943                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2944                     }
2945                 }
2946             }
2947
2948             if (this.hasHeaders) {
2949                 for (var prop in this.headers) {
2950                     if (this.headers.hasOwnProperty(prop)) {
2951                         o.conn.setRequestHeader(prop, this.headers[prop]);
2952                     }
2953                 }
2954                 this.headers = {};
2955                 this.hasHeaders = false;
2956             }
2957         },
2958
2959         resetDefaultHeaders:function() {
2960             delete this.defaultHeaders;
2961             this.defaultHeaders = {};
2962             this.hasDefaultHeaders = false;
2963         },
2964
2965         abort:function(o, callback, isTimeout)
2966         {
2967             if(this.isCallInProgress(o)) {
2968                 o.conn.abort();
2969                 window.clearInterval(this.poll[o.tId]);
2970                 delete this.poll[o.tId];
2971                 if (isTimeout) {
2972                     delete this.timeout[o.tId];
2973                 }
2974
2975                 this.handleTransactionResponse(o, callback, true);
2976
2977                 return true;
2978             }
2979             else {
2980                 return false;
2981             }
2982         },
2983
2984
2985         isCallInProgress:function(o)
2986         {
2987             if (o && o.conn) {
2988                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2989             }
2990             else {
2991
2992                 return false;
2993             }
2994         },
2995
2996
2997         releaseObject:function(o)
2998         {
2999
3000             o.conn = null;
3001
3002             o = null;
3003         },
3004
3005         activeX:[
3006         'MSXML2.XMLHTTP.3.0',
3007         'MSXML2.XMLHTTP',
3008         'Microsoft.XMLHTTP'
3009         ]
3010
3011
3012     };
3013 })();/*
3014  * Portions of this file are based on pieces of Yahoo User Interface Library
3015  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3016  * YUI licensed under the BSD License:
3017  * http://developer.yahoo.net/yui/license.txt
3018  * <script type="text/javascript">
3019  *
3020  */
3021
3022 Roo.lib.Region = function(t, r, b, l) {
3023     this.top = t;
3024     this[1] = t;
3025     this.right = r;
3026     this.bottom = b;
3027     this.left = l;
3028     this[0] = l;
3029 };
3030
3031
3032 Roo.lib.Region.prototype = {
3033     contains : function(region) {
3034         return ( region.left >= this.left &&
3035                  region.right <= this.right &&
3036                  region.top >= this.top &&
3037                  region.bottom <= this.bottom    );
3038
3039     },
3040
3041     getArea : function() {
3042         return ( (this.bottom - this.top) * (this.right - this.left) );
3043     },
3044
3045     intersect : function(region) {
3046         var t = Math.max(this.top, region.top);
3047         var r = Math.min(this.right, region.right);
3048         var b = Math.min(this.bottom, region.bottom);
3049         var l = Math.max(this.left, region.left);
3050
3051         if (b >= t && r >= l) {
3052             return new Roo.lib.Region(t, r, b, l);
3053         } else {
3054             return null;
3055         }
3056     },
3057     union : function(region) {
3058         var t = Math.min(this.top, region.top);
3059         var r = Math.max(this.right, region.right);
3060         var b = Math.max(this.bottom, region.bottom);
3061         var l = Math.min(this.left, region.left);
3062
3063         return new Roo.lib.Region(t, r, b, l);
3064     },
3065
3066     adjust : function(t, l, b, r) {
3067         this.top += t;
3068         this.left += l;
3069         this.right += r;
3070         this.bottom += b;
3071         return this;
3072     }
3073 };
3074
3075 Roo.lib.Region.getRegion = function(el) {
3076     var p = Roo.lib.Dom.getXY(el);
3077
3078     var t = p[1];
3079     var r = p[0] + el.offsetWidth;
3080     var b = p[1] + el.offsetHeight;
3081     var l = p[0];
3082
3083     return new Roo.lib.Region(t, r, b, l);
3084 };
3085 /*
3086  * Portions of this file are based on pieces of Yahoo User Interface Library
3087  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088  * YUI licensed under the BSD License:
3089  * http://developer.yahoo.net/yui/license.txt
3090  * <script type="text/javascript">
3091  *
3092  */
3093 //@@dep Roo.lib.Region
3094
3095
3096 Roo.lib.Point = function(x, y) {
3097     if (x instanceof Array) {
3098         y = x[1];
3099         x = x[0];
3100     }
3101     this.x = this.right = this.left = this[0] = x;
3102     this.y = this.top = this.bottom = this[1] = y;
3103 };
3104
3105 Roo.lib.Point.prototype = new Roo.lib.Region();
3106 /*
3107  * Portions of this file are based on pieces of Yahoo User Interface Library
3108  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109  * YUI licensed under the BSD License:
3110  * http://developer.yahoo.net/yui/license.txt
3111  * <script type="text/javascript">
3112  *
3113  */
3114  
3115 (function() {   
3116
3117     Roo.lib.Anim = {
3118         scroll : function(el, args, duration, easing, cb, scope) {
3119             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3120         },
3121
3122         motion : function(el, args, duration, easing, cb, scope) {
3123             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3124         },
3125
3126         color : function(el, args, duration, easing, cb, scope) {
3127             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3128         },
3129
3130         run : function(el, args, duration, easing, cb, scope, type) {
3131             type = type || Roo.lib.AnimBase;
3132             if (typeof easing == "string") {
3133                 easing = Roo.lib.Easing[easing];
3134             }
3135             var anim = new type(el, args, duration, easing);
3136             anim.animateX(function() {
3137                 Roo.callback(cb, scope);
3138             });
3139             return anim;
3140         }
3141     };
3142 })();/*
3143  * Portions of this file are based on pieces of Yahoo User Interface Library
3144  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3145  * YUI licensed under the BSD License:
3146  * http://developer.yahoo.net/yui/license.txt
3147  * <script type="text/javascript">
3148  *
3149  */
3150
3151 (function() {    
3152     var libFlyweight;
3153     
3154     function fly(el) {
3155         if (!libFlyweight) {
3156             libFlyweight = new Roo.Element.Flyweight();
3157         }
3158         libFlyweight.dom = el;
3159         return libFlyweight;
3160     }
3161
3162     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3163     
3164    
3165     
3166     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3167         if (el) {
3168             this.init(el, attributes, duration, method);
3169         }
3170     };
3171
3172     Roo.lib.AnimBase.fly = fly;
3173     
3174     
3175     
3176     Roo.lib.AnimBase.prototype = {
3177
3178         toString: function() {
3179             var el = this.getEl();
3180             var id = el.id || el.tagName;
3181             return ("Anim " + id);
3182         },
3183
3184         patterns: {
3185             noNegatives:        /width|height|opacity|padding/i,
3186             offsetAttribute:  /^((width|height)|(top|left))$/,
3187             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3188             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3189         },
3190
3191
3192         doMethod: function(attr, start, end) {
3193             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3194         },
3195
3196
3197         setAttribute: function(attr, val, unit) {
3198             if (this.patterns.noNegatives.test(attr)) {
3199                 val = (val > 0) ? val : 0;
3200             }
3201
3202             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3203         },
3204
3205
3206         getAttribute: function(attr) {
3207             var el = this.getEl();
3208             var val = fly(el).getStyle(attr);
3209
3210             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3211                 return parseFloat(val);
3212             }
3213
3214             var a = this.patterns.offsetAttribute.exec(attr) || [];
3215             var pos = !!( a[3] );
3216             var box = !!( a[2] );
3217
3218
3219             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3220                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3221             } else {
3222                 val = 0;
3223             }
3224
3225             return val;
3226         },
3227
3228
3229         getDefaultUnit: function(attr) {
3230             if (this.patterns.defaultUnit.test(attr)) {
3231                 return 'px';
3232             }
3233
3234             return '';
3235         },
3236
3237         animateX : function(callback, scope) {
3238             var f = function() {
3239                 this.onComplete.removeListener(f);
3240                 if (typeof callback == "function") {
3241                     callback.call(scope || this, this);
3242                 }
3243             };
3244             this.onComplete.addListener(f, this);
3245             this.animate();
3246         },
3247
3248
3249         setRuntimeAttribute: function(attr) {
3250             var start;
3251             var end;
3252             var attributes = this.attributes;
3253
3254             this.runtimeAttributes[attr] = {};
3255
3256             var isset = function(prop) {
3257                 return (typeof prop !== 'undefined');
3258             };
3259
3260             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3261                 return false;
3262             }
3263
3264             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3265
3266
3267             if (isset(attributes[attr]['to'])) {
3268                 end = attributes[attr]['to'];
3269             } else if (isset(attributes[attr]['by'])) {
3270                 if (start.constructor == Array) {
3271                     end = [];
3272                     for (var i = 0, len = start.length; i < len; ++i) {
3273                         end[i] = start[i] + attributes[attr]['by'][i];
3274                     }
3275                 } else {
3276                     end = start + attributes[attr]['by'];
3277                 }
3278             }
3279
3280             this.runtimeAttributes[attr].start = start;
3281             this.runtimeAttributes[attr].end = end;
3282
3283
3284             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3285         },
3286
3287
3288         init: function(el, attributes, duration, method) {
3289
3290             var isAnimated = false;
3291
3292
3293             var startTime = null;
3294
3295
3296             var actualFrames = 0;
3297
3298
3299             el = Roo.getDom(el);
3300
3301
3302             this.attributes = attributes || {};
3303
3304
3305             this.duration = duration || 1;
3306
3307
3308             this.method = method || Roo.lib.Easing.easeNone;
3309
3310
3311             this.useSeconds = true;
3312
3313
3314             this.currentFrame = 0;
3315
3316
3317             this.totalFrames = Roo.lib.AnimMgr.fps;
3318
3319
3320             this.getEl = function() {
3321                 return el;
3322             };
3323
3324
3325             this.isAnimated = function() {
3326                 return isAnimated;
3327             };
3328
3329
3330             this.getStartTime = function() {
3331                 return startTime;
3332             };
3333
3334             this.runtimeAttributes = {};
3335
3336
3337             this.animate = function() {
3338                 if (this.isAnimated()) {
3339                     return false;
3340                 }
3341
3342                 this.currentFrame = 0;
3343
3344                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3345
3346                 Roo.lib.AnimMgr.registerElement(this);
3347             };
3348
3349
3350             this.stop = function(finish) {
3351                 if (finish) {
3352                     this.currentFrame = this.totalFrames;
3353                     this._onTween.fire();
3354                 }
3355                 Roo.lib.AnimMgr.stop(this);
3356             };
3357
3358             var onStart = function() {
3359                 this.onStart.fire();
3360
3361                 this.runtimeAttributes = {};
3362                 for (var attr in this.attributes) {
3363                     this.setRuntimeAttribute(attr);
3364                 }
3365
3366                 isAnimated = true;
3367                 actualFrames = 0;
3368                 startTime = new Date();
3369             };
3370
3371
3372             var onTween = function() {
3373                 var data = {
3374                     duration: new Date() - this.getStartTime(),
3375                     currentFrame: this.currentFrame
3376                 };
3377
3378                 data.toString = function() {
3379                     return (
3380                             'duration: ' + data.duration +
3381                             ', currentFrame: ' + data.currentFrame
3382                             );
3383                 };
3384
3385                 this.onTween.fire(data);
3386
3387                 var runtimeAttributes = this.runtimeAttributes;
3388
3389                 for (var attr in runtimeAttributes) {
3390                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3391                 }
3392
3393                 actualFrames += 1;
3394             };
3395
3396             var onComplete = function() {
3397                 var actual_duration = (new Date() - startTime) / 1000 ;
3398
3399                 var data = {
3400                     duration: actual_duration,
3401                     frames: actualFrames,
3402                     fps: actualFrames / actual_duration
3403                 };
3404
3405                 data.toString = function() {
3406                     return (
3407                             'duration: ' + data.duration +
3408                             ', frames: ' + data.frames +
3409                             ', fps: ' + data.fps
3410                             );
3411                 };
3412
3413                 isAnimated = false;
3414                 actualFrames = 0;
3415                 this.onComplete.fire(data);
3416             };
3417
3418
3419             this._onStart = new Roo.util.Event(this);
3420             this.onStart = new Roo.util.Event(this);
3421             this.onTween = new Roo.util.Event(this);
3422             this._onTween = new Roo.util.Event(this);
3423             this.onComplete = new Roo.util.Event(this);
3424             this._onComplete = new Roo.util.Event(this);
3425             this._onStart.addListener(onStart);
3426             this._onTween.addListener(onTween);
3427             this._onComplete.addListener(onComplete);
3428         }
3429     };
3430 })();
3431 /*
3432  * Portions of this file are based on pieces of Yahoo User Interface Library
3433  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3434  * YUI licensed under the BSD License:
3435  * http://developer.yahoo.net/yui/license.txt
3436  * <script type="text/javascript">
3437  *
3438  */
3439
3440 Roo.lib.AnimMgr = new function() {
3441
3442     var thread = null;
3443
3444
3445     var queue = [];
3446
3447
3448     var tweenCount = 0;
3449
3450
3451     this.fps = 1000;
3452
3453
3454     this.delay = 1;
3455
3456
3457     this.registerElement = function(tween) {
3458         queue[queue.length] = tween;
3459         tweenCount += 1;
3460         tween._onStart.fire();
3461         this.start();
3462     };
3463
3464
3465     this.unRegister = function(tween, index) {
3466         tween._onComplete.fire();
3467         index = index || getIndex(tween);
3468         if (index != -1) {
3469             queue.splice(index, 1);
3470         }
3471
3472         tweenCount -= 1;
3473         if (tweenCount <= 0) {
3474             this.stop();
3475         }
3476     };
3477
3478
3479     this.start = function() {
3480         if (thread === null) {
3481             thread = setInterval(this.run, this.delay);
3482         }
3483     };
3484
3485
3486     this.stop = function(tween) {
3487         if (!tween) {
3488             clearInterval(thread);
3489
3490             for (var i = 0, len = queue.length; i < len; ++i) {
3491                 if (queue[0].isAnimated()) {
3492                     this.unRegister(queue[0], 0);
3493                 }
3494             }
3495
3496             queue = [];
3497             thread = null;
3498             tweenCount = 0;
3499         }
3500         else {
3501             this.unRegister(tween);
3502         }
3503     };
3504
3505
3506     this.run = function() {
3507         for (var i = 0, len = queue.length; i < len; ++i) {
3508             var tween = queue[i];
3509             if (!tween || !tween.isAnimated()) {
3510                 continue;
3511             }
3512
3513             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3514             {
3515                 tween.currentFrame += 1;
3516
3517                 if (tween.useSeconds) {
3518                     correctFrame(tween);
3519                 }
3520                 tween._onTween.fire();
3521             }
3522             else {
3523                 Roo.lib.AnimMgr.stop(tween, i);
3524             }
3525         }
3526     };
3527
3528     var getIndex = function(anim) {
3529         for (var i = 0, len = queue.length; i < len; ++i) {
3530             if (queue[i] == anim) {
3531                 return i;
3532             }
3533         }
3534         return -1;
3535     };
3536
3537
3538     var correctFrame = function(tween) {
3539         var frames = tween.totalFrames;
3540         var frame = tween.currentFrame;
3541         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3542         var elapsed = (new Date() - tween.getStartTime());
3543         var tweak = 0;
3544
3545         if (elapsed < tween.duration * 1000) {
3546             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3547         } else {
3548             tweak = frames - (frame + 1);
3549         }
3550         if (tweak > 0 && isFinite(tweak)) {
3551             if (tween.currentFrame + tweak >= frames) {
3552                 tweak = frames - (frame + 1);
3553             }
3554
3555             tween.currentFrame += tweak;
3556         }
3557     };
3558 };
3559
3560     /*
3561  * Portions of this file are based on pieces of Yahoo User Interface Library
3562  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3563  * YUI licensed under the BSD License:
3564  * http://developer.yahoo.net/yui/license.txt
3565  * <script type="text/javascript">
3566  *
3567  */
3568 Roo.lib.Bezier = new function() {
3569
3570         this.getPosition = function(points, t) {
3571             var n = points.length;
3572             var tmp = [];
3573
3574             for (var i = 0; i < n; ++i) {
3575                 tmp[i] = [points[i][0], points[i][1]];
3576             }
3577
3578             for (var j = 1; j < n; ++j) {
3579                 for (i = 0; i < n - j; ++i) {
3580                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3581                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3582                 }
3583             }
3584
3585             return [ tmp[0][0], tmp[0][1] ];
3586
3587         };
3588     };/*
3589  * Portions of this file are based on pieces of Yahoo User Interface Library
3590  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3591  * YUI licensed under the BSD License:
3592  * http://developer.yahoo.net/yui/license.txt
3593  * <script type="text/javascript">
3594  *
3595  */
3596 (function() {
3597
3598     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3599         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3600     };
3601
3602     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3603
3604     var fly = Roo.lib.AnimBase.fly;
3605     var Y = Roo.lib;
3606     var superclass = Y.ColorAnim.superclass;
3607     var proto = Y.ColorAnim.prototype;
3608
3609     proto.toString = function() {
3610         var el = this.getEl();
3611         var id = el.id || el.tagName;
3612         return ("ColorAnim " + id);
3613     };
3614
3615     proto.patterns.color = /color$/i;
3616     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3617     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3618     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3619     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3620
3621
3622     proto.parseColor = function(s) {
3623         if (s.length == 3) {
3624             return s;
3625         }
3626
3627         var c = this.patterns.hex.exec(s);
3628         if (c && c.length == 4) {
3629             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3630         }
3631
3632         c = this.patterns.rgb.exec(s);
3633         if (c && c.length == 4) {
3634             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3635         }
3636
3637         c = this.patterns.hex3.exec(s);
3638         if (c && c.length == 4) {
3639             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3640         }
3641
3642         return null;
3643     };
3644     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3645     proto.getAttribute = function(attr) {
3646         var el = this.getEl();
3647         if (this.patterns.color.test(attr)) {
3648             var val = fly(el).getStyle(attr);
3649
3650             if (this.patterns.transparent.test(val)) {
3651                 var parent = el.parentNode;
3652                 val = fly(parent).getStyle(attr);
3653
3654                 while (parent && this.patterns.transparent.test(val)) {
3655                     parent = parent.parentNode;
3656                     val = fly(parent).getStyle(attr);
3657                     if (parent.tagName.toUpperCase() == 'HTML') {
3658                         val = '#fff';
3659                     }
3660                 }
3661             }
3662         } else {
3663             val = superclass.getAttribute.call(this, attr);
3664         }
3665
3666         return val;
3667     };
3668     proto.getAttribute = function(attr) {
3669         var el = this.getEl();
3670         if (this.patterns.color.test(attr)) {
3671             var val = fly(el).getStyle(attr);
3672
3673             if (this.patterns.transparent.test(val)) {
3674                 var parent = el.parentNode;
3675                 val = fly(parent).getStyle(attr);
3676
3677                 while (parent && this.patterns.transparent.test(val)) {
3678                     parent = parent.parentNode;
3679                     val = fly(parent).getStyle(attr);
3680                     if (parent.tagName.toUpperCase() == 'HTML') {
3681                         val = '#fff';
3682                     }
3683                 }
3684             }
3685         } else {
3686             val = superclass.getAttribute.call(this, attr);
3687         }
3688
3689         return val;
3690     };
3691
3692     proto.doMethod = function(attr, start, end) {
3693         var val;
3694
3695         if (this.patterns.color.test(attr)) {
3696             val = [];
3697             for (var i = 0, len = start.length; i < len; ++i) {
3698                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3699             }
3700
3701             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3702         }
3703         else {
3704             val = superclass.doMethod.call(this, attr, start, end);
3705         }
3706
3707         return val;
3708     };
3709
3710     proto.setRuntimeAttribute = function(attr) {
3711         superclass.setRuntimeAttribute.call(this, attr);
3712
3713         if (this.patterns.color.test(attr)) {
3714             var attributes = this.attributes;
3715             var start = this.parseColor(this.runtimeAttributes[attr].start);
3716             var end = this.parseColor(this.runtimeAttributes[attr].end);
3717
3718             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3719                 end = this.parseColor(attributes[attr].by);
3720
3721                 for (var i = 0, len = start.length; i < len; ++i) {
3722                     end[i] = start[i] + end[i];
3723                 }
3724             }
3725
3726             this.runtimeAttributes[attr].start = start;
3727             this.runtimeAttributes[attr].end = end;
3728         }
3729     };
3730 })();
3731
3732 /*
3733  * Portions of this file are based on pieces of Yahoo User Interface Library
3734  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3735  * YUI licensed under the BSD License:
3736  * http://developer.yahoo.net/yui/license.txt
3737  * <script type="text/javascript">
3738  *
3739  */
3740 Roo.lib.Easing = {
3741
3742
3743     easeNone: function (t, b, c, d) {
3744         return c * t / d + b;
3745     },
3746
3747
3748     easeIn: function (t, b, c, d) {
3749         return c * (t /= d) * t + b;
3750     },
3751
3752
3753     easeOut: function (t, b, c, d) {
3754         return -c * (t /= d) * (t - 2) + b;
3755     },
3756
3757
3758     easeBoth: function (t, b, c, d) {
3759         if ((t /= d / 2) < 1) {
3760             return c / 2 * t * t + b;
3761         }
3762
3763         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3764     },
3765
3766
3767     easeInStrong: function (t, b, c, d) {
3768         return c * (t /= d) * t * t * t + b;
3769     },
3770
3771
3772     easeOutStrong: function (t, b, c, d) {
3773         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3774     },
3775
3776
3777     easeBothStrong: function (t, b, c, d) {
3778         if ((t /= d / 2) < 1) {
3779             return c / 2 * t * t * t * t + b;
3780         }
3781
3782         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3783     },
3784
3785
3786
3787     elasticIn: function (t, b, c, d, a, p) {
3788         if (t == 0) {
3789             return b;
3790         }
3791         if ((t /= d) == 1) {
3792             return b + c;
3793         }
3794         if (!p) {
3795             p = d * .3;
3796         }
3797
3798         if (!a || a < Math.abs(c)) {
3799             a = c;
3800             var s = p / 4;
3801         }
3802         else {
3803             var s = p / (2 * Math.PI) * Math.asin(c / a);
3804         }
3805
3806         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3807     },
3808
3809
3810     elasticOut: function (t, b, c, d, a, p) {
3811         if (t == 0) {
3812             return b;
3813         }
3814         if ((t /= d) == 1) {
3815             return b + c;
3816         }
3817         if (!p) {
3818             p = d * .3;
3819         }
3820
3821         if (!a || a < Math.abs(c)) {
3822             a = c;
3823             var s = p / 4;
3824         }
3825         else {
3826             var s = p / (2 * Math.PI) * Math.asin(c / a);
3827         }
3828
3829         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3830     },
3831
3832
3833     elasticBoth: function (t, b, c, d, a, p) {
3834         if (t == 0) {
3835             return b;
3836         }
3837
3838         if ((t /= d / 2) == 2) {
3839             return b + c;
3840         }
3841
3842         if (!p) {
3843             p = d * (.3 * 1.5);
3844         }
3845
3846         if (!a || a < Math.abs(c)) {
3847             a = c;
3848             var s = p / 4;
3849         }
3850         else {
3851             var s = p / (2 * Math.PI) * Math.asin(c / a);
3852         }
3853
3854         if (t < 1) {
3855             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3856                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3857         }
3858         return a * Math.pow(2, -10 * (t -= 1)) *
3859                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3860     },
3861
3862
3863
3864     backIn: function (t, b, c, d, s) {
3865         if (typeof s == 'undefined') {
3866             s = 1.70158;
3867         }
3868         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3869     },
3870
3871
3872     backOut: function (t, b, c, d, s) {
3873         if (typeof s == 'undefined') {
3874             s = 1.70158;
3875         }
3876         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3877     },
3878
3879
3880     backBoth: function (t, b, c, d, s) {
3881         if (typeof s == 'undefined') {
3882             s = 1.70158;
3883         }
3884
3885         if ((t /= d / 2 ) < 1) {
3886             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3887         }
3888         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3889     },
3890
3891
3892     bounceIn: function (t, b, c, d) {
3893         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3894     },
3895
3896
3897     bounceOut: function (t, b, c, d) {
3898         if ((t /= d) < (1 / 2.75)) {
3899             return c * (7.5625 * t * t) + b;
3900         } else if (t < (2 / 2.75)) {
3901             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3902         } else if (t < (2.5 / 2.75)) {
3903             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3904         }
3905         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3906     },
3907
3908
3909     bounceBoth: function (t, b, c, d) {
3910         if (t < d / 2) {
3911             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3912         }
3913         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3914     }
3915 };/*
3916  * Portions of this file are based on pieces of Yahoo User Interface Library
3917  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3918  * YUI licensed under the BSD License:
3919  * http://developer.yahoo.net/yui/license.txt
3920  * <script type="text/javascript">
3921  *
3922  */
3923     (function() {
3924         Roo.lib.Motion = function(el, attributes, duration, method) {
3925             if (el) {
3926                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3927             }
3928         };
3929
3930         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3931
3932
3933         var Y = Roo.lib;
3934         var superclass = Y.Motion.superclass;
3935         var proto = Y.Motion.prototype;
3936
3937         proto.toString = function() {
3938             var el = this.getEl();
3939             var id = el.id || el.tagName;
3940             return ("Motion " + id);
3941         };
3942
3943         proto.patterns.points = /^points$/i;
3944
3945         proto.setAttribute = function(attr, val, unit) {
3946             if (this.patterns.points.test(attr)) {
3947                 unit = unit || 'px';
3948                 superclass.setAttribute.call(this, 'left', val[0], unit);
3949                 superclass.setAttribute.call(this, 'top', val[1], unit);
3950             } else {
3951                 superclass.setAttribute.call(this, attr, val, unit);
3952             }
3953         };
3954
3955         proto.getAttribute = function(attr) {
3956             if (this.patterns.points.test(attr)) {
3957                 var val = [
3958                         superclass.getAttribute.call(this, 'left'),
3959                         superclass.getAttribute.call(this, 'top')
3960                         ];
3961             } else {
3962                 val = superclass.getAttribute.call(this, attr);
3963             }
3964
3965             return val;
3966         };
3967
3968         proto.doMethod = function(attr, start, end) {
3969             var val = null;
3970
3971             if (this.patterns.points.test(attr)) {
3972                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3973                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3974             } else {
3975                 val = superclass.doMethod.call(this, attr, start, end);
3976             }
3977             return val;
3978         };
3979
3980         proto.setRuntimeAttribute = function(attr) {
3981             if (this.patterns.points.test(attr)) {
3982                 var el = this.getEl();
3983                 var attributes = this.attributes;
3984                 var start;
3985                 var control = attributes['points']['control'] || [];
3986                 var end;
3987                 var i, len;
3988
3989                 if (control.length > 0 && !(control[0] instanceof Array)) {
3990                     control = [control];
3991                 } else {
3992                     var tmp = [];
3993                     for (i = 0,len = control.length; i < len; ++i) {
3994                         tmp[i] = control[i];
3995                     }
3996                     control = tmp;
3997                 }
3998
3999                 Roo.fly(el).position();
4000
4001                 if (isset(attributes['points']['from'])) {
4002                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4003                 }
4004                 else {
4005                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4006                 }
4007
4008                 start = this.getAttribute('points');
4009
4010
4011                 if (isset(attributes['points']['to'])) {
4012                     end = translateValues.call(this, attributes['points']['to'], start);
4013
4014                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4015                     for (i = 0,len = control.length; i < len; ++i) {
4016                         control[i] = translateValues.call(this, control[i], start);
4017                     }
4018
4019
4020                 } else if (isset(attributes['points']['by'])) {
4021                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4022
4023                     for (i = 0,len = control.length; i < len; ++i) {
4024                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4025                     }
4026                 }
4027
4028                 this.runtimeAttributes[attr] = [start];
4029
4030                 if (control.length > 0) {
4031                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4032                 }
4033
4034                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4035             }
4036             else {
4037                 superclass.setRuntimeAttribute.call(this, attr);
4038             }
4039         };
4040
4041         var translateValues = function(val, start) {
4042             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4043             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4044
4045             return val;
4046         };
4047
4048         var isset = function(prop) {
4049             return (typeof prop !== 'undefined');
4050         };
4051     })();
4052 /*
4053  * Portions of this file are based on pieces of Yahoo User Interface Library
4054  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4055  * YUI licensed under the BSD License:
4056  * http://developer.yahoo.net/yui/license.txt
4057  * <script type="text/javascript">
4058  *
4059  */
4060     (function() {
4061         Roo.lib.Scroll = function(el, attributes, duration, method) {
4062             if (el) {
4063                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4064             }
4065         };
4066
4067         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4068
4069
4070         var Y = Roo.lib;
4071         var superclass = Y.Scroll.superclass;
4072         var proto = Y.Scroll.prototype;
4073
4074         proto.toString = function() {
4075             var el = this.getEl();
4076             var id = el.id || el.tagName;
4077             return ("Scroll " + id);
4078         };
4079
4080         proto.doMethod = function(attr, start, end) {
4081             var val = null;
4082
4083             if (attr == 'scroll') {
4084                 val = [
4085                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4086                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4087                         ];
4088
4089             } else {
4090                 val = superclass.doMethod.call(this, attr, start, end);
4091             }
4092             return val;
4093         };
4094
4095         proto.getAttribute = function(attr) {
4096             var val = null;
4097             var el = this.getEl();
4098
4099             if (attr == 'scroll') {
4100                 val = [ el.scrollLeft, el.scrollTop ];
4101             } else {
4102                 val = superclass.getAttribute.call(this, attr);
4103             }
4104
4105             return val;
4106         };
4107
4108         proto.setAttribute = function(attr, val, unit) {
4109             var el = this.getEl();
4110
4111             if (attr == 'scroll') {
4112                 el.scrollLeft = val[0];
4113                 el.scrollTop = val[1];
4114             } else {
4115                 superclass.setAttribute.call(this, attr, val, unit);
4116             }
4117         };
4118     })();
4119 /*
4120  * Based on:
4121  * Ext JS Library 1.1.1
4122  * Copyright(c) 2006-2007, Ext JS, LLC.
4123  *
4124  * Originally Released Under LGPL - original licence link has changed is not relivant.
4125  *
4126  * Fork - LGPL
4127  * <script type="text/javascript">
4128  */
4129
4130
4131 // nasty IE9 hack - what a pile of crap that is..
4132
4133  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4134     Range.prototype.createContextualFragment = function (html) {
4135         var doc = window.document;
4136         var container = doc.createElement("div");
4137         container.innerHTML = html;
4138         var frag = doc.createDocumentFragment(), n;
4139         while ((n = container.firstChild)) {
4140             frag.appendChild(n);
4141         }
4142         return frag;
4143     };
4144 }
4145
4146 /**
4147  * @class Roo.DomHelper
4148  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4149  * 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>.
4150  * @singleton
4151  */
4152 Roo.DomHelper = function(){
4153     var tempTableEl = null;
4154     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4155     var tableRe = /^table|tbody|tr|td$/i;
4156     var xmlns = {};
4157     // build as innerHTML where available
4158     /** @ignore */
4159     var createHtml = function(o){
4160         if(typeof o == 'string'){
4161             return o;
4162         }
4163         var b = "";
4164         if(!o.tag){
4165             o.tag = "div";
4166         }
4167         b += "<" + o.tag;
4168         for(var attr in o){
4169             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4170             if(attr == "style"){
4171                 var s = o["style"];
4172                 if(typeof s == "function"){
4173                     s = s.call();
4174                 }
4175                 if(typeof s == "string"){
4176                     b += ' style="' + s + '"';
4177                 }else if(typeof s == "object"){
4178                     b += ' style="';
4179                     for(var key in s){
4180                         if(typeof s[key] != "function"){
4181                             b += key + ":" + s[key] + ";";
4182                         }
4183                     }
4184                     b += '"';
4185                 }
4186             }else{
4187                 if(attr == "cls"){
4188                     b += ' class="' + o["cls"] + '"';
4189                 }else if(attr == "htmlFor"){
4190                     b += ' for="' + o["htmlFor"] + '"';
4191                 }else{
4192                     b += " " + attr + '="' + o[attr] + '"';
4193                 }
4194             }
4195         }
4196         if(emptyTags.test(o.tag)){
4197             b += "/>";
4198         }else{
4199             b += ">";
4200             var cn = o.children || o.cn;
4201             if(cn){
4202                 //http://bugs.kde.org/show_bug.cgi?id=71506
4203                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4204                     for(var i = 0, len = cn.length; i < len; i++) {
4205                         b += createHtml(cn[i], b);
4206                     }
4207                 }else{
4208                     b += createHtml(cn, b);
4209                 }
4210             }
4211             if(o.html){
4212                 b += o.html;
4213             }
4214             b += "</" + o.tag + ">";
4215         }
4216         return b;
4217     };
4218
4219     // build as dom
4220     /** @ignore */
4221     var createDom = function(o, parentNode){
4222          
4223         // defininition craeted..
4224         var ns = false;
4225         if (o.ns && o.ns != 'html') {
4226                
4227             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4228                 xmlns[o.ns] = o.xmlns;
4229                 ns = o.xmlns;
4230             }
4231             if (typeof(xmlns[o.ns]) == 'undefined') {
4232                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4233             }
4234             ns = xmlns[o.ns];
4235         }
4236         
4237         
4238         if (typeof(o) == 'string') {
4239             return parentNode.appendChild(document.createTextNode(o));
4240         }
4241         o.tag = o.tag || div;
4242         if (o.ns && Roo.isIE) {
4243             ns = false;
4244             o.tag = o.ns + ':' + o.tag;
4245             
4246         }
4247         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4248         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4249         for(var attr in o){
4250             
4251             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4252                     attr == "style" || typeof o[attr] == "function") { continue; }
4253                     
4254             if(attr=="cls" && Roo.isIE){
4255                 el.className = o["cls"];
4256             }else{
4257                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4258                 else { 
4259                     el[attr] = o[attr];
4260                 }
4261             }
4262         }
4263         Roo.DomHelper.applyStyles(el, o.style);
4264         var cn = o.children || o.cn;
4265         if(cn){
4266             //http://bugs.kde.org/show_bug.cgi?id=71506
4267              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4268                 for(var i = 0, len = cn.length; i < len; i++) {
4269                     createDom(cn[i], el);
4270                 }
4271             }else{
4272                 createDom(cn, el);
4273             }
4274         }
4275         if(o.html){
4276             el.innerHTML = o.html;
4277         }
4278         if(parentNode){
4279            parentNode.appendChild(el);
4280         }
4281         return el;
4282     };
4283
4284     var ieTable = function(depth, s, h, e){
4285         tempTableEl.innerHTML = [s, h, e].join('');
4286         var i = -1, el = tempTableEl;
4287         while(++i < depth){
4288             el = el.firstChild;
4289         }
4290         return el;
4291     };
4292
4293     // kill repeat to save bytes
4294     var ts = '<table>',
4295         te = '</table>',
4296         tbs = ts+'<tbody>',
4297         tbe = '</tbody>'+te,
4298         trs = tbs + '<tr>',
4299         tre = '</tr>'+tbe;
4300
4301     /**
4302      * @ignore
4303      * Nasty code for IE's broken table implementation
4304      */
4305     var insertIntoTable = function(tag, where, el, html){
4306         if(!tempTableEl){
4307             tempTableEl = document.createElement('div');
4308         }
4309         var node;
4310         var before = null;
4311         if(tag == 'td'){
4312             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4313                 return;
4314             }
4315             if(where == 'beforebegin'){
4316                 before = el;
4317                 el = el.parentNode;
4318             } else{
4319                 before = el.nextSibling;
4320                 el = el.parentNode;
4321             }
4322             node = ieTable(4, trs, html, tre);
4323         }
4324         else if(tag == 'tr'){
4325             if(where == 'beforebegin'){
4326                 before = el;
4327                 el = el.parentNode;
4328                 node = ieTable(3, tbs, html, tbe);
4329             } else if(where == 'afterend'){
4330                 before = el.nextSibling;
4331                 el = el.parentNode;
4332                 node = ieTable(3, tbs, html, tbe);
4333             } else{ // INTO a TR
4334                 if(where == 'afterbegin'){
4335                     before = el.firstChild;
4336                 }
4337                 node = ieTable(4, trs, html, tre);
4338             }
4339         } else if(tag == 'tbody'){
4340             if(where == 'beforebegin'){
4341                 before = el;
4342                 el = el.parentNode;
4343                 node = ieTable(2, ts, html, te);
4344             } else if(where == 'afterend'){
4345                 before = el.nextSibling;
4346                 el = el.parentNode;
4347                 node = ieTable(2, ts, html, te);
4348             } else{
4349                 if(where == 'afterbegin'){
4350                     before = el.firstChild;
4351                 }
4352                 node = ieTable(3, tbs, html, tbe);
4353             }
4354         } else{ // TABLE
4355             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4356                 return;
4357             }
4358             if(where == 'afterbegin'){
4359                 before = el.firstChild;
4360             }
4361             node = ieTable(2, ts, html, te);
4362         }
4363         el.insertBefore(node, before);
4364         return node;
4365     };
4366
4367     return {
4368     /** True to force the use of DOM instead of html fragments @type Boolean */
4369     useDom : false,
4370
4371     /**
4372      * Returns the markup for the passed Element(s) config
4373      * @param {Object} o The Dom object spec (and children)
4374      * @return {String}
4375      */
4376     markup : function(o){
4377         return createHtml(o);
4378     },
4379
4380     /**
4381      * Applies a style specification to an element
4382      * @param {String/HTMLElement} el The element to apply styles to
4383      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4384      * a function which returns such a specification.
4385      */
4386     applyStyles : function(el, styles){
4387         if(styles){
4388            el = Roo.fly(el);
4389            if(typeof styles == "string"){
4390                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4391                var matches;
4392                while ((matches = re.exec(styles)) != null){
4393                    el.setStyle(matches[1], matches[2]);
4394                }
4395            }else if (typeof styles == "object"){
4396                for (var style in styles){
4397                   el.setStyle(style, styles[style]);
4398                }
4399            }else if (typeof styles == "function"){
4400                 Roo.DomHelper.applyStyles(el, styles.call());
4401            }
4402         }
4403     },
4404
4405     /**
4406      * Inserts an HTML fragment into the Dom
4407      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4408      * @param {HTMLElement} el The context element
4409      * @param {String} html The HTML fragmenet
4410      * @return {HTMLElement} The new node
4411      */
4412     insertHtml : function(where, el, html){
4413         where = where.toLowerCase();
4414         if(el.insertAdjacentHTML){
4415             if(tableRe.test(el.tagName)){
4416                 var rs;
4417                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4418                     return rs;
4419                 }
4420             }
4421             switch(where){
4422                 case "beforebegin":
4423                     el.insertAdjacentHTML('BeforeBegin', html);
4424                     return el.previousSibling;
4425                 case "afterbegin":
4426                     el.insertAdjacentHTML('AfterBegin', html);
4427                     return el.firstChild;
4428                 case "beforeend":
4429                     el.insertAdjacentHTML('BeforeEnd', html);
4430                     return el.lastChild;
4431                 case "afterend":
4432                     el.insertAdjacentHTML('AfterEnd', html);
4433                     return el.nextSibling;
4434             }
4435             throw 'Illegal insertion point -> "' + where + '"';
4436         }
4437         var range = el.ownerDocument.createRange();
4438         var frag;
4439         switch(where){
4440              case "beforebegin":
4441                 range.setStartBefore(el);
4442                 frag = range.createContextualFragment(html);
4443                 el.parentNode.insertBefore(frag, el);
4444                 return el.previousSibling;
4445              case "afterbegin":
4446                 if(el.firstChild){
4447                     range.setStartBefore(el.firstChild);
4448                     frag = range.createContextualFragment(html);
4449                     el.insertBefore(frag, el.firstChild);
4450                     return el.firstChild;
4451                 }else{
4452                     el.innerHTML = html;
4453                     return el.firstChild;
4454                 }
4455             case "beforeend":
4456                 if(el.lastChild){
4457                     range.setStartAfter(el.lastChild);
4458                     frag = range.createContextualFragment(html);
4459                     el.appendChild(frag);
4460                     return el.lastChild;
4461                 }else{
4462                     el.innerHTML = html;
4463                     return el.lastChild;
4464                 }
4465             case "afterend":
4466                 range.setStartAfter(el);
4467                 frag = range.createContextualFragment(html);
4468                 el.parentNode.insertBefore(frag, el.nextSibling);
4469                 return el.nextSibling;
4470             }
4471             throw 'Illegal insertion point -> "' + where + '"';
4472     },
4473
4474     /**
4475      * Creates new Dom element(s) and inserts them before el
4476      * @param {String/HTMLElement/Element} el The context element
4477      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4478      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4479      * @return {HTMLElement/Roo.Element} The new node
4480      */
4481     insertBefore : function(el, o, returnElement){
4482         return this.doInsert(el, o, returnElement, "beforeBegin");
4483     },
4484
4485     /**
4486      * Creates new Dom element(s) and inserts them after el
4487      * @param {String/HTMLElement/Element} el The context element
4488      * @param {Object} o The Dom object spec (and children)
4489      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490      * @return {HTMLElement/Roo.Element} The new node
4491      */
4492     insertAfter : function(el, o, returnElement){
4493         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4494     },
4495
4496     /**
4497      * Creates new Dom element(s) and inserts them as the first child of el
4498      * @param {String/HTMLElement/Element} el The context element
4499      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4500      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4501      * @return {HTMLElement/Roo.Element} The new node
4502      */
4503     insertFirst : function(el, o, returnElement){
4504         return this.doInsert(el, o, returnElement, "afterBegin");
4505     },
4506
4507     // private
4508     doInsert : function(el, o, returnElement, pos, sibling){
4509         el = Roo.getDom(el);
4510         var newNode;
4511         if(this.useDom || o.ns){
4512             newNode = createDom(o, null);
4513             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4514         }else{
4515             var html = createHtml(o);
4516             newNode = this.insertHtml(pos, el, html);
4517         }
4518         return returnElement ? Roo.get(newNode, true) : newNode;
4519     },
4520
4521     /**
4522      * Creates new Dom element(s) and appends them to el
4523      * @param {String/HTMLElement/Element} el The context element
4524      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526      * @return {HTMLElement/Roo.Element} The new node
4527      */
4528     append : function(el, o, returnElement){
4529         el = Roo.getDom(el);
4530         var newNode;
4531         if(this.useDom || o.ns){
4532             newNode = createDom(o, null);
4533             el.appendChild(newNode);
4534         }else{
4535             var html = createHtml(o);
4536             newNode = this.insertHtml("beforeEnd", el, html);
4537         }
4538         return returnElement ? Roo.get(newNode, true) : newNode;
4539     },
4540
4541     /**
4542      * Creates new Dom element(s) and overwrites the contents of el with them
4543      * @param {String/HTMLElement/Element} el The context element
4544      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4545      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4546      * @return {HTMLElement/Roo.Element} The new node
4547      */
4548     overwrite : function(el, o, returnElement){
4549         el = Roo.getDom(el);
4550         if (o.ns) {
4551           
4552             while (el.childNodes.length) {
4553                 el.removeChild(el.firstChild);
4554             }
4555             createDom(o, el);
4556         } else {
4557             el.innerHTML = createHtml(o);   
4558         }
4559         
4560         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4561     },
4562
4563     /**
4564      * Creates a new Roo.DomHelper.Template from the Dom object spec
4565      * @param {Object} o The Dom object spec (and children)
4566      * @return {Roo.DomHelper.Template} The new template
4567      */
4568     createTemplate : function(o){
4569         var html = createHtml(o);
4570         return new Roo.Template(html);
4571     }
4572     };
4573 }();
4574 /*
4575  * Based on:
4576  * Ext JS Library 1.1.1
4577  * Copyright(c) 2006-2007, Ext JS, LLC.
4578  *
4579  * Originally Released Under LGPL - original licence link has changed is not relivant.
4580  *
4581  * Fork - LGPL
4582  * <script type="text/javascript">
4583  */
4584  
4585 /**
4586 * @class Roo.Template
4587 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4588 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4589 * Usage:
4590 <pre><code>
4591 var t = new Roo.Template({
4592     html :  '&lt;div name="{id}"&gt;' + 
4593         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4594         '&lt;/div&gt;',
4595     myformat: function (value, allValues) {
4596         return 'XX' + value;
4597     }
4598 });
4599 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4600 </code></pre>
4601 * For more information see this blog post with examples:
4602 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4603      - Create Elements using DOM, HTML fragments and Templates</a>. 
4604 * @constructor
4605 * @param {Object} cfg - Configuration object.
4606 */
4607 Roo.Template = function(cfg){
4608     // BC!
4609     if(cfg instanceof Array){
4610         cfg = cfg.join("");
4611     }else if(arguments.length > 1){
4612         cfg = Array.prototype.join.call(arguments, "");
4613     }
4614     
4615     
4616     if (typeof(cfg) == 'object') {
4617         Roo.apply(this,cfg)
4618     } else {
4619         // bc
4620         this.html = cfg;
4621     }
4622     if (this.url) {
4623         this.load();
4624     }
4625     
4626 };
4627 Roo.Template.prototype = {
4628     
4629     /**
4630      * @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..
4631      *                    it should be fixed so that template is observable...
4632      */
4633     url : false,
4634     /**
4635      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4636      */
4637     html : '',
4638     /**
4639      * Returns an HTML fragment of this template with the specified values applied.
4640      * @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'})
4641      * @return {String} The HTML fragment
4642      */
4643     applyTemplate : function(values){
4644         try {
4645            
4646             if(this.compiled){
4647                 return this.compiled(values);
4648             }
4649             var useF = this.disableFormats !== true;
4650             var fm = Roo.util.Format, tpl = this;
4651             var fn = function(m, name, format, args){
4652                 if(format && useF){
4653                     if(format.substr(0, 5) == "this."){
4654                         return tpl.call(format.substr(5), values[name], values);
4655                     }else{
4656                         if(args){
4657                             // quoted values are required for strings in compiled templates, 
4658                             // but for non compiled we need to strip them
4659                             // quoted reversed for jsmin
4660                             var re = /^\s*['"](.*)["']\s*$/;
4661                             args = args.split(',');
4662                             for(var i = 0, len = args.length; i < len; i++){
4663                                 args[i] = args[i].replace(re, "$1");
4664                             }
4665                             args = [values[name]].concat(args);
4666                         }else{
4667                             args = [values[name]];
4668                         }
4669                         return fm[format].apply(fm, args);
4670                     }
4671                 }else{
4672                     return values[name] !== undefined ? values[name] : "";
4673                 }
4674             };
4675             return this.html.replace(this.re, fn);
4676         } catch (e) {
4677             Roo.log(e);
4678             throw e;
4679         }
4680          
4681     },
4682     
4683     loading : false,
4684       
4685     load : function ()
4686     {
4687          
4688         if (this.loading) {
4689             return;
4690         }
4691         var _t = this;
4692         
4693         this.loading = true;
4694         this.compiled = false;
4695         
4696         var cx = new Roo.data.Connection();
4697         cx.request({
4698             url : this.url,
4699             method : 'GET',
4700             success : function (response) {
4701                 _t.loading = false;
4702                 _t.html = response.responseText;
4703                 _t.url = false;
4704                 _t.compile();
4705              },
4706             failure : function(response) {
4707                 Roo.log("Template failed to load from " + _t.url);
4708                 _t.loading = false;
4709             }
4710         });
4711     },
4712
4713     /**
4714      * Sets the HTML used as the template and optionally compiles it.
4715      * @param {String} html
4716      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4717      * @return {Roo.Template} this
4718      */
4719     set : function(html, compile){
4720         this.html = html;
4721         this.compiled = null;
4722         if(compile){
4723             this.compile();
4724         }
4725         return this;
4726     },
4727     
4728     /**
4729      * True to disable format functions (defaults to false)
4730      * @type Boolean
4731      */
4732     disableFormats : false,
4733     
4734     /**
4735     * The regular expression used to match template variables 
4736     * @type RegExp
4737     * @property 
4738     */
4739     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4740     
4741     /**
4742      * Compiles the template into an internal function, eliminating the RegEx overhead.
4743      * @return {Roo.Template} this
4744      */
4745     compile : function(){
4746         var fm = Roo.util.Format;
4747         var useF = this.disableFormats !== true;
4748         var sep = Roo.isGecko ? "+" : ",";
4749         var fn = function(m, name, format, args){
4750             if(format && useF){
4751                 args = args ? ',' + args : "";
4752                 if(format.substr(0, 5) != "this."){
4753                     format = "fm." + format + '(';
4754                 }else{
4755                     format = 'this.call("'+ format.substr(5) + '", ';
4756                     args = ", values";
4757                 }
4758             }else{
4759                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4760             }
4761             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4762         };
4763         var body;
4764         // branched to use + in gecko and [].join() in others
4765         if(Roo.isGecko){
4766             body = "this.compiled = function(values){ return '" +
4767                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4768                     "';};";
4769         }else{
4770             body = ["this.compiled = function(values){ return ['"];
4771             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4772             body.push("'].join('');};");
4773             body = body.join('');
4774         }
4775         /**
4776          * eval:var:values
4777          * eval:var:fm
4778          */
4779         eval(body);
4780         return this;
4781     },
4782     
4783     // private function used to call members
4784     call : function(fnName, value, allValues){
4785         return this[fnName](value, allValues);
4786     },
4787     
4788     /**
4789      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4790      * @param {String/HTMLElement/Roo.Element} el The context element
4791      * @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'})
4792      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793      * @return {HTMLElement/Roo.Element} The new node or Element
4794      */
4795     insertFirst: function(el, values, returnElement){
4796         return this.doInsert('afterBegin', el, values, returnElement);
4797     },
4798
4799     /**
4800      * Applies the supplied values to the template and inserts the new node(s) before el.
4801      * @param {String/HTMLElement/Roo.Element} el The context element
4802      * @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'})
4803      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4804      * @return {HTMLElement/Roo.Element} The new node or Element
4805      */
4806     insertBefore: function(el, values, returnElement){
4807         return this.doInsert('beforeBegin', el, values, returnElement);
4808     },
4809
4810     /**
4811      * Applies the supplied values to the template and inserts the new node(s) after el.
4812      * @param {String/HTMLElement/Roo.Element} el The context element
4813      * @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'})
4814      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4815      * @return {HTMLElement/Roo.Element} The new node or Element
4816      */
4817     insertAfter : function(el, values, returnElement){
4818         return this.doInsert('afterEnd', el, values, returnElement);
4819     },
4820     
4821     /**
4822      * Applies the supplied values to the template and appends the new node(s) to el.
4823      * @param {String/HTMLElement/Roo.Element} el The context element
4824      * @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'})
4825      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4826      * @return {HTMLElement/Roo.Element} The new node or Element
4827      */
4828     append : function(el, values, returnElement){
4829         return this.doInsert('beforeEnd', el, values, returnElement);
4830     },
4831
4832     doInsert : function(where, el, values, returnEl){
4833         el = Roo.getDom(el);
4834         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4835         return returnEl ? Roo.get(newNode, true) : newNode;
4836     },
4837
4838     /**
4839      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4840      * @param {String/HTMLElement/Roo.Element} el The context element
4841      * @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'})
4842      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4843      * @return {HTMLElement/Roo.Element} The new node or Element
4844      */
4845     overwrite : function(el, values, returnElement){
4846         el = Roo.getDom(el);
4847         el.innerHTML = this.applyTemplate(values);
4848         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4849     }
4850 };
4851 /**
4852  * Alias for {@link #applyTemplate}
4853  * @method
4854  */
4855 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4856
4857 // backwards compat
4858 Roo.DomHelper.Template = Roo.Template;
4859
4860 /**
4861  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4862  * @param {String/HTMLElement} el A DOM element or its id
4863  * @returns {Roo.Template} The created template
4864  * @static
4865  */
4866 Roo.Template.from = function(el){
4867     el = Roo.getDom(el);
4868     return new Roo.Template(el.value || el.innerHTML);
4869 };/*
4870  * Based on:
4871  * Ext JS Library 1.1.1
4872  * Copyright(c) 2006-2007, Ext JS, LLC.
4873  *
4874  * Originally Released Under LGPL - original licence link has changed is not relivant.
4875  *
4876  * Fork - LGPL
4877  * <script type="text/javascript">
4878  */
4879  
4880
4881 /*
4882  * This is code is also distributed under MIT license for use
4883  * with jQuery and prototype JavaScript libraries.
4884  */
4885 /**
4886  * @class Roo.DomQuery
4887 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).
4888 <p>
4889 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>
4890
4891 <p>
4892 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.
4893 </p>
4894 <h4>Element Selectors:</h4>
4895 <ul class="list">
4896     <li> <b>*</b> any element</li>
4897     <li> <b>E</b> an element with the tag E</li>
4898     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4899     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4900     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4901     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4902 </ul>
4903 <h4>Attribute Selectors:</h4>
4904 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4905 <ul class="list">
4906     <li> <b>E[foo]</b> has an attribute "foo"</li>
4907     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4908     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4909     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4910     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4911     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4912     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4913 </ul>
4914 <h4>Pseudo Classes:</h4>
4915 <ul class="list">
4916     <li> <b>E:first-child</b> E is the first child of its parent</li>
4917     <li> <b>E:last-child</b> E is the last child of its parent</li>
4918     <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>
4919     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4920     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4921     <li> <b>E:only-child</b> E is the only child of its parent</li>
4922     <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>
4923     <li> <b>E:first</b> the first E in the resultset</li>
4924     <li> <b>E:last</b> the last E in the resultset</li>
4925     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4926     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4927     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4928     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4929     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4930     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4931     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4932     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4933     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4934 </ul>
4935 <h4>CSS Value Selectors:</h4>
4936 <ul class="list">
4937     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4938     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4939     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4940     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4941     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4942     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4943 </ul>
4944  * @singleton
4945  */
4946 Roo.DomQuery = function(){
4947     var cache = {}, simpleCache = {}, valueCache = {};
4948     var nonSpace = /\S/;
4949     var trimRe = /^\s+|\s+$/g;
4950     var tplRe = /\{(\d+)\}/g;
4951     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4952     var tagTokenRe = /^(#)?([\w-\*]+)/;
4953     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4954
4955     function child(p, index){
4956         var i = 0;
4957         var n = p.firstChild;
4958         while(n){
4959             if(n.nodeType == 1){
4960                if(++i == index){
4961                    return n;
4962                }
4963             }
4964             n = n.nextSibling;
4965         }
4966         return null;
4967     };
4968
4969     function next(n){
4970         while((n = n.nextSibling) && n.nodeType != 1);
4971         return n;
4972     };
4973
4974     function prev(n){
4975         while((n = n.previousSibling) && n.nodeType != 1);
4976         return n;
4977     };
4978
4979     function children(d){
4980         var n = d.firstChild, ni = -1;
4981             while(n){
4982                 var nx = n.nextSibling;
4983                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4984                     d.removeChild(n);
4985                 }else{
4986                     n.nodeIndex = ++ni;
4987                 }
4988                 n = nx;
4989             }
4990             return this;
4991         };
4992
4993     function byClassName(c, a, v){
4994         if(!v){
4995             return c;
4996         }
4997         var r = [], ri = -1, cn;
4998         for(var i = 0, ci; ci = c[i]; i++){
4999             if((' '+ci.className+' ').indexOf(v) != -1){
5000                 r[++ri] = ci;
5001             }
5002         }
5003         return r;
5004     };
5005
5006     function attrValue(n, attr){
5007         if(!n.tagName && typeof n.length != "undefined"){
5008             n = n[0];
5009         }
5010         if(!n){
5011             return null;
5012         }
5013         if(attr == "for"){
5014             return n.htmlFor;
5015         }
5016         if(attr == "class" || attr == "className"){
5017             return n.className;
5018         }
5019         return n.getAttribute(attr) || n[attr];
5020
5021     };
5022
5023     function getNodes(ns, mode, tagName){
5024         var result = [], ri = -1, cs;
5025         if(!ns){
5026             return result;
5027         }
5028         tagName = tagName || "*";
5029         if(typeof ns.getElementsByTagName != "undefined"){
5030             ns = [ns];
5031         }
5032         if(!mode){
5033             for(var i = 0, ni; ni = ns[i]; i++){
5034                 cs = ni.getElementsByTagName(tagName);
5035                 for(var j = 0, ci; ci = cs[j]; j++){
5036                     result[++ri] = ci;
5037                 }
5038             }
5039         }else if(mode == "/" || mode == ">"){
5040             var utag = tagName.toUpperCase();
5041             for(var i = 0, ni, cn; ni = ns[i]; i++){
5042                 cn = ni.children || ni.childNodes;
5043                 for(var j = 0, cj; cj = cn[j]; j++){
5044                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5045                         result[++ri] = cj;
5046                     }
5047                 }
5048             }
5049         }else if(mode == "+"){
5050             var utag = tagName.toUpperCase();
5051             for(var i = 0, n; n = ns[i]; i++){
5052                 while((n = n.nextSibling) && n.nodeType != 1);
5053                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5054                     result[++ri] = n;
5055                 }
5056             }
5057         }else if(mode == "~"){
5058             for(var i = 0, n; n = ns[i]; i++){
5059                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5060                 if(n){
5061                     result[++ri] = n;
5062                 }
5063             }
5064         }
5065         return result;
5066     };
5067
5068     function concat(a, b){
5069         if(b.slice){
5070             return a.concat(b);
5071         }
5072         for(var i = 0, l = b.length; i < l; i++){
5073             a[a.length] = b[i];
5074         }
5075         return a;
5076     }
5077
5078     function byTag(cs, tagName){
5079         if(cs.tagName || cs == document){
5080             cs = [cs];
5081         }
5082         if(!tagName){
5083             return cs;
5084         }
5085         var r = [], ri = -1;
5086         tagName = tagName.toLowerCase();
5087         for(var i = 0, ci; ci = cs[i]; i++){
5088             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089                 r[++ri] = ci;
5090             }
5091         }
5092         return r;
5093     };
5094
5095     function byId(cs, attr, id){
5096         if(cs.tagName || cs == document){
5097             cs = [cs];
5098         }
5099         if(!id){
5100             return cs;
5101         }
5102         var r = [], ri = -1;
5103         for(var i = 0,ci; ci = cs[i]; i++){
5104             if(ci && ci.id == id){
5105                 r[++ri] = ci;
5106                 return r;
5107             }
5108         }
5109         return r;
5110     };
5111
5112     function byAttribute(cs, attr, value, op, custom){
5113         var r = [], ri = -1, st = custom=="{";
5114         var f = Roo.DomQuery.operators[op];
5115         for(var i = 0, ci; ci = cs[i]; i++){
5116             var a;
5117             if(st){
5118                 a = Roo.DomQuery.getStyle(ci, attr);
5119             }
5120             else if(attr == "class" || attr == "className"){
5121                 a = ci.className;
5122             }else if(attr == "for"){
5123                 a = ci.htmlFor;
5124             }else if(attr == "href"){
5125                 a = ci.getAttribute("href", 2);
5126             }else{
5127                 a = ci.getAttribute(attr);
5128             }
5129             if((f && f(a, value)) || (!f && a)){
5130                 r[++ri] = ci;
5131             }
5132         }
5133         return r;
5134     };
5135
5136     function byPseudo(cs, name, value){
5137         return Roo.DomQuery.pseudos[name](cs, value);
5138     };
5139
5140     // This is for IE MSXML which does not support expandos.
5141     // IE runs the same speed using setAttribute, however FF slows way down
5142     // and Safari completely fails so they need to continue to use expandos.
5143     var isIE = window.ActiveXObject ? true : false;
5144
5145     // this eval is stop the compressor from
5146     // renaming the variable to something shorter
5147     
5148     /** eval:var:batch */
5149     var batch = 30803; 
5150
5151     var key = 30803;
5152
5153     function nodupIEXml(cs){
5154         var d = ++key;
5155         cs[0].setAttribute("_nodup", d);
5156         var r = [cs[0]];
5157         for(var i = 1, len = cs.length; i < len; i++){
5158             var c = cs[i];
5159             if(!c.getAttribute("_nodup") != d){
5160                 c.setAttribute("_nodup", d);
5161                 r[r.length] = c;
5162             }
5163         }
5164         for(var i = 0, len = cs.length; i < len; i++){
5165             cs[i].removeAttribute("_nodup");
5166         }
5167         return r;
5168     }
5169
5170     function nodup(cs){
5171         if(!cs){
5172             return [];
5173         }
5174         var len = cs.length, c, i, r = cs, cj, ri = -1;
5175         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5176             return cs;
5177         }
5178         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5179             return nodupIEXml(cs);
5180         }
5181         var d = ++key;
5182         cs[0]._nodup = d;
5183         for(i = 1; c = cs[i]; i++){
5184             if(c._nodup != d){
5185                 c._nodup = d;
5186             }else{
5187                 r = [];
5188                 for(var j = 0; j < i; j++){
5189                     r[++ri] = cs[j];
5190                 }
5191                 for(j = i+1; cj = cs[j]; j++){
5192                     if(cj._nodup != d){
5193                         cj._nodup = d;
5194                         r[++ri] = cj;
5195                     }
5196                 }
5197                 return r;
5198             }
5199         }
5200         return r;
5201     }
5202
5203     function quickDiffIEXml(c1, c2){
5204         var d = ++key;
5205         for(var i = 0, len = c1.length; i < len; i++){
5206             c1[i].setAttribute("_qdiff", d);
5207         }
5208         var r = [];
5209         for(var i = 0, len = c2.length; i < len; i++){
5210             if(c2[i].getAttribute("_qdiff") != d){
5211                 r[r.length] = c2[i];
5212             }
5213         }
5214         for(var i = 0, len = c1.length; i < len; i++){
5215            c1[i].removeAttribute("_qdiff");
5216         }
5217         return r;
5218     }
5219
5220     function quickDiff(c1, c2){
5221         var len1 = c1.length;
5222         if(!len1){
5223             return c2;
5224         }
5225         if(isIE && c1[0].selectSingleNode){
5226             return quickDiffIEXml(c1, c2);
5227         }
5228         var d = ++key;
5229         for(var i = 0; i < len1; i++){
5230             c1[i]._qdiff = d;
5231         }
5232         var r = [];
5233         for(var i = 0, len = c2.length; i < len; i++){
5234             if(c2[i]._qdiff != d){
5235                 r[r.length] = c2[i];
5236             }
5237         }
5238         return r;
5239     }
5240
5241     function quickId(ns, mode, root, id){
5242         if(ns == root){
5243            var d = root.ownerDocument || root;
5244            return d.getElementById(id);
5245         }
5246         ns = getNodes(ns, mode, "*");
5247         return byId(ns, null, id);
5248     }
5249
5250     return {
5251         getStyle : function(el, name){
5252             return Roo.fly(el).getStyle(name);
5253         },
5254         /**
5255          * Compiles a selector/xpath query into a reusable function. The returned function
5256          * takes one parameter "root" (optional), which is the context node from where the query should start.
5257          * @param {String} selector The selector/xpath query
5258          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5259          * @return {Function}
5260          */
5261         compile : function(path, type){
5262             type = type || "select";
5263             
5264             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5265             var q = path, mode, lq;
5266             var tk = Roo.DomQuery.matchers;
5267             var tklen = tk.length;
5268             var mm;
5269
5270             // accept leading mode switch
5271             var lmode = q.match(modeRe);
5272             if(lmode && lmode[1]){
5273                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5274                 q = q.replace(lmode[1], "");
5275             }
5276             // strip leading slashes
5277             while(path.substr(0, 1)=="/"){
5278                 path = path.substr(1);
5279             }
5280
5281             while(q && lq != q){
5282                 lq = q;
5283                 var tm = q.match(tagTokenRe);
5284                 if(type == "select"){
5285                     if(tm){
5286                         if(tm[1] == "#"){
5287                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5288                         }else{
5289                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5290                         }
5291                         q = q.replace(tm[0], "");
5292                     }else if(q.substr(0, 1) != '@'){
5293                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5294                     }
5295                 }else{
5296                     if(tm){
5297                         if(tm[1] == "#"){
5298                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5299                         }else{
5300                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5301                         }
5302                         q = q.replace(tm[0], "");
5303                     }
5304                 }
5305                 while(!(mm = q.match(modeRe))){
5306                     var matched = false;
5307                     for(var j = 0; j < tklen; j++){
5308                         var t = tk[j];
5309                         var m = q.match(t.re);
5310                         if(m){
5311                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5312                                                     return m[i];
5313                                                 });
5314                             q = q.replace(m[0], "");
5315                             matched = true;
5316                             break;
5317                         }
5318                     }
5319                     // prevent infinite loop on bad selector
5320                     if(!matched){
5321                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5322                     }
5323                 }
5324                 if(mm[1]){
5325                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5326                     q = q.replace(mm[1], "");
5327                 }
5328             }
5329             fn[fn.length] = "return nodup(n);\n}";
5330             
5331              /** 
5332               * list of variables that need from compression as they are used by eval.
5333              *  eval:var:batch 
5334              *  eval:var:nodup
5335              *  eval:var:byTag
5336              *  eval:var:ById
5337              *  eval:var:getNodes
5338              *  eval:var:quickId
5339              *  eval:var:mode
5340              *  eval:var:root
5341              *  eval:var:n
5342              *  eval:var:byClassName
5343              *  eval:var:byPseudo
5344              *  eval:var:byAttribute
5345              *  eval:var:attrValue
5346              * 
5347              **/ 
5348             eval(fn.join(""));
5349             return f;
5350         },
5351
5352         /**
5353          * Selects a group of elements.
5354          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5355          * @param {Node} root (optional) The start of the query (defaults to document).
5356          * @return {Array}
5357          */
5358         select : function(path, root, type){
5359             if(!root || root == document){
5360                 root = document;
5361             }
5362             if(typeof root == "string"){
5363                 root = document.getElementById(root);
5364             }
5365             var paths = path.split(",");
5366             var results = [];
5367             for(var i = 0, len = paths.length; i < len; i++){
5368                 var p = paths[i].replace(trimRe, "");
5369                 if(!cache[p]){
5370                     cache[p] = Roo.DomQuery.compile(p);
5371                     if(!cache[p]){
5372                         throw p + " is not a valid selector";
5373                     }
5374                 }
5375                 var result = cache[p](root);
5376                 if(result && result != document){
5377                     results = results.concat(result);
5378                 }
5379             }
5380             if(paths.length > 1){
5381                 return nodup(results);
5382             }
5383             return results;
5384         },
5385
5386         /**
5387          * Selects a single element.
5388          * @param {String} selector The selector/xpath query
5389          * @param {Node} root (optional) The start of the query (defaults to document).
5390          * @return {Element}
5391          */
5392         selectNode : function(path, root){
5393             return Roo.DomQuery.select(path, root)[0];
5394         },
5395
5396         /**
5397          * Selects the value of a node, optionally replacing null with the defaultValue.
5398          * @param {String} selector The selector/xpath query
5399          * @param {Node} root (optional) The start of the query (defaults to document).
5400          * @param {String} defaultValue
5401          */
5402         selectValue : function(path, root, defaultValue){
5403             path = path.replace(trimRe, "");
5404             if(!valueCache[path]){
5405                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5406             }
5407             var n = valueCache[path](root);
5408             n = n[0] ? n[0] : n;
5409             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5410             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5411         },
5412
5413         /**
5414          * Selects the value of a node, parsing integers and floats.
5415          * @param {String} selector The selector/xpath query
5416          * @param {Node} root (optional) The start of the query (defaults to document).
5417          * @param {Number} defaultValue
5418          * @return {Number}
5419          */
5420         selectNumber : function(path, root, defaultValue){
5421             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5422             return parseFloat(v);
5423         },
5424
5425         /**
5426          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5427          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5428          * @param {String} selector The simple selector to test
5429          * @return {Boolean}
5430          */
5431         is : function(el, ss){
5432             if(typeof el == "string"){
5433                 el = document.getElementById(el);
5434             }
5435             var isArray = (el instanceof Array);
5436             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5437             return isArray ? (result.length == el.length) : (result.length > 0);
5438         },
5439
5440         /**
5441          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5442          * @param {Array} el An array of elements to filter
5443          * @param {String} selector The simple selector to test
5444          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5445          * the selector instead of the ones that match
5446          * @return {Array}
5447          */
5448         filter : function(els, ss, nonMatches){
5449             ss = ss.replace(trimRe, "");
5450             if(!simpleCache[ss]){
5451                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5452             }
5453             var result = simpleCache[ss](els);
5454             return nonMatches ? quickDiff(result, els) : result;
5455         },
5456
5457         /**
5458          * Collection of matching regular expressions and code snippets.
5459          */
5460         matchers : [{
5461                 re: /^\.([\w-]+)/,
5462                 select: 'n = byClassName(n, null, " {1} ");'
5463             }, {
5464                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5465                 select: 'n = byPseudo(n, "{1}", "{2}");'
5466             },{
5467                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5468                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5469             }, {
5470                 re: /^#([\w-]+)/,
5471                 select: 'n = byId(n, null, "{1}");'
5472             },{
5473                 re: /^@([\w-]+)/,
5474                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5475             }
5476         ],
5477
5478         /**
5479          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5480          * 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;.
5481          */
5482         operators : {
5483             "=" : function(a, v){
5484                 return a == v;
5485             },
5486             "!=" : function(a, v){
5487                 return a != v;
5488             },
5489             "^=" : function(a, v){
5490                 return a && a.substr(0, v.length) == v;
5491             },
5492             "$=" : function(a, v){
5493                 return a && a.substr(a.length-v.length) == v;
5494             },
5495             "*=" : function(a, v){
5496                 return a && a.indexOf(v) !== -1;
5497             },
5498             "%=" : function(a, v){
5499                 return (a % v) == 0;
5500             },
5501             "|=" : function(a, v){
5502                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5503             },
5504             "~=" : function(a, v){
5505                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5506             }
5507         },
5508
5509         /**
5510          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5511          * and the argument (if any) supplied in the selector.
5512          */
5513         pseudos : {
5514             "first-child" : function(c){
5515                 var r = [], ri = -1, n;
5516                 for(var i = 0, ci; ci = n = c[i]; i++){
5517                     while((n = n.previousSibling) && n.nodeType != 1);
5518                     if(!n){
5519                         r[++ri] = ci;
5520                     }
5521                 }
5522                 return r;
5523             },
5524
5525             "last-child" : function(c){
5526                 var r = [], ri = -1, n;
5527                 for(var i = 0, ci; ci = n = c[i]; i++){
5528                     while((n = n.nextSibling) && n.nodeType != 1);
5529                     if(!n){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "nth-child" : function(c, a) {
5537                 var r = [], ri = -1;
5538                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5539                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5540                 for(var i = 0, n; n = c[i]; i++){
5541                     var pn = n.parentNode;
5542                     if (batch != pn._batch) {
5543                         var j = 0;
5544                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5545                             if(cn.nodeType == 1){
5546                                cn.nodeIndex = ++j;
5547                             }
5548                         }
5549                         pn._batch = batch;
5550                     }
5551                     if (f == 1) {
5552                         if (l == 0 || n.nodeIndex == l){
5553                             r[++ri] = n;
5554                         }
5555                     } else if ((n.nodeIndex + l) % f == 0){
5556                         r[++ri] = n;
5557                     }
5558                 }
5559
5560                 return r;
5561             },
5562
5563             "only-child" : function(c){
5564                 var r = [], ri = -1;;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if(!prev(ci) && !next(ci)){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "empty" : function(c){
5574                 var r = [], ri = -1;
5575                 for(var i = 0, ci; ci = c[i]; i++){
5576                     var cns = ci.childNodes, j = 0, cn, empty = true;
5577                     while(cn = cns[j]){
5578                         ++j;
5579                         if(cn.nodeType == 1 || cn.nodeType == 3){
5580                             empty = false;
5581                             break;
5582                         }
5583                     }
5584                     if(empty){
5585                         r[++ri] = ci;
5586                     }
5587                 }
5588                 return r;
5589             },
5590
5591             "contains" : function(c, v){
5592                 var r = [], ri = -1;
5593                 for(var i = 0, ci; ci = c[i]; i++){
5594                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595                         r[++ri] = ci;
5596                     }
5597                 }
5598                 return r;
5599             },
5600
5601             "nodeValue" : function(c, v){
5602                 var r = [], ri = -1;
5603                 for(var i = 0, ci; ci = c[i]; i++){
5604                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5605                         r[++ri] = ci;
5606                     }
5607                 }
5608                 return r;
5609             },
5610
5611             "checked" : function(c){
5612                 var r = [], ri = -1;
5613                 for(var i = 0, ci; ci = c[i]; i++){
5614                     if(ci.checked == true){
5615                         r[++ri] = ci;
5616                     }
5617                 }
5618                 return r;
5619             },
5620
5621             "not" : function(c, ss){
5622                 return Roo.DomQuery.filter(c, ss, true);
5623             },
5624
5625             "odd" : function(c){
5626                 return this["nth-child"](c, "odd");
5627             },
5628
5629             "even" : function(c){
5630                 return this["nth-child"](c, "even");
5631             },
5632
5633             "nth" : function(c, a){
5634                 return c[a-1] || [];
5635             },
5636
5637             "first" : function(c){
5638                 return c[0] || [];
5639             },
5640
5641             "last" : function(c){
5642                 return c[c.length-1] || [];
5643             },
5644
5645             "has" : function(c, ss){
5646                 var s = Roo.DomQuery.select;
5647                 var r = [], ri = -1;
5648                 for(var i = 0, ci; ci = c[i]; i++){
5649                     if(s(ss, ci).length > 0){
5650                         r[++ri] = ci;
5651                     }
5652                 }
5653                 return r;
5654             },
5655
5656             "next" : function(c, ss){
5657                 var is = Roo.DomQuery.is;
5658                 var r = [], ri = -1;
5659                 for(var i = 0, ci; ci = c[i]; i++){
5660                     var n = next(ci);
5661                     if(n && is(n, ss)){
5662                         r[++ri] = ci;
5663                     }
5664                 }
5665                 return r;
5666             },
5667
5668             "prev" : function(c, ss){
5669                 var is = Roo.DomQuery.is;
5670                 var r = [], ri = -1;
5671                 for(var i = 0, ci; ci = c[i]; i++){
5672                     var n = prev(ci);
5673                     if(n && is(n, ss)){
5674                         r[++ri] = ci;
5675                     }
5676                 }
5677                 return r;
5678             }
5679         }
5680     };
5681 }();
5682
5683 /**
5684  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5685  * @param {String} path The selector/xpath query
5686  * @param {Node} root (optional) The start of the query (defaults to document).
5687  * @return {Array}
5688  * @member Roo
5689  * @method query
5690  */
5691 Roo.query = Roo.DomQuery.select;
5692 /*
5693  * Based on:
5694  * Ext JS Library 1.1.1
5695  * Copyright(c) 2006-2007, Ext JS, LLC.
5696  *
5697  * Originally Released Under LGPL - original licence link has changed is not relivant.
5698  *
5699  * Fork - LGPL
5700  * <script type="text/javascript">
5701  */
5702
5703 /**
5704  * @class Roo.util.Observable
5705  * Base class that provides a common interface for publishing events. Subclasses are expected to
5706  * to have a property "events" with all the events defined.<br>
5707  * For example:
5708  * <pre><code>
5709  Employee = function(name){
5710     this.name = name;
5711     this.addEvents({
5712         "fired" : true,
5713         "quit" : true
5714     });
5715  }
5716  Roo.extend(Employee, Roo.util.Observable);
5717 </code></pre>
5718  * @param {Object} config properties to use (incuding events / listeners)
5719  */
5720
5721 Roo.util.Observable = function(cfg){
5722     
5723     cfg = cfg|| {};
5724     this.addEvents(cfg.events || {});
5725     if (cfg.events) {
5726         delete cfg.events; // make sure
5727     }
5728      
5729     Roo.apply(this, cfg);
5730     
5731     if(this.listeners){
5732         this.on(this.listeners);
5733         delete this.listeners;
5734     }
5735 };
5736 Roo.util.Observable.prototype = {
5737     /** 
5738  * @cfg {Object} listeners  list of events and functions to call for this object, 
5739  * For example :
5740  * <pre><code>
5741     listeners :  { 
5742        'click' : function(e) {
5743            ..... 
5744         } ,
5745         .... 
5746     } 
5747   </code></pre>
5748  */
5749     
5750     
5751     /**
5752      * Fires the specified event with the passed parameters (minus the event name).
5753      * @param {String} eventName
5754      * @param {Object...} args Variable number of parameters are passed to handlers
5755      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5756      */
5757     fireEvent : function(){
5758         var ce = this.events[arguments[0].toLowerCase()];
5759         if(typeof ce == "object"){
5760             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761         }else{
5762             return true;
5763         }
5764     },
5765
5766     // private
5767     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5768
5769     /**
5770      * Appends an event handler to this component
5771      * @param {String}   eventName The type of event to listen for
5772      * @param {Function} handler The method the event invokes
5773      * @param {Object}   scope (optional) The scope in which to execute the handler
5774      * function. The handler function's "this" context.
5775      * @param {Object}   options (optional) An object containing handler configuration
5776      * properties. This may contain any of the following properties:<ul>
5777      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5778      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5779      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5780      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5781      * by the specified number of milliseconds. If the event fires again within that time, the original
5782      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5783      * </ul><br>
5784      * <p>
5785      * <b>Combining Options</b><br>
5786      * Using the options argument, it is possible to combine different types of listeners:<br>
5787      * <br>
5788      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5789                 <pre><code>
5790                 el.on('click', this.onClick, this, {
5791                         single: true,
5792                 delay: 100,
5793                 forumId: 4
5794                 });
5795                 </code></pre>
5796      * <p>
5797      * <b>Attaching multiple handlers in 1 call</b><br>
5798      * The method also allows for a single argument to be passed which is a config object containing properties
5799      * which specify multiple handlers.
5800      * <pre><code>
5801                 el.on({
5802                         'click': {
5803                         fn: this.onClick,
5804                         scope: this,
5805                         delay: 100
5806                 }, 
5807                 'mouseover': {
5808                         fn: this.onMouseOver,
5809                         scope: this
5810                 },
5811                 'mouseout': {
5812                         fn: this.onMouseOut,
5813                         scope: this
5814                 }
5815                 });
5816                 </code></pre>
5817      * <p>
5818      * Or a shorthand syntax which passes the same scope object to all handlers:
5819         <pre><code>
5820                 el.on({
5821                         'click': this.onClick,
5822                 'mouseover': this.onMouseOver,
5823                 'mouseout': this.onMouseOut,
5824                 scope: this
5825                 });
5826                 </code></pre>
5827      */
5828     addListener : function(eventName, fn, scope, o){
5829         if(typeof eventName == "object"){
5830             o = eventName;
5831             for(var e in o){
5832                 if(this.filterOptRe.test(e)){
5833                     continue;
5834                 }
5835                 if(typeof o[e] == "function"){
5836                     // shared options
5837                     this.addListener(e, o[e], o.scope,  o);
5838                 }else{
5839                     // individual options
5840                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5841                 }
5842             }
5843             return;
5844         }
5845         o = (!o || typeof o == "boolean") ? {} : o;
5846         eventName = eventName.toLowerCase();
5847         var ce = this.events[eventName] || true;
5848         if(typeof ce == "boolean"){
5849             ce = new Roo.util.Event(this, eventName);
5850             this.events[eventName] = ce;
5851         }
5852         ce.addListener(fn, scope, o);
5853     },
5854
5855     /**
5856      * Removes a listener
5857      * @param {String}   eventName     The type of event to listen for
5858      * @param {Function} handler        The handler to remove
5859      * @param {Object}   scope  (optional) The scope (this object) for the handler
5860      */
5861     removeListener : function(eventName, fn, scope){
5862         var ce = this.events[eventName.toLowerCase()];
5863         if(typeof ce == "object"){
5864             ce.removeListener(fn, scope);
5865         }
5866     },
5867
5868     /**
5869      * Removes all listeners for this object
5870      */
5871     purgeListeners : function(){
5872         for(var evt in this.events){
5873             if(typeof this.events[evt] == "object"){
5874                  this.events[evt].clearListeners();
5875             }
5876         }
5877     },
5878
5879     relayEvents : function(o, events){
5880         var createHandler = function(ename){
5881             return function(){
5882                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5883             };
5884         };
5885         for(var i = 0, len = events.length; i < len; i++){
5886             var ename = events[i];
5887             if(!this.events[ename]){ this.events[ename] = true; };
5888             o.on(ename, createHandler(ename), this);
5889         }
5890     },
5891
5892     /**
5893      * Used to define events on this Observable
5894      * @param {Object} object The object with the events defined
5895      */
5896     addEvents : function(o){
5897         if(!this.events){
5898             this.events = {};
5899         }
5900         Roo.applyIf(this.events, o);
5901     },
5902
5903     /**
5904      * Checks to see if this object has any listeners for a specified event
5905      * @param {String} eventName The name of the event to check for
5906      * @return {Boolean} True if the event is being listened for, else false
5907      */
5908     hasListener : function(eventName){
5909         var e = this.events[eventName];
5910         return typeof e == "object" && e.listeners.length > 0;
5911     }
5912 };
5913 /**
5914  * Appends an event handler to this element (shorthand for addListener)
5915  * @param {String}   eventName     The type of event to listen for
5916  * @param {Function} handler        The method the event invokes
5917  * @param {Object}   scope (optional) The scope in which to execute the handler
5918  * function. The handler function's "this" context.
5919  * @param {Object}   options  (optional)
5920  * @method
5921  */
5922 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5923 /**
5924  * Removes a listener (shorthand for removeListener)
5925  * @param {String}   eventName     The type of event to listen for
5926  * @param {Function} handler        The handler to remove
5927  * @param {Object}   scope  (optional) The scope (this object) for the handler
5928  * @method
5929  */
5930 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5931
5932 /**
5933  * Starts capture on the specified Observable. All events will be passed
5934  * to the supplied function with the event name + standard signature of the event
5935  * <b>before</b> the event is fired. If the supplied function returns false,
5936  * the event will not fire.
5937  * @param {Observable} o The Observable to capture
5938  * @param {Function} fn The function to call
5939  * @param {Object} scope (optional) The scope (this object) for the fn
5940  * @static
5941  */
5942 Roo.util.Observable.capture = function(o, fn, scope){
5943     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5944 };
5945
5946 /**
5947  * Removes <b>all</b> added captures from the Observable.
5948  * @param {Observable} o The Observable to release
5949  * @static
5950  */
5951 Roo.util.Observable.releaseCapture = function(o){
5952     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5953 };
5954
5955 (function(){
5956
5957     var createBuffered = function(h, o, scope){
5958         var task = new Roo.util.DelayedTask();
5959         return function(){
5960             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5961         };
5962     };
5963
5964     var createSingle = function(h, e, fn, scope){
5965         return function(){
5966             e.removeListener(fn, scope);
5967             return h.apply(scope, arguments);
5968         };
5969     };
5970
5971     var createDelayed = function(h, o, scope){
5972         return function(){
5973             var args = Array.prototype.slice.call(arguments, 0);
5974             setTimeout(function(){
5975                 h.apply(scope, args);
5976             }, o.delay || 10);
5977         };
5978     };
5979
5980     Roo.util.Event = function(obj, name){
5981         this.name = name;
5982         this.obj = obj;
5983         this.listeners = [];
5984     };
5985
5986     Roo.util.Event.prototype = {
5987         addListener : function(fn, scope, options){
5988             var o = options || {};
5989             scope = scope || this.obj;
5990             if(!this.isListening(fn, scope)){
5991                 var l = {fn: fn, scope: scope, options: o};
5992                 var h = fn;
5993                 if(o.delay){
5994                     h = createDelayed(h, o, scope);
5995                 }
5996                 if(o.single){
5997                     h = createSingle(h, this, fn, scope);
5998                 }
5999                 if(o.buffer){
6000                     h = createBuffered(h, o, scope);
6001                 }
6002                 l.fireFn = h;
6003                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6004                     this.listeners.push(l);
6005                 }else{
6006                     this.listeners = this.listeners.slice(0);
6007                     this.listeners.push(l);
6008                 }
6009             }
6010         },
6011
6012         findListener : function(fn, scope){
6013             scope = scope || this.obj;
6014             var ls = this.listeners;
6015             for(var i = 0, len = ls.length; i < len; i++){
6016                 var l = ls[i];
6017                 if(l.fn == fn && l.scope == scope){
6018                     return i;
6019                 }
6020             }
6021             return -1;
6022         },
6023
6024         isListening : function(fn, scope){
6025             return this.findListener(fn, scope) != -1;
6026         },
6027
6028         removeListener : function(fn, scope){
6029             var index;
6030             if((index = this.findListener(fn, scope)) != -1){
6031                 if(!this.firing){
6032                     this.listeners.splice(index, 1);
6033                 }else{
6034                     this.listeners = this.listeners.slice(0);
6035                     this.listeners.splice(index, 1);
6036                 }
6037                 return true;
6038             }
6039             return false;
6040         },
6041
6042         clearListeners : function(){
6043             this.listeners = [];
6044         },
6045
6046         fire : function(){
6047             var ls = this.listeners, scope, len = ls.length;
6048             if(len > 0){
6049                 this.firing = true;
6050                 var args = Array.prototype.slice.call(arguments, 0);
6051                 for(var i = 0; i < len; i++){
6052                     var l = ls[i];
6053                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6054                         this.firing = false;
6055                         return false;
6056                     }
6057                 }
6058                 this.firing = false;
6059             }
6060             return true;
6061         }
6062     };
6063 })();/*
6064  * RooJS Library 
6065  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066  *
6067  * Licence LGPL 
6068  *
6069  */
6070  
6071 /**
6072  * @class Roo.Document
6073  * @extends Roo.util.Observable
6074  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6075  * 
6076  * @param {Object} config the methods and properties of the 'base' class for the application.
6077  * 
6078  *  Generic Page handler - implement this to start your app..
6079  * 
6080  * eg.
6081  *  MyProject = new Roo.Document({
6082         events : {
6083             'load' : true // your events..
6084         },
6085         listeners : {
6086             'ready' : function() {
6087                 // fired on Roo.onReady()
6088             }
6089         }
6090  * 
6091  */
6092 Roo.Document = function(cfg) {
6093      
6094     this.addEvents({ 
6095         'ready' : true
6096     });
6097     Roo.util.Observable.call(this,cfg);
6098     
6099     var _this = this;
6100     
6101     Roo.onReady(function() {
6102         _this.fireEvent('ready');
6103     },null,false);
6104     
6105     
6106 }
6107
6108 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6109  * Based on:
6110  * Ext JS Library 1.1.1
6111  * Copyright(c) 2006-2007, Ext JS, LLC.
6112  *
6113  * Originally Released Under LGPL - original licence link has changed is not relivant.
6114  *
6115  * Fork - LGPL
6116  * <script type="text/javascript">
6117  */
6118
6119 /**
6120  * @class Roo.EventManager
6121  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6122  * several useful events directly.
6123  * See {@link Roo.EventObject} for more details on normalized event objects.
6124  * @singleton
6125  */
6126 Roo.EventManager = function(){
6127     var docReadyEvent, docReadyProcId, docReadyState = false;
6128     var resizeEvent, resizeTask, textEvent, textSize;
6129     var E = Roo.lib.Event;
6130     var D = Roo.lib.Dom;
6131
6132     
6133     
6134
6135     var fireDocReady = function(){
6136         if(!docReadyState){
6137             docReadyState = true;
6138             Roo.isReady = true;
6139             if(docReadyProcId){
6140                 clearInterval(docReadyProcId);
6141             }
6142             if(Roo.isGecko || Roo.isOpera) {
6143                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6144             }
6145             if(Roo.isIE){
6146                 var defer = document.getElementById("ie-deferred-loader");
6147                 if(defer){
6148                     defer.onreadystatechange = null;
6149                     defer.parentNode.removeChild(defer);
6150                 }
6151             }
6152             if(docReadyEvent){
6153                 docReadyEvent.fire();
6154                 docReadyEvent.clearListeners();
6155             }
6156         }
6157     };
6158     
6159     var initDocReady = function(){
6160         docReadyEvent = new Roo.util.Event();
6161         if(Roo.isGecko || Roo.isOpera) {
6162             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6163         }else if(Roo.isIE){
6164             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6165             var defer = document.getElementById("ie-deferred-loader");
6166             defer.onreadystatechange = function(){
6167                 if(this.readyState == "complete"){
6168                     fireDocReady();
6169                 }
6170             };
6171         }else if(Roo.isSafari){ 
6172             docReadyProcId = setInterval(function(){
6173                 var rs = document.readyState;
6174                 if(rs == "complete") {
6175                     fireDocReady();     
6176                  }
6177             }, 10);
6178         }
6179         // no matter what, make sure it fires on load
6180         E.on(window, "load", fireDocReady);
6181     };
6182
6183     var createBuffered = function(h, o){
6184         var task = new Roo.util.DelayedTask(h);
6185         return function(e){
6186             // create new event object impl so new events don't wipe out properties
6187             e = new Roo.EventObjectImpl(e);
6188             task.delay(o.buffer, h, null, [e]);
6189         };
6190     };
6191
6192     var createSingle = function(h, el, ename, fn){
6193         return function(e){
6194             Roo.EventManager.removeListener(el, ename, fn);
6195             h(e);
6196         };
6197     };
6198
6199     var createDelayed = function(h, o){
6200         return function(e){
6201             // create new event object impl so new events don't wipe out properties
6202             e = new Roo.EventObjectImpl(e);
6203             setTimeout(function(){
6204                 h(e);
6205             }, o.delay || 10);
6206         };
6207     };
6208     var transitionEndVal = false;
6209     
6210     var transitionEnd = function()
6211     {
6212         if (transitionEndVal) {
6213             return transitionEndVal;
6214         }
6215         var el = document.createElement('div');
6216
6217         var transEndEventNames = {
6218             WebkitTransition : 'webkitTransitionEnd',
6219             MozTransition    : 'transitionend',
6220             OTransition      : 'oTransitionEnd otransitionend',
6221             transition       : 'transitionend'
6222         };
6223     
6224         for (var name in transEndEventNames) {
6225             if (el.style[name] !== undefined) {
6226                 transitionEndVal = transEndEventNames[name];
6227                 return  transitionEndVal ;
6228             }
6229         }
6230     }
6231     
6232
6233     var listen = function(element, ename, opt, fn, scope){
6234         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6235         fn = fn || o.fn; scope = scope || o.scope;
6236         var el = Roo.getDom(element);
6237         
6238         
6239         if(!el){
6240             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6241         }
6242         
6243         if (ename == 'transitionend') {
6244             ename = transitionEnd();
6245         }
6246         var h = function(e){
6247             e = Roo.EventObject.setEvent(e);
6248             var t;
6249             if(o.delegate){
6250                 t = e.getTarget(o.delegate, el);
6251                 if(!t){
6252                     return;
6253                 }
6254             }else{
6255                 t = e.target;
6256             }
6257             if(o.stopEvent === true){
6258                 e.stopEvent();
6259             }
6260             if(o.preventDefault === true){
6261                e.preventDefault();
6262             }
6263             if(o.stopPropagation === true){
6264                 e.stopPropagation();
6265             }
6266
6267             if(o.normalized === false){
6268                 e = e.browserEvent;
6269             }
6270
6271             fn.call(scope || el, e, t, o);
6272         };
6273         if(o.delay){
6274             h = createDelayed(h, o);
6275         }
6276         if(o.single){
6277             h = createSingle(h, el, ename, fn);
6278         }
6279         if(o.buffer){
6280             h = createBuffered(h, o);
6281         }
6282         fn._handlers = fn._handlers || [];
6283         
6284         
6285         fn._handlers.push([Roo.id(el), ename, h]);
6286         
6287         
6288          
6289         E.on(el, ename, h);
6290         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6291             el.addEventListener("DOMMouseScroll", h, false);
6292             E.on(window, 'unload', function(){
6293                 el.removeEventListener("DOMMouseScroll", h, false);
6294             });
6295         }
6296         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6297             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6298         }
6299         return h;
6300     };
6301
6302     var stopListening = function(el, ename, fn){
6303         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6304         if(hds){
6305             for(var i = 0, len = hds.length; i < len; i++){
6306                 var h = hds[i];
6307                 if(h[0] == id && h[1] == ename){
6308                     hd = h[2];
6309                     hds.splice(i, 1);
6310                     break;
6311                 }
6312             }
6313         }
6314         E.un(el, ename, hd);
6315         el = Roo.getDom(el);
6316         if(ename == "mousewheel" && el.addEventListener){
6317             el.removeEventListener("DOMMouseScroll", hd, false);
6318         }
6319         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6320             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6321         }
6322     };
6323
6324     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325     
6326     var pub = {
6327         
6328         
6329         /** 
6330          * Fix for doc tools
6331          * @scope Roo.EventManager
6332          */
6333         
6334         
6335         /** 
6336          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6337          * object with a Roo.EventObject
6338          * @param {Function} fn        The method the event invokes
6339          * @param {Object}   scope    An object that becomes the scope of the handler
6340          * @param {boolean}  override If true, the obj passed in becomes
6341          *                             the execution scope of the listener
6342          * @return {Function} The wrapped function
6343          * @deprecated
6344          */
6345         wrap : function(fn, scope, override){
6346             return function(e){
6347                 Roo.EventObject.setEvent(e);
6348                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6349             };
6350         },
6351         
6352         /**
6353      * Appends an event handler to an element (shorthand for addListener)
6354      * @param {String/HTMLElement}   element        The html element or id to assign the
6355      * @param {String}   eventName The type of event to listen for
6356      * @param {Function} handler The method the event invokes
6357      * @param {Object}   scope (optional) The scope in which to execute the handler
6358      * function. The handler function's "this" context.
6359      * @param {Object}   options (optional) An object containing handler configuration
6360      * properties. This may contain any of the following properties:<ul>
6361      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6362      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6363      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6364      * <li>preventDefault {Boolean} True to prevent the default action</li>
6365      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6366      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6367      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6368      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6369      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6370      * by the specified number of milliseconds. If the event fires again within that time, the original
6371      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6372      * </ul><br>
6373      * <p>
6374      * <b>Combining Options</b><br>
6375      * Using the options argument, it is possible to combine different types of listeners:<br>
6376      * <br>
6377      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6378      * Code:<pre><code>
6379 el.on('click', this.onClick, this, {
6380     single: true,
6381     delay: 100,
6382     stopEvent : true,
6383     forumId: 4
6384 });</code></pre>
6385      * <p>
6386      * <b>Attaching multiple handlers in 1 call</b><br>
6387       * The method also allows for a single argument to be passed which is a config object containing properties
6388      * which specify multiple handlers.
6389      * <p>
6390      * Code:<pre><code>
6391 el.on({
6392     'click' : {
6393         fn: this.onClick
6394         scope: this,
6395         delay: 100
6396     },
6397     'mouseover' : {
6398         fn: this.onMouseOver
6399         scope: this
6400     },
6401     'mouseout' : {
6402         fn: this.onMouseOut
6403         scope: this
6404     }
6405 });</code></pre>
6406      * <p>
6407      * Or a shorthand syntax:<br>
6408      * Code:<pre><code>
6409 el.on({
6410     'click' : this.onClick,
6411     'mouseover' : this.onMouseOver,
6412     'mouseout' : this.onMouseOut
6413     scope: this
6414 });</code></pre>
6415      */
6416         addListener : function(element, eventName, fn, scope, options){
6417             if(typeof eventName == "object"){
6418                 var o = eventName;
6419                 for(var e in o){
6420                     if(propRe.test(e)){
6421                         continue;
6422                     }
6423                     if(typeof o[e] == "function"){
6424                         // shared options
6425                         listen(element, e, o, o[e], o.scope);
6426                     }else{
6427                         // individual options
6428                         listen(element, e, o[e]);
6429                     }
6430                 }
6431                 return;
6432             }
6433             return listen(element, eventName, options, fn, scope);
6434         },
6435         
6436         /**
6437          * Removes an event handler
6438          *
6439          * @param {String/HTMLElement}   element        The id or html element to remove the 
6440          *                             event from
6441          * @param {String}   eventName     The type of event
6442          * @param {Function} fn
6443          * @return {Boolean} True if a listener was actually removed
6444          */
6445         removeListener : function(element, eventName, fn){
6446             return stopListening(element, eventName, fn);
6447         },
6448         
6449         /**
6450          * Fires when the document is ready (before onload and before images are loaded). Can be 
6451          * accessed shorthanded Roo.onReady().
6452          * @param {Function} fn        The method the event invokes
6453          * @param {Object}   scope    An  object that becomes the scope of the handler
6454          * @param {boolean}  options
6455          */
6456         onDocumentReady : function(fn, scope, options){
6457             if(docReadyState){ // if it already fired
6458                 docReadyEvent.addListener(fn, scope, options);
6459                 docReadyEvent.fire();
6460                 docReadyEvent.clearListeners();
6461                 return;
6462             }
6463             if(!docReadyEvent){
6464                 initDocReady();
6465             }
6466             docReadyEvent.addListener(fn, scope, options);
6467         },
6468         
6469         /**
6470          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6471          * @param {Function} fn        The method the event invokes
6472          * @param {Object}   scope    An object that becomes the scope of the handler
6473          * @param {boolean}  options
6474          */
6475         onWindowResize : function(fn, scope, options){
6476             if(!resizeEvent){
6477                 resizeEvent = new Roo.util.Event();
6478                 resizeTask = new Roo.util.DelayedTask(function(){
6479                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6480                 });
6481                 E.on(window, "resize", function(){
6482                     if(Roo.isIE){
6483                         resizeTask.delay(50);
6484                     }else{
6485                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6486                     }
6487                 });
6488             }
6489             resizeEvent.addListener(fn, scope, options);
6490         },
6491
6492         /**
6493          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6494          * @param {Function} fn        The method the event invokes
6495          * @param {Object}   scope    An object that becomes the scope of the handler
6496          * @param {boolean}  options
6497          */
6498         onTextResize : function(fn, scope, options){
6499             if(!textEvent){
6500                 textEvent = new Roo.util.Event();
6501                 var textEl = new Roo.Element(document.createElement('div'));
6502                 textEl.dom.className = 'x-text-resize';
6503                 textEl.dom.innerHTML = 'X';
6504                 textEl.appendTo(document.body);
6505                 textSize = textEl.dom.offsetHeight;
6506                 setInterval(function(){
6507                     if(textEl.dom.offsetHeight != textSize){
6508                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6509                     }
6510                 }, this.textResizeInterval);
6511             }
6512             textEvent.addListener(fn, scope, options);
6513         },
6514
6515         /**
6516          * Removes the passed window resize listener.
6517          * @param {Function} fn        The method the event invokes
6518          * @param {Object}   scope    The scope of handler
6519          */
6520         removeResizeListener : function(fn, scope){
6521             if(resizeEvent){
6522                 resizeEvent.removeListener(fn, scope);
6523             }
6524         },
6525
6526         // private
6527         fireResize : function(){
6528             if(resizeEvent){
6529                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6530             }   
6531         },
6532         /**
6533          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6534          */
6535         ieDeferSrc : false,
6536         /**
6537          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6538          */
6539         textResizeInterval : 50
6540     };
6541     
6542     /**
6543      * Fix for doc tools
6544      * @scopeAlias pub=Roo.EventManager
6545      */
6546     
6547      /**
6548      * Appends an event handler to an element (shorthand for addListener)
6549      * @param {String/HTMLElement}   element        The html element or id to assign the
6550      * @param {String}   eventName The type of event to listen for
6551      * @param {Function} handler The method the event invokes
6552      * @param {Object}   scope (optional) The scope in which to execute the handler
6553      * function. The handler function's "this" context.
6554      * @param {Object}   options (optional) An object containing handler configuration
6555      * properties. This may contain any of the following properties:<ul>
6556      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6557      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6558      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6559      * <li>preventDefault {Boolean} True to prevent the default action</li>
6560      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6561      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6562      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6563      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6564      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6565      * by the specified number of milliseconds. If the event fires again within that time, the original
6566      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6567      * </ul><br>
6568      * <p>
6569      * <b>Combining Options</b><br>
6570      * Using the options argument, it is possible to combine different types of listeners:<br>
6571      * <br>
6572      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6573      * Code:<pre><code>
6574 el.on('click', this.onClick, this, {
6575     single: true,
6576     delay: 100,
6577     stopEvent : true,
6578     forumId: 4
6579 });</code></pre>
6580      * <p>
6581      * <b>Attaching multiple handlers in 1 call</b><br>
6582       * The method also allows for a single argument to be passed which is a config object containing properties
6583      * which specify multiple handlers.
6584      * <p>
6585      * Code:<pre><code>
6586 el.on({
6587     'click' : {
6588         fn: this.onClick
6589         scope: this,
6590         delay: 100
6591     },
6592     'mouseover' : {
6593         fn: this.onMouseOver
6594         scope: this
6595     },
6596     'mouseout' : {
6597         fn: this.onMouseOut
6598         scope: this
6599     }
6600 });</code></pre>
6601      * <p>
6602      * Or a shorthand syntax:<br>
6603      * Code:<pre><code>
6604 el.on({
6605     'click' : this.onClick,
6606     'mouseover' : this.onMouseOver,
6607     'mouseout' : this.onMouseOut
6608     scope: this
6609 });</code></pre>
6610      */
6611     pub.on = pub.addListener;
6612     pub.un = pub.removeListener;
6613
6614     pub.stoppedMouseDownEvent = new Roo.util.Event();
6615     return pub;
6616 }();
6617 /**
6618   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6619   * @param {Function} fn        The method the event invokes
6620   * @param {Object}   scope    An  object that becomes the scope of the handler
6621   * @param {boolean}  override If true, the obj passed in becomes
6622   *                             the execution scope of the listener
6623   * @member Roo
6624   * @method onReady
6625  */
6626 Roo.onReady = Roo.EventManager.onDocumentReady;
6627
6628 Roo.onReady(function(){
6629     var bd = Roo.get(document.body);
6630     if(!bd){ return; }
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 });