roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     console.log('-------ua---------');
54     console.log(ua);
55
56     var isStrict = document.compatMode == "CSS1Compat",
57         isOpera = ua.indexOf("opera") > -1,
58         isSafari = (/webkit|khtml/).test(ua),
59         isFirefox = ua.indexOf("firefox") > -1,
60         isIE = ua.indexOf("msie") > -1,
61         isIE7 = ua.indexOf("msie 7") > -1,
62         isIE11 = /trident.*rv\:11\./.test(ua),
63         isEdge = ua.indexOf("edge") > -1,
64         isGecko = !isSafari && ua.indexOf("gecko") > -1,
65         isBorderBox = isIE && !isStrict,
66         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
67         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
68         isLinux = (ua.indexOf("linux") != -1),
69         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
70         isIOS = /iphone|ipad/.test(ua),
71         isAndroid = /android/.test(ua),
72         isTouch =  (function() {
73             try {
74                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
75                     window.addEventListener('touchstart', function __set_has_touch__ () {
76                         Roo.isTouch = true;
77                         window.removeEventListener('touchstart', __set_has_touch__);
78                     });
79                     return false; // no touch on chrome!?
80                 }
81                 document.createEvent("TouchEvent");  
82                 return true;  
83             } catch (e) {  
84                 return false;  
85             } 
86             
87         })();
88     // remove css image flicker
89         if(isIE && !isIE7){
90         try{
91             document.execCommand("BackgroundImageCache", false, true);
92         }catch(e){}
93     }
94     
95     Roo.apply(Roo, {
96         /**
97          * True if the browser is in strict mode
98          * @type Boolean
99          */
100         isStrict : isStrict,
101         /**
102          * True if the page is running over SSL
103          * @type Boolean
104          */
105         isSecure : isSecure,
106         /**
107          * True when the document is fully initialized and ready for action
108          * @type Boolean
109          */
110         isReady : false,
111         /**
112          * Turn on debugging output (currently only the factory uses this)
113          * @type Boolean
114          */
115         
116         debug: false,
117
118         /**
119          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
120          * @type Boolean
121          */
122         enableGarbageCollector : true,
123
124         /**
125          * True to automatically purge event listeners after uncaching an element (defaults to false).
126          * Note: this only happens if enableGarbageCollector is true.
127          * @type Boolean
128          */
129         enableListenerCollection:false,
130
131         /**
132          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
133          * the IE insecure content warning (defaults to javascript:false).
134          * @type String
135          */
136         SSL_SECURE_URL : "javascript:false",
137
138         /**
139          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
140          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
141          * @type String
142          */
143         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
144
145         emptyFn : function(){},
146         
147         /**
148          * Copies all the properties of config to obj if they don't already exist.
149          * @param {Object} obj The receiver of the properties
150          * @param {Object} config The source of the properties
151          * @return {Object} returns obj
152          */
153         applyIf : function(o, c){
154             if(o && c){
155                 for(var p in c){
156                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
157                 }
158             }
159             return o;
160         },
161
162         /**
163          * Applies event listeners to elements by selectors when the document is ready.
164          * The event name is specified with an @ suffix.
165 <pre><code>
166 Roo.addBehaviors({
167    // add a listener for click on all anchors in element with id foo
168    '#foo a@click' : function(e, t){
169        // do something
170    },
171
172    // add the same listener to multiple selectors (separated by comma BEFORE the @)
173    '#foo a, #bar span.some-class@mouseover' : function(){
174        // do something
175    }
176 });
177 </code></pre>
178          * @param {Object} obj The list of behaviors to apply
179          */
180         addBehaviors : function(o){
181             if(!Roo.isReady){
182                 Roo.onReady(function(){
183                     Roo.addBehaviors(o);
184                 });
185                 return;
186             }
187             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
188             for(var b in o){
189                 var parts = b.split('@');
190                 if(parts[1]){ // for Object prototype breakers
191                     var s = parts[0];
192                     if(!cache[s]){
193                         cache[s] = Roo.select(s);
194                     }
195                     cache[s].on(parts[1], o[b]);
196                 }
197             }
198             cache = null;
199         },
200
201         /**
202          * Generates unique ids. If the element already has an id, it is unchanged
203          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
204          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
205          * @return {String} The generated Id.
206          */
207         id : function(el, prefix){
208             prefix = prefix || "roo-gen";
209             el = Roo.getDom(el);
210             var id = prefix + (++idSeed);
211             return el ? (el.id ? el.id : (el.id = id)) : id;
212         },
213          
214        
215         /**
216          * Extends one class with another class and optionally overrides members with the passed literal. This class
217          * also adds the function "override()" to the class that can be used to override
218          * members on an instance.
219          * @param {Object} subclass The class inheriting the functionality
220          * @param {Object} superclass The class being extended
221          * @param {Object} overrides (optional) A literal with members
222          * @method extend
223          */
224         extend : function(){
225             // inline overrides
226             var io = function(o){
227                 for(var m in o){
228                     this[m] = o[m];
229                 }
230             };
231             return function(sb, sp, overrides){
232                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
233                     overrides = sp;
234                     sp = sb;
235                     sb = function(){sp.apply(this, arguments);};
236                 }
237                 var F = function(){}, sbp, spp = sp.prototype;
238                 F.prototype = spp;
239                 sbp = sb.prototype = new F();
240                 sbp.constructor=sb;
241                 sb.superclass=spp;
242                 
243                 if(spp.constructor == Object.prototype.constructor){
244                     spp.constructor=sp;
245                    
246                 }
247                 
248                 sb.override = function(o){
249                     Roo.override(sb, o);
250                 };
251                 sbp.override = io;
252                 Roo.override(sb, overrides);
253                 return sb;
254             };
255         }(),
256
257         /**
258          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
259          * Usage:<pre><code>
260 Roo.override(MyClass, {
261     newMethod1: function(){
262         // etc.
263     },
264     newMethod2: function(foo){
265         // etc.
266     }
267 });
268  </code></pre>
269          * @param {Object} origclass The class to override
270          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
271          * containing one or more methods.
272          * @method override
273          */
274         override : function(origclass, overrides){
275             if(overrides){
276                 var p = origclass.prototype;
277                 for(var method in overrides){
278                     p[method] = overrides[method];
279                 }
280             }
281         },
282         /**
283          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
284          * <pre><code>
285 Roo.namespace('Company', 'Company.data');
286 Company.Widget = function() { ... }
287 Company.data.CustomStore = function(config) { ... }
288 </code></pre>
289          * @param {String} namespace1
290          * @param {String} namespace2
291          * @param {String} etc
292          * @method namespace
293          */
294         namespace : function(){
295             var a=arguments, o=null, i, j, d, rt;
296             for (i=0; i<a.length; ++i) {
297                 d=a[i].split(".");
298                 rt = d[0];
299                 /** eval:var:o */
300                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
301                 for (j=1; j<d.length; ++j) {
302                     o[d[j]]=o[d[j]] || {};
303                     o=o[d[j]];
304                 }
305             }
306         },
307         /**
308          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
309          * <pre><code>
310 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
311 Roo.factory(conf, Roo.data);
312 </code></pre>
313          * @param {String} classname
314          * @param {String} namespace (optional)
315          * @method factory
316          */
317          
318         factory : function(c, ns)
319         {
320             // no xtype, no ns or c.xns - or forced off by c.xns
321             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
322                 return c;
323             }
324             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
325             if (c.constructor == ns[c.xtype]) {// already created...
326                 return c;
327             }
328             if (ns[c.xtype]) {
329                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
330                 var ret = new ns[c.xtype](c);
331                 ret.xns = false;
332                 return ret;
333             }
334             c.xns = false; // prevent recursion..
335             return c;
336         },
337          /**
338          * Logs to console if it can.
339          *
340          * @param {String|Object} string
341          * @method log
342          */
343         log : function(s)
344         {
345             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
346                 return; // alerT?
347             }
348             console.log(s);
349             
350         },
351         /**
352          * 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.
353          * @param {Object} o
354          * @return {String}
355          */
356         urlEncode : function(o){
357             if(!o){
358                 return "";
359             }
360             var buf = [];
361             for(var key in o){
362                 var ov = o[key], k = Roo.encodeURIComponent(key);
363                 var type = typeof ov;
364                 if(type == 'undefined'){
365                     buf.push(k, "=&");
366                 }else if(type != "function" && type != "object"){
367                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
368                 }else if(ov instanceof Array){
369                     if (ov.length) {
370                             for(var i = 0, len = ov.length; i < len; i++) {
371                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
372                             }
373                         } else {
374                             buf.push(k, "=&");
375                         }
376                 }
377             }
378             buf.pop();
379             return buf.join("");
380         },
381          /**
382          * Safe version of encodeURIComponent
383          * @param {String} data 
384          * @return {String} 
385          */
386         
387         encodeURIComponent : function (data)
388         {
389             try {
390                 return encodeURIComponent(data);
391             } catch(e) {} // should be an uri encode error.
392             
393             if (data == '' || data == null){
394                return '';
395             }
396             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
397             function nibble_to_hex(nibble){
398                 var chars = '0123456789ABCDEF';
399                 return chars.charAt(nibble);
400             }
401             data = data.toString();
402             var buffer = '';
403             for(var i=0; i<data.length; i++){
404                 var c = data.charCodeAt(i);
405                 var bs = new Array();
406                 if (c > 0x10000){
407                         // 4 bytes
408                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
409                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
410                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
411                     bs[3] = 0x80 | (c & 0x3F);
412                 }else if (c > 0x800){
413                          // 3 bytes
414                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
415                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
416                     bs[2] = 0x80 | (c & 0x3F);
417                 }else if (c > 0x80){
418                        // 2 bytes
419                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
420                     bs[1] = 0x80 | (c & 0x3F);
421                 }else{
422                         // 1 byte
423                     bs[0] = c;
424                 }
425                 for(var j=0; j<bs.length; j++){
426                     var b = bs[j];
427                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
428                             + nibble_to_hex(b &0x0F);
429                     buffer += '%'+hex;
430                }
431             }
432             return buffer;    
433              
434         },
435
436         /**
437          * 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]}.
438          * @param {String} string
439          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
440          * @return {Object} A literal with members
441          */
442         urlDecode : function(string, overwrite){
443             if(!string || !string.length){
444                 return {};
445             }
446             var obj = {};
447             var pairs = string.split('&');
448             var pair, name, value;
449             for(var i = 0, len = pairs.length; i < len; i++){
450                 pair = pairs[i].split('=');
451                 name = decodeURIComponent(pair[0]);
452                 value = decodeURIComponent(pair[1]);
453                 if(overwrite !== true){
454                     if(typeof obj[name] == "undefined"){
455                         obj[name] = value;
456                     }else if(typeof obj[name] == "string"){
457                         obj[name] = [obj[name]];
458                         obj[name].push(value);
459                     }else{
460                         obj[name].push(value);
461                     }
462                 }else{
463                     obj[name] = value;
464                 }
465             }
466             return obj;
467         },
468
469         /**
470          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
471          * passed array is not really an array, your function is called once with it.
472          * The supplied function is called with (Object item, Number index, Array allItems).
473          * @param {Array/NodeList/Mixed} array
474          * @param {Function} fn
475          * @param {Object} scope
476          */
477         each : function(array, fn, scope){
478             if(typeof array.length == "undefined" || typeof array == "string"){
479                 array = [array];
480             }
481             for(var i = 0, len = array.length; i < len; i++){
482                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
483             }
484         },
485
486         // deprecated
487         combine : function(){
488             var as = arguments, l = as.length, r = [];
489             for(var i = 0; i < l; i++){
490                 var a = as[i];
491                 if(a instanceof Array){
492                     r = r.concat(a);
493                 }else if(a.length !== undefined && !a.substr){
494                     r = r.concat(Array.prototype.slice.call(a, 0));
495                 }else{
496                     r.push(a);
497                 }
498             }
499             return r;
500         },
501
502         /**
503          * Escapes the passed string for use in a regular expression
504          * @param {String} str
505          * @return {String}
506          */
507         escapeRe : function(s) {
508             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509         },
510
511         // internal
512         callback : function(cb, scope, args, delay){
513             if(typeof cb == "function"){
514                 if(delay){
515                     cb.defer(delay, scope, args || []);
516                 }else{
517                     cb.apply(scope, args || []);
518                 }
519             }
520         },
521
522         /**
523          * Return the dom node for the passed string (id), dom node, or Roo.Element
524          * @param {String/HTMLElement/Roo.Element} el
525          * @return HTMLElement
526          */
527         getDom : function(el){
528             if(!el){
529                 return null;
530             }
531             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532         },
533
534         /**
535         * Shorthand for {@link Roo.ComponentMgr#get}
536         * @param {String} id
537         * @return Roo.Component
538         */
539         getCmp : function(id){
540             return Roo.ComponentMgr.get(id);
541         },
542          
543         num : function(v, defaultValue){
544             if(typeof v != 'number'){
545                 return defaultValue;
546             }
547             return v;
548         },
549
550         destroy : function(){
551             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552                 var as = a[i];
553                 if(as){
554                     if(as.dom){
555                         as.removeAllListeners();
556                         as.remove();
557                         continue;
558                     }
559                     if(typeof as.purgeListeners == 'function'){
560                         as.purgeListeners();
561                     }
562                     if(typeof as.destroy == 'function'){
563                         as.destroy();
564                     }
565                 }
566             }
567         },
568
569         // inpired by a similar function in mootools library
570         /**
571          * Returns the type of object that is passed in. If the object passed in is null or undefined it
572          * return false otherwise it returns one of the following values:<ul>
573          * <li><b>string</b>: If the object passed is a string</li>
574          * <li><b>number</b>: If the object passed is a number</li>
575          * <li><b>boolean</b>: If the object passed is a boolean value</li>
576          * <li><b>function</b>: If the object passed is a function reference</li>
577          * <li><b>object</b>: If the object passed is an object</li>
578          * <li><b>array</b>: If the object passed is an array</li>
579          * <li><b>regexp</b>: If the object passed is a regular expression</li>
580          * <li><b>element</b>: If the object passed is a DOM Element</li>
581          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
582          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
583          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
584          * @param {Mixed} object
585          * @return {String}
586          */
587         type : function(o){
588             if(o === undefined || o === null){
589                 return false;
590             }
591             if(o.htmlElement){
592                 return 'element';
593             }
594             var t = typeof o;
595             if(t == 'object' && o.nodeName) {
596                 switch(o.nodeType) {
597                     case 1: return 'element';
598                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
599                 }
600             }
601             if(t == 'object' || t == 'function') {
602                 switch(o.constructor) {
603                     case Array: return 'array';
604                     case RegExp: return 'regexp';
605                 }
606                 if(typeof o.length == 'number' && typeof o.item == 'function') {
607                     return 'nodelist';
608                 }
609             }
610             return t;
611         },
612
613         /**
614          * Returns true if the passed value is null, undefined or an empty string (optional).
615          * @param {Mixed} value The value to test
616          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
617          * @return {Boolean}
618          */
619         isEmpty : function(v, allowBlank){
620             return v === null || v === undefined || (!allowBlank ? v === '' : false);
621         },
622         
623         /** @type Boolean */
624         isOpera : isOpera,
625         /** @type Boolean */
626         isSafari : isSafari,
627         /** @type Boolean */
628         isFirefox : isFirefox,
629         /** @type Boolean */
630         isIE : isIE,
631         /** @type Boolean */
632         isIE7 : isIE7,
633         /** @type Boolean */
634         isIE11 : isIE11,
635         /** @type Boolean */
636         isGecko : isGecko,
637         /** @type Boolean */
638         isBorderBox : isBorderBox,
639         /** @type Boolean */
640         isWindows : isWindows,
641         /** @type Boolean */
642         isLinux : isLinux,
643         /** @type Boolean */
644         isMac : isMac,
645         /** @type Boolean */
646         isIOS : isIOS,
647         /** @type Boolean */
648         isAndroid : isAndroid,
649         /** @type Boolean */
650         isTouch : isTouch,
651
652         /**
653          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
654          * you may want to set this to true.
655          * @type Boolean
656          */
657         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
658         
659         
660                 
661         /**
662          * Selects a single element as a Roo Element
663          * This is about as close as you can get to jQuery's $('do crazy stuff')
664          * @param {String} selector The selector/xpath query
665          * @param {Node} root (optional) The start of the query (defaults to document).
666          * @return {Roo.Element}
667          */
668         selectNode : function(selector, root) 
669         {
670             var node = Roo.DomQuery.selectNode(selector,root);
671             return node ? Roo.get(node) : new Roo.Element(false);
672         }
673         
674     });
675
676
677 })();
678
679 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
680                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
681                 "Roo.app", "Roo.ux",
682                 "Roo.bootstrap",
683                 "Roo.bootstrap.dash");
684 /*
685  * Based on:
686  * Ext JS Library 1.1.1
687  * Copyright(c) 2006-2007, Ext JS, LLC.
688  *
689  * Originally Released Under LGPL - original licence link has changed is not relivant.
690  *
691  * Fork - LGPL
692  * <script type="text/javascript">
693  */
694
695 (function() {    
696     // wrappedn so fnCleanup is not in global scope...
697     if(Roo.isIE) {
698         function fnCleanUp() {
699             var p = Function.prototype;
700             delete p.createSequence;
701             delete p.defer;
702             delete p.createDelegate;
703             delete p.createCallback;
704             delete p.createInterceptor;
705
706             window.detachEvent("onunload", fnCleanUp);
707         }
708         window.attachEvent("onunload", fnCleanUp);
709     }
710 })();
711
712
713 /**
714  * @class Function
715  * These functions are available on every Function object (any JavaScript function).
716  */
717 Roo.apply(Function.prototype, {
718      /**
719      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
720      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
721      * Will create a function that is bound to those 2 args.
722      * @return {Function} The new function
723     */
724     createCallback : function(/*args...*/){
725         // make args available, in function below
726         var args = arguments;
727         var method = this;
728         return function() {
729             return method.apply(window, args);
730         };
731     },
732
733     /**
734      * Creates a delegate (callback) that sets the scope to obj.
735      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
736      * Will create a function that is automatically scoped to this.
737      * @param {Object} obj (optional) The object for which the scope is set
738      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
739      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
740      *                                             if a number the args are inserted at the specified position
741      * @return {Function} The new function
742      */
743     createDelegate : function(obj, args, appendArgs){
744         var method = this;
745         return function() {
746             var callArgs = args || arguments;
747             if(appendArgs === true){
748                 callArgs = Array.prototype.slice.call(arguments, 0);
749                 callArgs = callArgs.concat(args);
750             }else if(typeof appendArgs == "number"){
751                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
752                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
753                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754             }
755             return method.apply(obj || window, callArgs);
756         };
757     },
758
759     /**
760      * Calls this function after the number of millseconds specified.
761      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
762      * @param {Object} obj (optional) The object for which the scope is set
763      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
764      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
765      *                                             if a number the args are inserted at the specified position
766      * @return {Number} The timeout id that can be used with clearTimeout
767      */
768     defer : function(millis, obj, args, appendArgs){
769         var fn = this.createDelegate(obj, args, appendArgs);
770         if(millis){
771             return setTimeout(fn, millis);
772         }
773         fn();
774         return 0;
775     },
776     /**
777      * Create a combined function call sequence of the original function + the passed function.
778      * The resulting function returns the results of the original function.
779      * The passed fcn is called with the parameters of the original function
780      * @param {Function} fcn The function to sequence
781      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
782      * @return {Function} The new function
783      */
784     createSequence : function(fcn, scope){
785         if(typeof fcn != "function"){
786             return this;
787         }
788         var method = this;
789         return function() {
790             var retval = method.apply(this || window, arguments);
791             fcn.apply(scope || this || window, arguments);
792             return retval;
793         };
794     },
795
796     /**
797      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
798      * The resulting function returns the results of the original function.
799      * The passed fcn is called with the parameters of the original function.
800      * @addon
801      * @param {Function} fcn The function to call before the original
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createInterceptor : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             fcn.target = this;
812             fcn.method = method;
813             if(fcn.apply(scope || this || window, arguments) === false){
814                 return;
815             }
816             return method.apply(this || window, arguments);
817         };
818     }
819 });
820 /*
821  * Based on:
822  * Ext JS Library 1.1.1
823  * Copyright(c) 2006-2007, Ext JS, LLC.
824  *
825  * Originally Released Under LGPL - original licence link has changed is not relivant.
826  *
827  * Fork - LGPL
828  * <script type="text/javascript">
829  */
830
831 Roo.applyIf(String, {
832     
833     /** @scope String */
834     
835     /**
836      * Escapes the passed string for ' and \
837      * @param {String} string The string to escape
838      * @return {String} The escaped string
839      * @static
840      */
841     escape : function(string) {
842         return string.replace(/('|\\)/g, "\\$1");
843     },
844
845     /**
846      * Pads the left side of a string with a specified character.  This is especially useful
847      * for normalizing number and date strings.  Example usage:
848      * <pre><code>
849 var s = String.leftPad('123', 5, '0');
850 // s now contains the string: '00123'
851 </code></pre>
852      * @param {String} string The original string
853      * @param {Number} size The total length of the output string
854      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
855      * @return {String} The padded string
856      * @static
857      */
858     leftPad : function (val, size, ch) {
859         var result = new String(val);
860         if(ch === null || ch === undefined || ch === '') {
861             ch = " ";
862         }
863         while (result.length < size) {
864             result = ch + result;
865         }
866         return result;
867     },
868
869     /**
870      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
871      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
872      * <pre><code>
873 var cls = 'my-class', text = 'Some text';
874 var s = String.format('<div class="{0}">{1}</div>', cls, text);
875 // s now contains the string: '<div class="my-class">Some text</div>'
876 </code></pre>
877      * @param {String} string The tokenized string to be formatted
878      * @param {String} value1 The value to replace token {0}
879      * @param {String} value2 Etc...
880      * @return {String} The formatted string
881      * @static
882      */
883     format : function(format){
884         var args = Array.prototype.slice.call(arguments, 1);
885         return format.replace(/\{(\d+)\}/g, function(m, i){
886             return Roo.util.Format.htmlEncode(args[i]);
887         });
888     }
889 });
890
891 /**
892  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
893  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
894  * they are already different, the first value passed in is returned.  Note that this method returns the new value
895  * but does not change the current string.
896  * <pre><code>
897 // alternate sort directions
898 sort = sort.toggle('ASC', 'DESC');
899
900 // instead of conditional logic:
901 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
902 </code></pre>
903  * @param {String} value The value to compare to the current string
904  * @param {String} other The new value to use if the string already equals the first value passed in
905  * @return {String} The new value
906  */
907  
908 String.prototype.toggle = function(value, other){
909     return this == value ? other : value;
910 };/*
911  * Based on:
912  * Ext JS Library 1.1.1
913  * Copyright(c) 2006-2007, Ext JS, LLC.
914  *
915  * Originally Released Under LGPL - original licence link has changed is not relivant.
916  *
917  * Fork - LGPL
918  * <script type="text/javascript">
919  */
920
921  /**
922  * @class Number
923  */
924 Roo.applyIf(Number.prototype, {
925     /**
926      * Checks whether or not the current number is within a desired range.  If the number is already within the
927      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
928      * exceeded.  Note that this method returns the constrained value but does not change the current number.
929      * @param {Number} min The minimum number in the range
930      * @param {Number} max The maximum number in the range
931      * @return {Number} The constrained value if outside the range, otherwise the current value
932      */
933     constrain : function(min, max){
934         return Math.min(Math.max(this, min), max);
935     }
936 });/*
937  * Based on:
938  * Ext JS Library 1.1.1
939  * Copyright(c) 2006-2007, Ext JS, LLC.
940  *
941  * Originally Released Under LGPL - original licence link has changed is not relivant.
942  *
943  * Fork - LGPL
944  * <script type="text/javascript">
945  */
946  /**
947  * @class Array
948  */
949 Roo.applyIf(Array.prototype, {
950     /**
951      * 
952      * Checks whether or not the specified object exists in the array.
953      * @param {Object} o The object to check for
954      * @return {Number} The index of o in the array (or -1 if it is not found)
955      */
956     indexOf : function(o){
957        for (var i = 0, len = this.length; i < len; i++){
958               if(this[i] == o) { return i; }
959        }
960            return -1;
961     },
962
963     /**
964      * Removes the specified object from the array.  If the object is not found nothing happens.
965      * @param {Object} o The object to remove
966      */
967     remove : function(o){
968        var index = this.indexOf(o);
969        if(index != -1){
970            this.splice(index, 1);
971        }
972     },
973     /**
974      * Map (JS 1.6 compatibility)
975      * @param {Function} function  to call
976      */
977     map : function(fun )
978     {
979         var len = this.length >>> 0;
980         if (typeof fun != "function") {
981             throw new TypeError();
982         }
983         var res = new Array(len);
984         var thisp = arguments[1];
985         for (var i = 0; i < len; i++)
986         {
987             if (i in this) {
988                 res[i] = fun.call(thisp, this[i], i, this);
989             }
990         }
991
992         return res;
993     }
994     
995 });
996
997
998  
999 /*
1000  * Based on:
1001  * Ext JS Library 1.1.1
1002  * Copyright(c) 2006-2007, Ext JS, LLC.
1003  *
1004  * Originally Released Under LGPL - original licence link has changed is not relivant.
1005  *
1006  * Fork - LGPL
1007  * <script type="text/javascript">
1008  */
1009
1010 /**
1011  * @class Date
1012  *
1013  * The date parsing and format syntax is a subset of
1014  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1015  * supported will provide results equivalent to their PHP versions.
1016  *
1017  * Following is the list of all currently supported formats:
1018  *<pre>
1019 Sample date:
1020 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1021
1022 Format  Output      Description
1023 ------  ----------  --------------------------------------------------------------
1024   d      10         Day of the month, 2 digits with leading zeros
1025   D      Wed        A textual representation of a day, three letters
1026   j      10         Day of the month without leading zeros
1027   l      Wednesday  A full textual representation of the day of the week
1028   S      th         English ordinal day of month suffix, 2 chars (use with j)
1029   w      3          Numeric representation of the day of the week
1030   z      9          The julian date, or day of the year (0-365)
1031   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1032   F      January    A full textual representation of the month
1033   m      01         Numeric representation of a month, with leading zeros
1034   M      Jan        Month name abbreviation, three letters
1035   n      1          Numeric representation of a month, without leading zeros
1036   t      31         Number of days in the given month
1037   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1038   Y      2007       A full numeric representation of a year, 4 digits
1039   y      07         A two digit representation of a year
1040   a      pm         Lowercase Ante meridiem and Post meridiem
1041   A      PM         Uppercase Ante meridiem and Post meridiem
1042   g      3          12-hour format of an hour without leading zeros
1043   G      15         24-hour format of an hour without leading zeros
1044   h      03         12-hour format of an hour with leading zeros
1045   H      15         24-hour format of an hour with leading zeros
1046   i      05         Minutes with leading zeros
1047   s      01         Seconds, with leading zeros
1048   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1049   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1050   T      CST        Timezone setting of the machine running the code
1051   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1052 </pre>
1053  *
1054  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1055  * <pre><code>
1056 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1057 document.write(dt.format('Y-m-d'));                         //2007-01-10
1058 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1059 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
1060  </code></pre>
1061  *
1062  * Here are some standard date/time patterns that you might find helpful.  They
1063  * are not part of the source of Date.js, but to use them you can simply copy this
1064  * block of code into any script that is included after Date.js and they will also become
1065  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1066  * <pre><code>
1067 Date.patterns = {
1068     ISO8601Long:"Y-m-d H:i:s",
1069     ISO8601Short:"Y-m-d",
1070     ShortDate: "n/j/Y",
1071     LongDate: "l, F d, Y",
1072     FullDateTime: "l, F d, Y g:i:s A",
1073     MonthDay: "F d",
1074     ShortTime: "g:i A",
1075     LongTime: "g:i:s A",
1076     SortableDateTime: "Y-m-d\\TH:i:s",
1077     UniversalSortableDateTime: "Y-m-d H:i:sO",
1078     YearMonth: "F, Y"
1079 };
1080 </code></pre>
1081  *
1082  * Example usage:
1083  * <pre><code>
1084 var dt = new Date();
1085 document.write(dt.format(Date.patterns.ShortDate));
1086  </code></pre>
1087  */
1088
1089 /*
1090  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1091  * They generate precompiled functions from date formats instead of parsing and
1092  * processing the pattern every time you format a date.  These functions are available
1093  * on every Date object (any javascript function).
1094  *
1095  * The original article and download are here:
1096  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1097  *
1098  */
1099  
1100  
1101  // was in core
1102 /**
1103  Returns the number of milliseconds between this date and date
1104  @param {Date} date (optional) Defaults to now
1105  @return {Number} The diff in milliseconds
1106  @member Date getElapsed
1107  */
1108 Date.prototype.getElapsed = function(date) {
1109         return Math.abs((date || new Date()).getTime()-this.getTime());
1110 };
1111 // was in date file..
1112
1113
1114 // private
1115 Date.parseFunctions = {count:0};
1116 // private
1117 Date.parseRegexes = [];
1118 // private
1119 Date.formatFunctions = {count:0};
1120
1121 // private
1122 Date.prototype.dateFormat = function(format) {
1123     if (Date.formatFunctions[format] == null) {
1124         Date.createNewFormat(format);
1125     }
1126     var func = Date.formatFunctions[format];
1127     return this[func]();
1128 };
1129
1130
1131 /**
1132  * Formats a date given the supplied format string
1133  * @param {String} format The format string
1134  * @return {String} The formatted date
1135  * @method
1136  */
1137 Date.prototype.format = Date.prototype.dateFormat;
1138
1139 // private
1140 Date.createNewFormat = function(format) {
1141     var funcName = "format" + Date.formatFunctions.count++;
1142     Date.formatFunctions[format] = funcName;
1143     var code = "Date.prototype." + funcName + " = function(){return ";
1144     var special = false;
1145     var ch = '';
1146     for (var i = 0; i < format.length; ++i) {
1147         ch = format.charAt(i);
1148         if (!special && ch == "\\") {
1149             special = true;
1150         }
1151         else if (special) {
1152             special = false;
1153             code += "'" + String.escape(ch) + "' + ";
1154         }
1155         else {
1156             code += Date.getFormatCode(ch);
1157         }
1158     }
1159     /** eval:var:zzzzzzzzzzzzz */
1160     eval(code.substring(0, code.length - 3) + ";}");
1161 };
1162
1163 // private
1164 Date.getFormatCode = function(character) {
1165     switch (character) {
1166     case "d":
1167         return "String.leftPad(this.getDate(), 2, '0') + ";
1168     case "D":
1169         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1170     case "j":
1171         return "this.getDate() + ";
1172     case "l":
1173         return "Date.dayNames[this.getDay()] + ";
1174     case "S":
1175         return "this.getSuffix() + ";
1176     case "w":
1177         return "this.getDay() + ";
1178     case "z":
1179         return "this.getDayOfYear() + ";
1180     case "W":
1181         return "this.getWeekOfYear() + ";
1182     case "F":
1183         return "Date.monthNames[this.getMonth()] + ";
1184     case "m":
1185         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1186     case "M":
1187         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1188     case "n":
1189         return "(this.getMonth() + 1) + ";
1190     case "t":
1191         return "this.getDaysInMonth() + ";
1192     case "L":
1193         return "(this.isLeapYear() ? 1 : 0) + ";
1194     case "Y":
1195         return "this.getFullYear() + ";
1196     case "y":
1197         return "('' + this.getFullYear()).substring(2, 4) + ";
1198     case "a":
1199         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1200     case "A":
1201         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1202     case "g":
1203         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1204     case "G":
1205         return "this.getHours() + ";
1206     case "h":
1207         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1208     case "H":
1209         return "String.leftPad(this.getHours(), 2, '0') + ";
1210     case "i":
1211         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1212     case "s":
1213         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1214     case "O":
1215         return "this.getGMTOffset() + ";
1216     case "P":
1217         return "this.getGMTColonOffset() + ";
1218     case "T":
1219         return "this.getTimezone() + ";
1220     case "Z":
1221         return "(this.getTimezoneOffset() * -60) + ";
1222     default:
1223         return "'" + String.escape(character) + "' + ";
1224     }
1225 };
1226
1227 /**
1228  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1229  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1230  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1231  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1232  * string or the parse operation will fail.
1233  * Example Usage:
1234 <pre><code>
1235 //dt = Fri May 25 2007 (current date)
1236 var dt = new Date();
1237
1238 //dt = Thu May 25 2006 (today's month/day in 2006)
1239 dt = Date.parseDate("2006", "Y");
1240
1241 //dt = Sun Jan 15 2006 (all date parts specified)
1242 dt = Date.parseDate("2006-1-15", "Y-m-d");
1243
1244 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1245 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1246 </code></pre>
1247  * @param {String} input The unparsed date as a string
1248  * @param {String} format The format the date is in
1249  * @return {Date} The parsed date
1250  * @static
1251  */
1252 Date.parseDate = function(input, format) {
1253     if (Date.parseFunctions[format] == null) {
1254         Date.createParser(format);
1255     }
1256     var func = Date.parseFunctions[format];
1257     return Date[func](input);
1258 };
1259 /**
1260  * @private
1261  */
1262
1263 Date.createParser = function(format) {
1264     var funcName = "parse" + Date.parseFunctions.count++;
1265     var regexNum = Date.parseRegexes.length;
1266     var currentGroup = 1;
1267     Date.parseFunctions[format] = funcName;
1268
1269     var code = "Date." + funcName + " = function(input){\n"
1270         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1271         + "var d = new Date();\n"
1272         + "y = d.getFullYear();\n"
1273         + "m = d.getMonth();\n"
1274         + "d = d.getDate();\n"
1275         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1276         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1277         + "if (results && results.length > 0) {";
1278     var regex = "";
1279
1280     var special = false;
1281     var ch = '';
1282     for (var i = 0; i < format.length; ++i) {
1283         ch = format.charAt(i);
1284         if (!special && ch == "\\") {
1285             special = true;
1286         }
1287         else if (special) {
1288             special = false;
1289             regex += String.escape(ch);
1290         }
1291         else {
1292             var obj = Date.formatCodeToRegex(ch, currentGroup);
1293             currentGroup += obj.g;
1294             regex += obj.s;
1295             if (obj.g && obj.c) {
1296                 code += obj.c;
1297             }
1298         }
1299     }
1300
1301     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1302         + "{v = new Date(y, m, d, h, i, s);}\n"
1303         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1304         + "{v = new Date(y, m, d, h, i);}\n"
1305         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1306         + "{v = new Date(y, m, d, h);}\n"
1307         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1308         + "{v = new Date(y, m, d);}\n"
1309         + "else if (y >= 0 && m >= 0)\n"
1310         + "{v = new Date(y, m);}\n"
1311         + "else if (y >= 0)\n"
1312         + "{v = new Date(y);}\n"
1313         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1314         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1315         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1316         + ";}";
1317
1318     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1319     /** eval:var:zzzzzzzzzzzzz */
1320     eval(code);
1321 };
1322
1323 // private
1324 Date.formatCodeToRegex = function(character, currentGroup) {
1325     switch (character) {
1326     case "D":
1327         return {g:0,
1328         c:null,
1329         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1330     case "j":
1331         return {g:1,
1332             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1333             s:"(\\d{1,2})"}; // day of month without leading zeroes
1334     case "d":
1335         return {g:1,
1336             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1337             s:"(\\d{2})"}; // day of month with leading zeroes
1338     case "l":
1339         return {g:0,
1340             c:null,
1341             s:"(?:" + Date.dayNames.join("|") + ")"};
1342     case "S":
1343         return {g:0,
1344             c:null,
1345             s:"(?:st|nd|rd|th)"};
1346     case "w":
1347         return {g:0,
1348             c:null,
1349             s:"\\d"};
1350     case "z":
1351         return {g:0,
1352             c:null,
1353             s:"(?:\\d{1,3})"};
1354     case "W":
1355         return {g:0,
1356             c:null,
1357             s:"(?:\\d{2})"};
1358     case "F":
1359         return {g:1,
1360             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1361             s:"(" + Date.monthNames.join("|") + ")"};
1362     case "M":
1363         return {g:1,
1364             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1365             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1366     case "n":
1367         return {g:1,
1368             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1369             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1370     case "m":
1371         return {g:1,
1372             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1373             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1374     case "t":
1375         return {g:0,
1376             c:null,
1377             s:"\\d{1,2}"};
1378     case "L":
1379         return {g:0,
1380             c:null,
1381             s:"(?:1|0)"};
1382     case "Y":
1383         return {g:1,
1384             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{4})"};
1386     case "y":
1387         return {g:1,
1388             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1389                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1390             s:"(\\d{1,2})"};
1391     case "a":
1392         return {g:1,
1393             c:"if (results[" + currentGroup + "] == 'am') {\n"
1394                 + "if (h == 12) { h = 0; }\n"
1395                 + "} else { if (h < 12) { h += 12; }}",
1396             s:"(am|pm)"};
1397     case "A":
1398         return {g:1,
1399             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1400                 + "if (h == 12) { h = 0; }\n"
1401                 + "} else { if (h < 12) { h += 12; }}",
1402             s:"(AM|PM)"};
1403     case "g":
1404     case "G":
1405         return {g:1,
1406             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1407             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1408     case "h":
1409     case "H":
1410         return {g:1,
1411             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1412             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1413     case "i":
1414         return {g:1,
1415             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1416             s:"(\\d{2})"};
1417     case "s":
1418         return {g:1,
1419             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1420             s:"(\\d{2})"};
1421     case "O":
1422         return {g:1,
1423             c:[
1424                 "o = results[", currentGroup, "];\n",
1425                 "var sn = o.substring(0,1);\n", // get + / - sign
1426                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1427                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1428                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1429                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1430             ].join(""),
1431             s:"([+\-]\\d{2,4})"};
1432     
1433     
1434     case "P":
1435         return {g:1,
1436                 c:[
1437                    "o = results[", currentGroup, "];\n",
1438                    "var sn = o.substring(0,1);\n",
1439                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1440                    "var mn = o.substring(4,6) % 60;\n",
1441                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1442                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1443             ].join(""),
1444             s:"([+\-]\\d{4})"};
1445     case "T":
1446         return {g:0,
1447             c:null,
1448             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1449     case "Z":
1450         return {g:1,
1451             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1452                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1453             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1454     default:
1455         return {g:0,
1456             c:null,
1457             s:String.escape(character)};
1458     }
1459 };
1460
1461 /**
1462  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1463  * @return {String} The abbreviated timezone name (e.g. 'CST')
1464  */
1465 Date.prototype.getTimezone = function() {
1466     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1467 };
1468
1469 /**
1470  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1471  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1472  */
1473 Date.prototype.getGMTOffset = function() {
1474     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1475         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1476         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1477 };
1478
1479 /**
1480  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1481  * @return {String} 2-characters representing hours and 2-characters representing minutes
1482  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1483  */
1484 Date.prototype.getGMTColonOffset = function() {
1485         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1486                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1487                 + ":"
1488                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1489 }
1490
1491 /**
1492  * Get the numeric day number of the year, adjusted for leap year.
1493  * @return {Number} 0 through 364 (365 in leap years)
1494  */
1495 Date.prototype.getDayOfYear = function() {
1496     var num = 0;
1497     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1498     for (var i = 0; i < this.getMonth(); ++i) {
1499         num += Date.daysInMonth[i];
1500     }
1501     return num + this.getDate() - 1;
1502 };
1503
1504 /**
1505  * Get the string representation of the numeric week number of the year
1506  * (equivalent to the format specifier 'W').
1507  * @return {String} '00' through '52'
1508  */
1509 Date.prototype.getWeekOfYear = function() {
1510     // Skip to Thursday of this week
1511     var now = this.getDayOfYear() + (4 - this.getDay());
1512     // Find the first Thursday of the year
1513     var jan1 = new Date(this.getFullYear(), 0, 1);
1514     var then = (7 - jan1.getDay() + 4);
1515     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1516 };
1517
1518 /**
1519  * Whether or not the current date is in a leap year.
1520  * @return {Boolean} True if the current date is in a leap year, else false
1521  */
1522 Date.prototype.isLeapYear = function() {
1523     var year = this.getFullYear();
1524     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1525 };
1526
1527 /**
1528  * Get the first day of the current month, adjusted for leap year.  The returned value
1529  * is the numeric day index within the week (0-6) which can be used in conjunction with
1530  * the {@link #monthNames} array to retrieve the textual day name.
1531  * Example:
1532  *<pre><code>
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1535 </code></pre>
1536  * @return {Number} The day number (0-6)
1537  */
1538 Date.prototype.getFirstDayOfMonth = function() {
1539     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1540     return (day < 0) ? (day + 7) : day;
1541 };
1542
1543 /**
1544  * Get the last day of the current month, adjusted for leap year.  The returned value
1545  * is the numeric day index within the week (0-6) which can be used in conjunction with
1546  * the {@link #monthNames} array to retrieve the textual day name.
1547  * Example:
1548  *<pre><code>
1549 var dt = new Date('1/10/2007');
1550 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1551 </code></pre>
1552  * @return {Number} The day number (0-6)
1553  */
1554 Date.prototype.getLastDayOfMonth = function() {
1555     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1556     return (day < 0) ? (day + 7) : day;
1557 };
1558
1559
1560 /**
1561  * Get the first date of this date's month
1562  * @return {Date}
1563  */
1564 Date.prototype.getFirstDateOfMonth = function() {
1565     return new Date(this.getFullYear(), this.getMonth(), 1);
1566 };
1567
1568 /**
1569  * Get the last date of this date's month
1570  * @return {Date}
1571  */
1572 Date.prototype.getLastDateOfMonth = function() {
1573     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1574 };
1575 /**
1576  * Get the number of days in the current month, adjusted for leap year.
1577  * @return {Number} The number of days in the month
1578  */
1579 Date.prototype.getDaysInMonth = function() {
1580     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1581     return Date.daysInMonth[this.getMonth()];
1582 };
1583
1584 /**
1585  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1586  * @return {String} 'st, 'nd', 'rd' or 'th'
1587  */
1588 Date.prototype.getSuffix = function() {
1589     switch (this.getDate()) {
1590         case 1:
1591         case 21:
1592         case 31:
1593             return "st";
1594         case 2:
1595         case 22:
1596             return "nd";
1597         case 3:
1598         case 23:
1599             return "rd";
1600         default:
1601             return "th";
1602     }
1603 };
1604
1605 // private
1606 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1607
1608 /**
1609  * An array of textual month names.
1610  * Override these values for international dates, for example...
1611  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1612  * @type Array
1613  * @static
1614  */
1615 Date.monthNames =
1616    ["January",
1617     "February",
1618     "March",
1619     "April",
1620     "May",
1621     "June",
1622     "July",
1623     "August",
1624     "September",
1625     "October",
1626     "November",
1627     "December"];
1628
1629 /**
1630  * An array of textual day names.
1631  * Override these values for international dates, for example...
1632  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1633  * @type Array
1634  * @static
1635  */
1636 Date.dayNames =
1637    ["Sunday",
1638     "Monday",
1639     "Tuesday",
1640     "Wednesday",
1641     "Thursday",
1642     "Friday",
1643     "Saturday"];
1644
1645 // private
1646 Date.y2kYear = 50;
1647 // private
1648 Date.monthNumbers = {
1649     Jan:0,
1650     Feb:1,
1651     Mar:2,
1652     Apr:3,
1653     May:4,
1654     Jun:5,
1655     Jul:6,
1656     Aug:7,
1657     Sep:8,
1658     Oct:9,
1659     Nov:10,
1660     Dec:11};
1661
1662 /**
1663  * Creates and returns a new Date instance with the exact same date value as the called instance.
1664  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1665  * variable will also be changed.  When the intention is to create a new variable that will not
1666  * modify the original instance, you should create a clone.
1667  *
1668  * Example of correctly cloning a date:
1669  * <pre><code>
1670 //wrong way:
1671 var orig = new Date('10/1/2006');
1672 var copy = orig;
1673 copy.setDate(5);
1674 document.write(orig);  //returns 'Thu Oct 05 2006'!
1675
1676 //correct way:
1677 var orig = new Date('10/1/2006');
1678 var copy = orig.clone();
1679 copy.setDate(5);
1680 document.write(orig);  //returns 'Thu Oct 01 2006'
1681 </code></pre>
1682  * @return {Date} The new Date instance
1683  */
1684 Date.prototype.clone = function() {
1685         return new Date(this.getTime());
1686 };
1687
1688 /**
1689  * Clears any time information from this date
1690  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1691  @return {Date} this or the clone
1692  */
1693 Date.prototype.clearTime = function(clone){
1694     if(clone){
1695         return this.clone().clearTime();
1696     }
1697     this.setHours(0);
1698     this.setMinutes(0);
1699     this.setSeconds(0);
1700     this.setMilliseconds(0);
1701     return this;
1702 };
1703
1704 // private
1705 // safari setMonth is broken -- check that this is only donw once...
1706 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1707     Date.brokenSetMonth = Date.prototype.setMonth;
1708         Date.prototype.setMonth = function(num){
1709                 if(num <= -1){
1710                         var n = Math.ceil(-num);
1711                         var back_year = Math.ceil(n/12);
1712                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1713                         this.setFullYear(this.getFullYear() - back_year);
1714                         return Date.brokenSetMonth.call(this, month);
1715                 } else {
1716                         return Date.brokenSetMonth.apply(this, arguments);
1717                 }
1718         };
1719 }
1720
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.MILLI = "ms";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.SECOND = "s";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.MINUTE = "mi";
1733 /** Date interval constant 
1734 * @static 
1735 * @type String */
1736 Date.HOUR = "h";
1737 /** Date interval constant 
1738 * @static 
1739 * @type String */
1740 Date.DAY = "d";
1741 /** Date interval constant 
1742 * @static 
1743 * @type String */
1744 Date.MONTH = "mo";
1745 /** Date interval constant 
1746 * @static 
1747 * @type String */
1748 Date.YEAR = "y";
1749
1750 /**
1751  * Provides a convenient method of performing basic date arithmetic.  This method
1752  * does not modify the Date instance being called - it creates and returns
1753  * a new Date instance containing the resulting date value.
1754  *
1755  * Examples:
1756  * <pre><code>
1757 //Basic usage:
1758 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1759 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1760
1761 //Negative values will subtract correctly:
1762 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1763 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1764
1765 //You can even chain several calls together in one line!
1766 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1767 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1768  </code></pre>
1769  *
1770  * @param {String} interval   A valid date interval enum value
1771  * @param {Number} value      The amount to add to the current date
1772  * @return {Date} The new Date instance
1773  */
1774 Date.prototype.add = function(interval, value){
1775   var d = this.clone();
1776   if (!interval || value === 0) { return d; }
1777   switch(interval.toLowerCase()){
1778     case Date.MILLI:
1779       d.setMilliseconds(this.getMilliseconds() + value);
1780       break;
1781     case Date.SECOND:
1782       d.setSeconds(this.getSeconds() + value);
1783       break;
1784     case Date.MINUTE:
1785       d.setMinutes(this.getMinutes() + value);
1786       break;
1787     case Date.HOUR:
1788       d.setHours(this.getHours() + value);
1789       break;
1790     case Date.DAY:
1791       d.setDate(this.getDate() + value);
1792       break;
1793     case Date.MONTH:
1794       var day = this.getDate();
1795       if(day > 28){
1796           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1797       }
1798       d.setDate(day);
1799       d.setMonth(this.getMonth() + value);
1800       break;
1801     case Date.YEAR:
1802       d.setFullYear(this.getFullYear() + value);
1803       break;
1804   }
1805   return d;
1806 };
1807 /*
1808  * Based on:
1809  * Ext JS Library 1.1.1
1810  * Copyright(c) 2006-2007, Ext JS, LLC.
1811  *
1812  * Originally Released Under LGPL - original licence link has changed is not relivant.
1813  *
1814  * Fork - LGPL
1815  * <script type="text/javascript">
1816  */
1817
1818 /**
1819  * @class Roo.lib.Dom
1820  * @static
1821  * 
1822  * Dom utils (from YIU afaik)
1823  * 
1824  **/
1825 Roo.lib.Dom = {
1826     /**
1827      * Get the view width
1828      * @param {Boolean} full True will get the full document, otherwise it's the view width
1829      * @return {Number} The width
1830      */
1831      
1832     getViewWidth : function(full) {
1833         return full ? this.getDocumentWidth() : this.getViewportWidth();
1834     },
1835     /**
1836      * Get the view height
1837      * @param {Boolean} full True will get the full document, otherwise it's the view height
1838      * @return {Number} The height
1839      */
1840     getViewHeight : function(full) {
1841         return full ? this.getDocumentHeight() : this.getViewportHeight();
1842     },
1843
1844     getDocumentHeight: function() {
1845         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1846         return Math.max(scrollHeight, this.getViewportHeight());
1847     },
1848
1849     getDocumentWidth: function() {
1850         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1851         return Math.max(scrollWidth, this.getViewportWidth());
1852     },
1853
1854     getViewportHeight: function() {
1855         var height = self.innerHeight;
1856         var mode = document.compatMode;
1857
1858         if ((mode || Roo.isIE) && !Roo.isOpera) {
1859             height = (mode == "CSS1Compat") ?
1860                      document.documentElement.clientHeight :
1861                      document.body.clientHeight;
1862         }
1863
1864         return height;
1865     },
1866
1867     getViewportWidth: function() {
1868         var width = self.innerWidth;
1869         var mode = document.compatMode;
1870
1871         if (mode || Roo.isIE) {
1872             width = (mode == "CSS1Compat") ?
1873                     document.documentElement.clientWidth :
1874                     document.body.clientWidth;
1875         }
1876         return width;
1877     },
1878
1879     isAncestor : function(p, c) {
1880         p = Roo.getDom(p);
1881         c = Roo.getDom(c);
1882         if (!p || !c) {
1883             return false;
1884         }
1885
1886         if (p.contains && !Roo.isSafari) {
1887             return p.contains(c);
1888         } else if (p.compareDocumentPosition) {
1889             return !!(p.compareDocumentPosition(c) & 16);
1890         } else {
1891             var parent = c.parentNode;
1892             while (parent) {
1893                 if (parent == p) {
1894                     return true;
1895                 }
1896                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1897                     return false;
1898                 }
1899                 parent = parent.parentNode;
1900             }
1901             return false;
1902         }
1903     },
1904
1905     getRegion : function(el) {
1906         return Roo.lib.Region.getRegion(el);
1907     },
1908
1909     getY : function(el) {
1910         return this.getXY(el)[1];
1911     },
1912
1913     getX : function(el) {
1914         return this.getXY(el)[0];
1915     },
1916
1917     getXY : function(el) {
1918         var p, pe, b, scroll, bd = document.body;
1919         el = Roo.getDom(el);
1920         var fly = Roo.lib.AnimBase.fly;
1921         if (el.getBoundingClientRect) {
1922             b = el.getBoundingClientRect();
1923             scroll = fly(document).getScroll();
1924             return [b.left + scroll.left, b.top + scroll.top];
1925         }
1926         var x = 0, y = 0;
1927
1928         p = el;
1929
1930         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1931
1932         while (p) {
1933
1934             x += p.offsetLeft;
1935             y += p.offsetTop;
1936
1937             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1938                 hasAbsolute = true;
1939             }
1940
1941             if (Roo.isGecko) {
1942                 pe = fly(p);
1943
1944                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1945                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1946
1947
1948                 x += bl;
1949                 y += bt;
1950
1951
1952                 if (p != el && pe.getStyle('overflow') != 'visible') {
1953                     x += bl;
1954                     y += bt;
1955                 }
1956             }
1957             p = p.offsetParent;
1958         }
1959
1960         if (Roo.isSafari && hasAbsolute) {
1961             x -= bd.offsetLeft;
1962             y -= bd.offsetTop;
1963         }
1964
1965         if (Roo.isGecko && !hasAbsolute) {
1966             var dbd = fly(bd);
1967             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1968             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1969         }
1970
1971         p = el.parentNode;
1972         while (p && p != bd) {
1973             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1974                 x -= p.scrollLeft;
1975                 y -= p.scrollTop;
1976             }
1977             p = p.parentNode;
1978         }
1979         return [x, y];
1980     },
1981  
1982   
1983
1984
1985     setXY : function(el, xy) {
1986         el = Roo.fly(el, '_setXY');
1987         el.position();
1988         var pts = el.translatePoints(xy);
1989         if (xy[0] !== false) {
1990             el.dom.style.left = pts.left + "px";
1991         }
1992         if (xy[1] !== false) {
1993             el.dom.style.top = pts.top + "px";
1994         }
1995     },
1996
1997     setX : function(el, x) {
1998         this.setXY(el, [x, false]);
1999     },
2000
2001     setY : function(el, y) {
2002         this.setXY(el, [false, y]);
2003     }
2004 };
2005 /*
2006  * Portions of this file are based on pieces of Yahoo User Interface Library
2007  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2008  * YUI licensed under the BSD License:
2009  * http://developer.yahoo.net/yui/license.txt
2010  * <script type="text/javascript">
2011  *
2012  */
2013
2014 Roo.lib.Event = function() {
2015     var loadComplete = false;
2016     var listeners = [];
2017     var unloadListeners = [];
2018     var retryCount = 0;
2019     var onAvailStack = [];
2020     var counter = 0;
2021     var lastError = null;
2022
2023     return {
2024         POLL_RETRYS: 200,
2025         POLL_INTERVAL: 20,
2026         EL: 0,
2027         TYPE: 1,
2028         FN: 2,
2029         WFN: 3,
2030         OBJ: 3,
2031         ADJ_SCOPE: 4,
2032         _interval: null,
2033
2034         startInterval: function() {
2035             if (!this._interval) {
2036                 var self = this;
2037                 var callback = function() {
2038                     self._tryPreloadAttach();
2039                 };
2040                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2041
2042             }
2043         },
2044
2045         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2046             onAvailStack.push({ id:         p_id,
2047                 fn:         p_fn,
2048                 obj:        p_obj,
2049                 override:   p_override,
2050                 checkReady: false    });
2051
2052             retryCount = this.POLL_RETRYS;
2053             this.startInterval();
2054         },
2055
2056
2057         addListener: function(el, eventName, fn) {
2058             el = Roo.getDom(el);
2059             if (!el || !fn) {
2060                 return false;
2061             }
2062
2063             if ("unload" == eventName) {
2064                 unloadListeners[unloadListeners.length] =
2065                 [el, eventName, fn];
2066                 return true;
2067             }
2068
2069             var wrappedFn = function(e) {
2070                 return fn(Roo.lib.Event.getEvent(e));
2071             };
2072
2073             var li = [el, eventName, fn, wrappedFn];
2074
2075             var index = listeners.length;
2076             listeners[index] = li;
2077
2078             this.doAdd(el, eventName, wrappedFn, false);
2079             return true;
2080
2081         },
2082
2083
2084         removeListener: function(el, eventName, fn) {
2085             var i, len;
2086
2087             el = Roo.getDom(el);
2088
2089             if(!fn) {
2090                 return this.purgeElement(el, false, eventName);
2091             }
2092
2093
2094             if ("unload" == eventName) {
2095
2096                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2097                     var li = unloadListeners[i];
2098                     if (li &&
2099                         li[0] == el &&
2100                         li[1] == eventName &&
2101                         li[2] == fn) {
2102                         unloadListeners.splice(i, 1);
2103                         return true;
2104                     }
2105                 }
2106
2107                 return false;
2108             }
2109
2110             var cacheItem = null;
2111
2112
2113             var index = arguments[3];
2114
2115             if ("undefined" == typeof index) {
2116                 index = this._getCacheIndex(el, eventName, fn);
2117             }
2118
2119             if (index >= 0) {
2120                 cacheItem = listeners[index];
2121             }
2122
2123             if (!el || !cacheItem) {
2124                 return false;
2125             }
2126
2127             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2128
2129             delete listeners[index][this.WFN];
2130             delete listeners[index][this.FN];
2131             listeners.splice(index, 1);
2132
2133             return true;
2134
2135         },
2136
2137
2138         getTarget: function(ev, resolveTextNode) {
2139             ev = ev.browserEvent || ev;
2140             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2141             var t = ev.target || ev.srcElement;
2142             return this.resolveTextNode(t);
2143         },
2144
2145
2146         resolveTextNode: function(node) {
2147             if (Roo.isSafari && node && 3 == node.nodeType) {
2148                 return node.parentNode;
2149             } else {
2150                 return node;
2151             }
2152         },
2153
2154
2155         getPageX: function(ev) {
2156             ev = ev.browserEvent || ev;
2157             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2158             var x = ev.pageX;
2159             if (!x && 0 !== x) {
2160                 x = ev.clientX || 0;
2161
2162                 if (Roo.isIE) {
2163                     x += this.getScroll()[1];
2164                 }
2165             }
2166
2167             return x;
2168         },
2169
2170
2171         getPageY: function(ev) {
2172             ev = ev.browserEvent || ev;
2173             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2174             var y = ev.pageY;
2175             if (!y && 0 !== y) {
2176                 y = ev.clientY || 0;
2177
2178                 if (Roo.isIE) {
2179                     y += this.getScroll()[0];
2180                 }
2181             }
2182
2183
2184             return y;
2185         },
2186
2187
2188         getXY: function(ev) {
2189             ev = ev.browserEvent || ev;
2190             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2191             return [this.getPageX(ev), this.getPageY(ev)];
2192         },
2193
2194
2195         getRelatedTarget: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2198             var t = ev.relatedTarget;
2199             if (!t) {
2200                 if (ev.type == "mouseout") {
2201                     t = ev.toElement;
2202                 } else if (ev.type == "mouseover") {
2203                     t = ev.fromElement;
2204                 }
2205             }
2206
2207             return this.resolveTextNode(t);
2208         },
2209
2210
2211         getTime: function(ev) {
2212             ev = ev.browserEvent || ev;
2213             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2214             if (!ev.time) {
2215                 var t = new Date().getTime();
2216                 try {
2217                     ev.time = t;
2218                 } catch(ex) {
2219                     this.lastError = ex;
2220                     return t;
2221                 }
2222             }
2223
2224             return ev.time;
2225         },
2226
2227
2228         stopEvent: function(ev) {
2229             this.stopPropagation(ev);
2230             this.preventDefault(ev);
2231         },
2232
2233
2234         stopPropagation: function(ev) {
2235             ev = ev.browserEvent || ev;
2236             if (ev.stopPropagation) {
2237                 ev.stopPropagation();
2238             } else {
2239                 ev.cancelBubble = true;
2240             }
2241         },
2242
2243
2244         preventDefault: function(ev) {
2245             ev = ev.browserEvent || ev;
2246             if(ev.preventDefault) {
2247                 ev.preventDefault();
2248             } else {
2249                 ev.returnValue = false;
2250             }
2251         },
2252
2253
2254         getEvent: function(e) {
2255             var ev = e || window.event;
2256             if (!ev) {
2257                 var c = this.getEvent.caller;
2258                 while (c) {
2259                     ev = c.arguments[0];
2260                     if (ev && Event == ev.constructor) {
2261                         break;
2262                     }
2263                     c = c.caller;
2264                 }
2265             }
2266             return ev;
2267         },
2268
2269
2270         getCharCode: function(ev) {
2271             ev = ev.browserEvent || ev;
2272             return ev.charCode || ev.keyCode || 0;
2273         },
2274
2275
2276         _getCacheIndex: function(el, eventName, fn) {
2277             for (var i = 0,len = listeners.length; i < len; ++i) {
2278                 var li = listeners[i];
2279                 if (li &&
2280                     li[this.FN] == fn &&
2281                     li[this.EL] == el &&
2282                     li[this.TYPE] == eventName) {
2283                     return i;
2284                 }
2285             }
2286
2287             return -1;
2288         },
2289
2290
2291         elCache: {},
2292
2293
2294         getEl: function(id) {
2295             return document.getElementById(id);
2296         },
2297
2298
2299         clearCache: function() {
2300         },
2301
2302
2303         _load: function(e) {
2304             loadComplete = true;
2305             var EU = Roo.lib.Event;
2306
2307
2308             if (Roo.isIE) {
2309                 EU.doRemove(window, "load", EU._load);
2310             }
2311         },
2312
2313
2314         _tryPreloadAttach: function() {
2315
2316             if (this.locked) {
2317                 return false;
2318             }
2319
2320             this.locked = true;
2321
2322
2323             var tryAgain = !loadComplete;
2324             if (!tryAgain) {
2325                 tryAgain = (retryCount > 0);
2326             }
2327
2328
2329             var notAvail = [];
2330             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2331                 var item = onAvailStack[i];
2332                 if (item) {
2333                     var el = this.getEl(item.id);
2334
2335                     if (el) {
2336                         if (!item.checkReady ||
2337                             loadComplete ||
2338                             el.nextSibling ||
2339                             (document && document.body)) {
2340
2341                             var scope = el;
2342                             if (item.override) {
2343                                 if (item.override === true) {
2344                                     scope = item.obj;
2345                                 } else {
2346                                     scope = item.override;
2347                                 }
2348                             }
2349                             item.fn.call(scope, item.obj);
2350                             onAvailStack[i] = null;
2351                         }
2352                     } else {
2353                         notAvail.push(item);
2354                     }
2355                 }
2356             }
2357
2358             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2359
2360             if (tryAgain) {
2361
2362                 this.startInterval();
2363             } else {
2364                 clearInterval(this._interval);
2365                 this._interval = null;
2366             }
2367
2368             this.locked = false;
2369
2370             return true;
2371
2372         },
2373
2374
2375         purgeElement: function(el, recurse, eventName) {
2376             var elListeners = this.getListeners(el, eventName);
2377             if (elListeners) {
2378                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2379                     var l = elListeners[i];
2380                     this.removeListener(el, l.type, l.fn);
2381                 }
2382             }
2383
2384             if (recurse && el && el.childNodes) {
2385                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2386                     this.purgeElement(el.childNodes[i], recurse, eventName);
2387                 }
2388             }
2389         },
2390
2391
2392         getListeners: function(el, eventName) {
2393             var results = [], searchLists;
2394             if (!eventName) {
2395                 searchLists = [listeners, unloadListeners];
2396             } else if (eventName == "unload") {
2397                 searchLists = [unloadListeners];
2398             } else {
2399                 searchLists = [listeners];
2400             }
2401
2402             for (var j = 0; j < searchLists.length; ++j) {
2403                 var searchList = searchLists[j];
2404                 if (searchList && searchList.length > 0) {
2405                     for (var i = 0,len = searchList.length; i < len; ++i) {
2406                         var l = searchList[i];
2407                         if (l && l[this.EL] === el &&
2408                             (!eventName || eventName === l[this.TYPE])) {
2409                             results.push({
2410                                 type:   l[this.TYPE],
2411                                 fn:     l[this.FN],
2412                                 obj:    l[this.OBJ],
2413                                 adjust: l[this.ADJ_SCOPE],
2414                                 index:  i
2415                             });
2416                         }
2417                     }
2418                 }
2419             }
2420
2421             return (results.length) ? results : null;
2422         },
2423
2424
2425         _unload: function(e) {
2426
2427             var EU = Roo.lib.Event, i, j, l, len, index;
2428
2429             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2430                 l = unloadListeners[i];
2431                 if (l) {
2432                     var scope = window;
2433                     if (l[EU.ADJ_SCOPE]) {
2434                         if (l[EU.ADJ_SCOPE] === true) {
2435                             scope = l[EU.OBJ];
2436                         } else {
2437                             scope = l[EU.ADJ_SCOPE];
2438                         }
2439                     }
2440                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2441                     unloadListeners[i] = null;
2442                     l = null;
2443                     scope = null;
2444                 }
2445             }
2446
2447             unloadListeners = null;
2448
2449             if (listeners && listeners.length > 0) {
2450                 j = listeners.length;
2451                 while (j) {
2452                     index = j - 1;
2453                     l = listeners[index];
2454                     if (l) {
2455                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2456                                 l[EU.FN], index);
2457                     }
2458                     j = j - 1;
2459                 }
2460                 l = null;
2461
2462                 EU.clearCache();
2463             }
2464
2465             EU.doRemove(window, "unload", EU._unload);
2466
2467         },
2468
2469
2470         getScroll: function() {
2471             var dd = document.documentElement, db = document.body;
2472             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2473                 return [dd.scrollTop, dd.scrollLeft];
2474             } else if (db) {
2475                 return [db.scrollTop, db.scrollLeft];
2476             } else {
2477                 return [0, 0];
2478             }
2479         },
2480
2481
2482         doAdd: function () {
2483             if (window.addEventListener) {
2484                 return function(el, eventName, fn, capture) {
2485                     el.addEventListener(eventName, fn, (capture));
2486                 };
2487             } else if (window.attachEvent) {
2488                 return function(el, eventName, fn, capture) {
2489                     el.attachEvent("on" + eventName, fn);
2490                 };
2491             } else {
2492                 return function() {
2493                 };
2494             }
2495         }(),
2496
2497
2498         doRemove: function() {
2499             if (window.removeEventListener) {
2500                 return function (el, eventName, fn, capture) {
2501                     el.removeEventListener(eventName, fn, (capture));
2502                 };
2503             } else if (window.detachEvent) {
2504                 return function (el, eventName, fn) {
2505                     el.detachEvent("on" + eventName, fn);
2506                 };
2507             } else {
2508                 return function() {
2509                 };
2510             }
2511         }()
2512     };
2513     
2514 }();
2515 (function() {     
2516    
2517     var E = Roo.lib.Event;
2518     E.on = E.addListener;
2519     E.un = E.removeListener;
2520
2521     if (document && document.body) {
2522         E._load();
2523     } else {
2524         E.doAdd(window, "load", E._load);
2525     }
2526     E.doAdd(window, "unload", E._unload);
2527     E._tryPreloadAttach();
2528 })();
2529
2530 /*
2531  * Portions of this file are based on pieces of Yahoo User Interface Library
2532  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2533  * YUI licensed under the BSD License:
2534  * http://developer.yahoo.net/yui/license.txt
2535  * <script type="text/javascript">
2536  *
2537  */
2538
2539 (function() {
2540     /**
2541      * @class Roo.lib.Ajax
2542      *
2543      */
2544     Roo.lib.Ajax = {
2545         /**
2546          * @static 
2547          */
2548         request : function(method, uri, cb, data, options) {
2549             if(options){
2550                 var hs = options.headers;
2551                 if(hs){
2552                     for(var h in hs){
2553                         if(hs.hasOwnProperty(h)){
2554                             this.initHeader(h, hs[h], false);
2555                         }
2556                     }
2557                 }
2558                 if(options.xmlData){
2559                     this.initHeader('Content-Type', 'text/xml', false);
2560                     method = 'POST';
2561                     data = options.xmlData;
2562                 }
2563             }
2564
2565             return this.asyncRequest(method, uri, cb, data);
2566         },
2567
2568         serializeForm : function(form) {
2569             if(typeof form == 'string') {
2570                 form = (document.getElementById(form) || document.forms[form]);
2571             }
2572
2573             var el, name, val, disabled, data = '', hasSubmit = false;
2574             for (var i = 0; i < form.elements.length; i++) {
2575                 el = form.elements[i];
2576                 disabled = form.elements[i].disabled;
2577                 name = form.elements[i].name;
2578                 val = form.elements[i].value;
2579
2580                 if (!disabled && name){
2581                     switch (el.type)
2582                             {
2583                         case 'select-one':
2584                         case 'select-multiple':
2585                             for (var j = 0; j < el.options.length; j++) {
2586                                 if (el.options[j].selected) {
2587                                     if (Roo.isIE) {
2588                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2589                                     }
2590                                     else {
2591                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592                                     }
2593                                 }
2594                             }
2595                             break;
2596                         case 'radio':
2597                         case 'checkbox':
2598                             if (el.checked) {
2599                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2600                             }
2601                             break;
2602                         case 'file':
2603
2604                         case undefined:
2605
2606                         case 'reset':
2607
2608                         case 'button':
2609
2610                             break;
2611                         case 'submit':
2612                             if(hasSubmit == false) {
2613                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2614                                 hasSubmit = true;
2615                             }
2616                             break;
2617                         default:
2618                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2619                             break;
2620                     }
2621                 }
2622             }
2623             data = data.substr(0, data.length - 1);
2624             return data;
2625         },
2626
2627         headers:{},
2628
2629         hasHeaders:false,
2630
2631         useDefaultHeader:true,
2632
2633         defaultPostHeader:'application/x-www-form-urlencoded',
2634
2635         useDefaultXhrHeader:true,
2636
2637         defaultXhrHeader:'XMLHttpRequest',
2638
2639         hasDefaultHeaders:true,
2640
2641         defaultHeaders:{},
2642
2643         poll:{},
2644
2645         timeout:{},
2646
2647         pollInterval:50,
2648
2649         transactionId:0,
2650
2651         setProgId:function(id)
2652         {
2653             this.activeX.unshift(id);
2654         },
2655
2656         setDefaultPostHeader:function(b)
2657         {
2658             this.useDefaultHeader = b;
2659         },
2660
2661         setDefaultXhrHeader:function(b)
2662         {
2663             this.useDefaultXhrHeader = b;
2664         },
2665
2666         setPollingInterval:function(i)
2667         {
2668             if (typeof i == 'number' && isFinite(i)) {
2669                 this.pollInterval = i;
2670             }
2671         },
2672
2673         createXhrObject:function(transactionId)
2674         {
2675             var obj,http;
2676             try
2677             {
2678
2679                 http = new XMLHttpRequest();
2680
2681                 obj = { conn:http, tId:transactionId };
2682             }
2683             catch(e)
2684             {
2685                 for (var i = 0; i < this.activeX.length; ++i) {
2686                     try
2687                     {
2688
2689                         http = new ActiveXObject(this.activeX[i]);
2690
2691                         obj = { conn:http, tId:transactionId };
2692                         break;
2693                     }
2694                     catch(e) {
2695                     }
2696                 }
2697             }
2698             finally
2699             {
2700                 return obj;
2701             }
2702         },
2703
2704         getConnectionObject:function()
2705         {
2706             var o;
2707             var tId = this.transactionId;
2708
2709             try
2710             {
2711                 o = this.createXhrObject(tId);
2712                 if (o) {
2713                     this.transactionId++;
2714                 }
2715             }
2716             catch(e) {
2717             }
2718             finally
2719             {
2720                 return o;
2721             }
2722         },
2723
2724         asyncRequest:function(method, uri, callback, postData)
2725         {
2726             var o = this.getConnectionObject();
2727
2728             if (!o) {
2729                 return null;
2730             }
2731             else {
2732                 o.conn.open(method, uri, true);
2733
2734                 if (this.useDefaultXhrHeader) {
2735                     if (!this.defaultHeaders['X-Requested-With']) {
2736                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2737                     }
2738                 }
2739
2740                 if(postData && this.useDefaultHeader){
2741                     this.initHeader('Content-Type', this.defaultPostHeader);
2742                 }
2743
2744                  if (this.hasDefaultHeaders || this.hasHeaders) {
2745                     this.setHeader(o);
2746                 }
2747
2748                 this.handleReadyState(o, callback);
2749                 o.conn.send(postData || null);
2750
2751                 return o;
2752             }
2753         },
2754
2755         handleReadyState:function(o, callback)
2756         {
2757             var oConn = this;
2758
2759             if (callback && callback.timeout) {
2760                 
2761                 this.timeout[o.tId] = window.setTimeout(function() {
2762                     oConn.abort(o, callback, true);
2763                 }, callback.timeout);
2764             }
2765
2766             this.poll[o.tId] = window.setInterval(
2767                     function() {
2768                         if (o.conn && o.conn.readyState == 4) {
2769                             window.clearInterval(oConn.poll[o.tId]);
2770                             delete oConn.poll[o.tId];
2771
2772                             if(callback && callback.timeout) {
2773                                 window.clearTimeout(oConn.timeout[o.tId]);
2774                                 delete oConn.timeout[o.tId];
2775                             }
2776
2777                             oConn.handleTransactionResponse(o, callback);
2778                         }
2779                     }
2780                     , this.pollInterval);
2781         },
2782
2783         handleTransactionResponse:function(o, callback, isAbort)
2784         {
2785
2786             if (!callback) {
2787                 this.releaseObject(o);
2788                 return;
2789             }
2790
2791             var httpStatus, responseObject;
2792
2793             try
2794             {
2795                 if (o.conn.status !== undefined && o.conn.status != 0) {
2796                     httpStatus = o.conn.status;
2797                 }
2798                 else {
2799                     httpStatus = 13030;
2800                 }
2801             }
2802             catch(e) {
2803
2804
2805                 httpStatus = 13030;
2806             }
2807
2808             if (httpStatus >= 200 && httpStatus < 300) {
2809                 responseObject = this.createResponseObject(o, callback.argument);
2810                 if (callback.success) {
2811                     if (!callback.scope) {
2812                         callback.success(responseObject);
2813                     }
2814                     else {
2815
2816
2817                         callback.success.apply(callback.scope, [responseObject]);
2818                     }
2819                 }
2820             }
2821             else {
2822                 switch (httpStatus) {
2823
2824                     case 12002:
2825                     case 12029:
2826                     case 12030:
2827                     case 12031:
2828                     case 12152:
2829                     case 13030:
2830                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2831                         if (callback.failure) {
2832                             if (!callback.scope) {
2833                                 callback.failure(responseObject);
2834                             }
2835                             else {
2836                                 callback.failure.apply(callback.scope, [responseObject]);
2837                             }
2838                         }
2839                         break;
2840                     default:
2841                         responseObject = this.createResponseObject(o, callback.argument);
2842                         if (callback.failure) {
2843                             if (!callback.scope) {
2844                                 callback.failure(responseObject);
2845                             }
2846                             else {
2847                                 callback.failure.apply(callback.scope, [responseObject]);
2848                             }
2849                         }
2850                 }
2851             }
2852
2853             this.releaseObject(o);
2854             responseObject = null;
2855         },
2856
2857         createResponseObject:function(o, callbackArg)
2858         {
2859             var obj = {};
2860             var headerObj = {};
2861
2862             try
2863             {
2864                 var headerStr = o.conn.getAllResponseHeaders();
2865                 var header = headerStr.split('\n');
2866                 for (var i = 0; i < header.length; i++) {
2867                     var delimitPos = header[i].indexOf(':');
2868                     if (delimitPos != -1) {
2869                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870                     }
2871                 }
2872             }
2873             catch(e) {
2874             }
2875
2876             obj.tId = o.tId;
2877             obj.status = o.conn.status;
2878             obj.statusText = o.conn.statusText;
2879             obj.getResponseHeader = headerObj;
2880             obj.getAllResponseHeaders = headerStr;
2881             obj.responseText = o.conn.responseText;
2882             obj.responseXML = o.conn.responseXML;
2883
2884             if (typeof callbackArg !== undefined) {
2885                 obj.argument = callbackArg;
2886             }
2887
2888             return obj;
2889         },
2890
2891         createExceptionObject:function(tId, callbackArg, isAbort)
2892         {
2893             var COMM_CODE = 0;
2894             var COMM_ERROR = 'communication failure';
2895             var ABORT_CODE = -1;
2896             var ABORT_ERROR = 'transaction aborted';
2897
2898             var obj = {};
2899
2900             obj.tId = tId;
2901             if (isAbort) {
2902                 obj.status = ABORT_CODE;
2903                 obj.statusText = ABORT_ERROR;
2904             }
2905             else {
2906                 obj.status = COMM_CODE;
2907                 obj.statusText = COMM_ERROR;
2908             }
2909
2910             if (callbackArg) {
2911                 obj.argument = callbackArg;
2912             }
2913
2914             return obj;
2915         },
2916
2917         initHeader:function(label, value, isDefault)
2918         {
2919             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2920
2921             if (headerObj[label] === undefined) {
2922                 headerObj[label] = value;
2923             }
2924             else {
2925
2926
2927                 headerObj[label] = value + "," + headerObj[label];
2928             }
2929
2930             if (isDefault) {
2931                 this.hasDefaultHeaders = true;
2932             }
2933             else {
2934                 this.hasHeaders = true;
2935             }
2936         },
2937
2938
2939         setHeader:function(o)
2940         {
2941             if (this.hasDefaultHeaders) {
2942                 for (var prop in this.defaultHeaders) {
2943                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2944                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2945                     }
2946                 }
2947             }
2948
2949             if (this.hasHeaders) {
2950                 for (var prop in this.headers) {
2951                     if (this.headers.hasOwnProperty(prop)) {
2952                         o.conn.setRequestHeader(prop, this.headers[prop]);
2953                     }
2954                 }
2955                 this.headers = {};
2956                 this.hasHeaders = false;
2957             }
2958         },
2959
2960         resetDefaultHeaders:function() {
2961             delete this.defaultHeaders;
2962             this.defaultHeaders = {};
2963             this.hasDefaultHeaders = false;
2964         },
2965
2966         abort:function(o, callback, isTimeout)
2967         {
2968             if(this.isCallInProgress(o)) {
2969                 o.conn.abort();
2970                 window.clearInterval(this.poll[o.tId]);
2971                 delete this.poll[o.tId];
2972                 if (isTimeout) {
2973                     delete this.timeout[o.tId];
2974                 }
2975
2976                 this.handleTransactionResponse(o, callback, true);
2977
2978                 return true;
2979             }
2980             else {
2981                 return false;
2982             }
2983         },
2984
2985
2986         isCallInProgress:function(o)
2987         {
2988             if (o && o.conn) {
2989                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2990             }
2991             else {
2992
2993                 return false;
2994             }
2995         },
2996
2997
2998         releaseObject:function(o)
2999         {
3000
3001             o.conn = null;
3002
3003             o = null;
3004         },
3005
3006         activeX:[
3007         'MSXML2.XMLHTTP.3.0',
3008         'MSXML2.XMLHTTP',
3009         'Microsoft.XMLHTTP'
3010         ]
3011
3012
3013     };
3014 })();/*
3015  * Portions of this file are based on pieces of Yahoo User Interface Library
3016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3017  * YUI licensed under the BSD License:
3018  * http://developer.yahoo.net/yui/license.txt
3019  * <script type="text/javascript">
3020  *
3021  */
3022
3023 Roo.lib.Region = function(t, r, b, l) {
3024     this.top = t;
3025     this[1] = t;
3026     this.right = r;
3027     this.bottom = b;
3028     this.left = l;
3029     this[0] = l;
3030 };
3031
3032
3033 Roo.lib.Region.prototype = {
3034     contains : function(region) {
3035         return ( region.left >= this.left &&
3036                  region.right <= this.right &&
3037                  region.top >= this.top &&
3038                  region.bottom <= this.bottom    );
3039
3040     },
3041
3042     getArea : function() {
3043         return ( (this.bottom - this.top) * (this.right - this.left) );
3044     },
3045
3046     intersect : function(region) {
3047         var t = Math.max(this.top, region.top);
3048         var r = Math.min(this.right, region.right);
3049         var b = Math.min(this.bottom, region.bottom);
3050         var l = Math.max(this.left, region.left);
3051
3052         if (b >= t && r >= l) {
3053             return new Roo.lib.Region(t, r, b, l);
3054         } else {
3055             return null;
3056         }
3057     },
3058     union : function(region) {
3059         var t = Math.min(this.top, region.top);
3060         var r = Math.max(this.right, region.right);
3061         var b = Math.max(this.bottom, region.bottom);
3062         var l = Math.min(this.left, region.left);
3063
3064         return new Roo.lib.Region(t, r, b, l);
3065     },
3066
3067     adjust : function(t, l, b, r) {
3068         this.top += t;
3069         this.left += l;
3070         this.right += r;
3071         this.bottom += b;
3072         return this;
3073     }
3074 };
3075
3076 Roo.lib.Region.getRegion = function(el) {
3077     var p = Roo.lib.Dom.getXY(el);
3078
3079     var t = p[1];
3080     var r = p[0] + el.offsetWidth;
3081     var b = p[1] + el.offsetHeight;
3082     var l = p[0];
3083
3084     return new Roo.lib.Region(t, r, b, l);
3085 };
3086 /*
3087  * Portions of this file are based on pieces of Yahoo User Interface Library
3088  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3089  * YUI licensed under the BSD License:
3090  * http://developer.yahoo.net/yui/license.txt
3091  * <script type="text/javascript">
3092  *
3093  */
3094 //@@dep Roo.lib.Region
3095
3096
3097 Roo.lib.Point = function(x, y) {
3098     if (x instanceof Array) {
3099         y = x[1];
3100         x = x[0];
3101     }
3102     this.x = this.right = this.left = this[0] = x;
3103     this.y = this.top = this.bottom = this[1] = y;
3104 };
3105
3106 Roo.lib.Point.prototype = new Roo.lib.Region();
3107 /*
3108  * Portions of this file are based on pieces of Yahoo User Interface Library
3109  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110  * YUI licensed under the BSD License:
3111  * http://developer.yahoo.net/yui/license.txt
3112  * <script type="text/javascript">
3113  *
3114  */
3115  
3116 (function() {   
3117
3118     Roo.lib.Anim = {
3119         scroll : function(el, args, duration, easing, cb, scope) {
3120             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3121         },
3122
3123         motion : function(el, args, duration, easing, cb, scope) {
3124             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3125         },
3126
3127         color : function(el, args, duration, easing, cb, scope) {
3128             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3129         },
3130
3131         run : function(el, args, duration, easing, cb, scope, type) {
3132             type = type || Roo.lib.AnimBase;
3133             if (typeof easing == "string") {
3134                 easing = Roo.lib.Easing[easing];
3135             }
3136             var anim = new type(el, args, duration, easing);
3137             anim.animateX(function() {
3138                 Roo.callback(cb, scope);
3139             });
3140             return anim;
3141         }
3142     };
3143 })();/*
3144  * Portions of this file are based on pieces of Yahoo User Interface Library
3145  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3146  * YUI licensed under the BSD License:
3147  * http://developer.yahoo.net/yui/license.txt
3148  * <script type="text/javascript">
3149  *
3150  */
3151
3152 (function() {    
3153     var libFlyweight;
3154     
3155     function fly(el) {
3156         if (!libFlyweight) {
3157             libFlyweight = new Roo.Element.Flyweight();
3158         }
3159         libFlyweight.dom = el;
3160         return libFlyweight;
3161     }
3162
3163     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3164     
3165    
3166     
3167     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3168         if (el) {
3169             this.init(el, attributes, duration, method);
3170         }
3171     };
3172
3173     Roo.lib.AnimBase.fly = fly;
3174     
3175     
3176     
3177     Roo.lib.AnimBase.prototype = {
3178
3179         toString: function() {
3180             var el = this.getEl();
3181             var id = el.id || el.tagName;
3182             return ("Anim " + id);
3183         },
3184
3185         patterns: {
3186             noNegatives:        /width|height|opacity|padding/i,
3187             offsetAttribute:  /^((width|height)|(top|left))$/,
3188             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3189             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3190         },
3191
3192
3193         doMethod: function(attr, start, end) {
3194             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3195         },
3196
3197
3198         setAttribute: function(attr, val, unit) {
3199             if (this.patterns.noNegatives.test(attr)) {
3200                 val = (val > 0) ? val : 0;
3201             }
3202
3203             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3204         },
3205
3206
3207         getAttribute: function(attr) {
3208             var el = this.getEl();
3209             var val = fly(el).getStyle(attr);
3210
3211             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3212                 return parseFloat(val);
3213             }
3214
3215             var a = this.patterns.offsetAttribute.exec(attr) || [];
3216             var pos = !!( a[3] );
3217             var box = !!( a[2] );
3218
3219
3220             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3221                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3222             } else {
3223                 val = 0;
3224             }
3225
3226             return val;
3227         },
3228
3229
3230         getDefaultUnit: function(attr) {
3231             if (this.patterns.defaultUnit.test(attr)) {
3232                 return 'px';
3233             }
3234
3235             return '';
3236         },
3237
3238         animateX : function(callback, scope) {
3239             var f = function() {
3240                 this.onComplete.removeListener(f);
3241                 if (typeof callback == "function") {
3242                     callback.call(scope || this, this);
3243                 }
3244             };
3245             this.onComplete.addListener(f, this);
3246             this.animate();
3247         },
3248
3249
3250         setRuntimeAttribute: function(attr) {
3251             var start;
3252             var end;
3253             var attributes = this.attributes;
3254
3255             this.runtimeAttributes[attr] = {};
3256
3257             var isset = function(prop) {
3258                 return (typeof prop !== 'undefined');
3259             };
3260
3261             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3262                 return false;
3263             }
3264
3265             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3266
3267
3268             if (isset(attributes[attr]['to'])) {
3269                 end = attributes[attr]['to'];
3270             } else if (isset(attributes[attr]['by'])) {
3271                 if (start.constructor == Array) {
3272                     end = [];
3273                     for (var i = 0, len = start.length; i < len; ++i) {
3274                         end[i] = start[i] + attributes[attr]['by'][i];
3275                     }
3276                 } else {
3277                     end = start + attributes[attr]['by'];
3278                 }
3279             }
3280
3281             this.runtimeAttributes[attr].start = start;
3282             this.runtimeAttributes[attr].end = end;
3283
3284
3285             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3286         },
3287
3288
3289         init: function(el, attributes, duration, method) {
3290
3291             var isAnimated = false;
3292
3293
3294             var startTime = null;
3295
3296
3297             var actualFrames = 0;
3298
3299
3300             el = Roo.getDom(el);
3301
3302
3303             this.attributes = attributes || {};
3304
3305
3306             this.duration = duration || 1;
3307
3308
3309             this.method = method || Roo.lib.Easing.easeNone;
3310
3311
3312             this.useSeconds = true;
3313
3314
3315             this.currentFrame = 0;
3316
3317
3318             this.totalFrames = Roo.lib.AnimMgr.fps;
3319
3320
3321             this.getEl = function() {
3322                 return el;
3323             };
3324
3325
3326             this.isAnimated = function() {
3327                 return isAnimated;
3328             };
3329
3330
3331             this.getStartTime = function() {
3332                 return startTime;
3333             };
3334
3335             this.runtimeAttributes = {};
3336
3337
3338             this.animate = function() {
3339                 if (this.isAnimated()) {
3340                     return false;
3341                 }
3342
3343                 this.currentFrame = 0;
3344
3345                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3346
3347                 Roo.lib.AnimMgr.registerElement(this);
3348             };
3349
3350
3351             this.stop = function(finish) {
3352                 if (finish) {
3353                     this.currentFrame = this.totalFrames;
3354                     this._onTween.fire();
3355                 }
3356                 Roo.lib.AnimMgr.stop(this);
3357             };
3358
3359             var onStart = function() {
3360                 this.onStart.fire();
3361
3362                 this.runtimeAttributes = {};
3363                 for (var attr in this.attributes) {
3364                     this.setRuntimeAttribute(attr);
3365                 }
3366
3367                 isAnimated = true;
3368                 actualFrames = 0;
3369                 startTime = new Date();
3370             };
3371
3372
3373             var onTween = function() {
3374                 var data = {
3375                     duration: new Date() - this.getStartTime(),
3376                     currentFrame: this.currentFrame
3377                 };
3378
3379                 data.toString = function() {
3380                     return (
3381                             'duration: ' + data.duration +
3382                             ', currentFrame: ' + data.currentFrame
3383                             );
3384                 };
3385
3386                 this.onTween.fire(data);
3387
3388                 var runtimeAttributes = this.runtimeAttributes;
3389
3390                 for (var attr in runtimeAttributes) {
3391                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3392                 }
3393
3394                 actualFrames += 1;
3395             };
3396
3397             var onComplete = function() {
3398                 var actual_duration = (new Date() - startTime) / 1000 ;
3399
3400                 var data = {
3401                     duration: actual_duration,
3402                     frames: actualFrames,
3403                     fps: actualFrames / actual_duration
3404                 };
3405
3406                 data.toString = function() {
3407                     return (
3408                             'duration: ' + data.duration +
3409                             ', frames: ' + data.frames +
3410                             ', fps: ' + data.fps
3411                             );
3412                 };
3413
3414                 isAnimated = false;
3415                 actualFrames = 0;
3416                 this.onComplete.fire(data);
3417             };
3418
3419
3420             this._onStart = new Roo.util.Event(this);
3421             this.onStart = new Roo.util.Event(this);
3422             this.onTween = new Roo.util.Event(this);
3423             this._onTween = new Roo.util.Event(this);
3424             this.onComplete = new Roo.util.Event(this);
3425             this._onComplete = new Roo.util.Event(this);
3426             this._onStart.addListener(onStart);
3427             this._onTween.addListener(onTween);
3428             this._onComplete.addListener(onComplete);
3429         }
3430     };
3431 })();
3432 /*
3433  * Portions of this file are based on pieces of Yahoo User Interface Library
3434  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3435  * YUI licensed under the BSD License:
3436  * http://developer.yahoo.net/yui/license.txt
3437  * <script type="text/javascript">
3438  *
3439  */
3440
3441 Roo.lib.AnimMgr = new function() {
3442
3443     var thread = null;
3444
3445
3446     var queue = [];
3447
3448
3449     var tweenCount = 0;
3450
3451
3452     this.fps = 1000;
3453
3454
3455     this.delay = 1;
3456
3457
3458     this.registerElement = function(tween) {
3459         queue[queue.length] = tween;
3460         tweenCount += 1;
3461         tween._onStart.fire();
3462         this.start();
3463     };
3464
3465
3466     this.unRegister = function(tween, index) {
3467         tween._onComplete.fire();
3468         index = index || getIndex(tween);
3469         if (index != -1) {
3470             queue.splice(index, 1);
3471         }
3472
3473         tweenCount -= 1;
3474         if (tweenCount <= 0) {
3475             this.stop();
3476         }
3477     };
3478
3479
3480     this.start = function() {
3481         if (thread === null) {
3482             thread = setInterval(this.run, this.delay);
3483         }
3484     };
3485
3486
3487     this.stop = function(tween) {
3488         if (!tween) {
3489             clearInterval(thread);
3490
3491             for (var i = 0, len = queue.length; i < len; ++i) {
3492                 if (queue[0].isAnimated()) {
3493                     this.unRegister(queue[0], 0);
3494                 }
3495             }
3496
3497             queue = [];
3498             thread = null;
3499             tweenCount = 0;
3500         }
3501         else {
3502             this.unRegister(tween);
3503         }
3504     };
3505
3506
3507     this.run = function() {
3508         for (var i = 0, len = queue.length; i < len; ++i) {
3509             var tween = queue[i];
3510             if (!tween || !tween.isAnimated()) {
3511                 continue;
3512             }
3513
3514             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3515             {
3516                 tween.currentFrame += 1;
3517
3518                 if (tween.useSeconds) {
3519                     correctFrame(tween);
3520                 }
3521                 tween._onTween.fire();
3522             }
3523             else {
3524                 Roo.lib.AnimMgr.stop(tween, i);
3525             }
3526         }
3527     };
3528
3529     var getIndex = function(anim) {
3530         for (var i = 0, len = queue.length; i < len; ++i) {
3531             if (queue[i] == anim) {
3532                 return i;
3533             }
3534         }
3535         return -1;
3536     };
3537
3538
3539     var correctFrame = function(tween) {
3540         var frames = tween.totalFrames;
3541         var frame = tween.currentFrame;
3542         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3543         var elapsed = (new Date() - tween.getStartTime());
3544         var tweak = 0;
3545
3546         if (elapsed < tween.duration * 1000) {
3547             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3548         } else {
3549             tweak = frames - (frame + 1);
3550         }
3551         if (tweak > 0 && isFinite(tweak)) {
3552             if (tween.currentFrame + tweak >= frames) {
3553                 tweak = frames - (frame + 1);
3554             }
3555
3556             tween.currentFrame += tweak;
3557         }
3558     };
3559 };
3560
3561     /*
3562  * Portions of this file are based on pieces of Yahoo User Interface Library
3563  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3564  * YUI licensed under the BSD License:
3565  * http://developer.yahoo.net/yui/license.txt
3566  * <script type="text/javascript">
3567  *
3568  */
3569 Roo.lib.Bezier = new function() {
3570
3571         this.getPosition = function(points, t) {
3572             var n = points.length;
3573             var tmp = [];
3574
3575             for (var i = 0; i < n; ++i) {
3576                 tmp[i] = [points[i][0], points[i][1]];
3577             }
3578
3579             for (var j = 1; j < n; ++j) {
3580                 for (i = 0; i < n - j; ++i) {
3581                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3582                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3583                 }
3584             }
3585
3586             return [ tmp[0][0], tmp[0][1] ];
3587
3588         };
3589     };/*
3590  * Portions of this file are based on pieces of Yahoo User Interface Library
3591  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3592  * YUI licensed under the BSD License:
3593  * http://developer.yahoo.net/yui/license.txt
3594  * <script type="text/javascript">
3595  *
3596  */
3597 (function() {
3598
3599     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3600         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3601     };
3602
3603     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3604
3605     var fly = Roo.lib.AnimBase.fly;
3606     var Y = Roo.lib;
3607     var superclass = Y.ColorAnim.superclass;
3608     var proto = Y.ColorAnim.prototype;
3609
3610     proto.toString = function() {
3611         var el = this.getEl();
3612         var id = el.id || el.tagName;
3613         return ("ColorAnim " + id);
3614     };
3615
3616     proto.patterns.color = /color$/i;
3617     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3618     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3619     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3620     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3621
3622
3623     proto.parseColor = function(s) {
3624         if (s.length == 3) {
3625             return s;
3626         }
3627
3628         var c = this.patterns.hex.exec(s);
3629         if (c && c.length == 4) {
3630             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3631         }
3632
3633         c = this.patterns.rgb.exec(s);
3634         if (c && c.length == 4) {
3635             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3636         }
3637
3638         c = this.patterns.hex3.exec(s);
3639         if (c && c.length == 4) {
3640             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3641         }
3642
3643         return null;
3644     };
3645     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3646     proto.getAttribute = function(attr) {
3647         var el = this.getEl();
3648         if (this.patterns.color.test(attr)) {
3649             var val = fly(el).getStyle(attr);
3650
3651             if (this.patterns.transparent.test(val)) {
3652                 var parent = el.parentNode;
3653                 val = fly(parent).getStyle(attr);
3654
3655                 while (parent && this.patterns.transparent.test(val)) {
3656                     parent = parent.parentNode;
3657                     val = fly(parent).getStyle(attr);
3658                     if (parent.tagName.toUpperCase() == 'HTML') {
3659                         val = '#fff';
3660                     }
3661                 }
3662             }
3663         } else {
3664             val = superclass.getAttribute.call(this, attr);
3665         }
3666
3667         return val;
3668     };
3669     proto.getAttribute = function(attr) {
3670         var el = this.getEl();
3671         if (this.patterns.color.test(attr)) {
3672             var val = fly(el).getStyle(attr);
3673
3674             if (this.patterns.transparent.test(val)) {
3675                 var parent = el.parentNode;
3676                 val = fly(parent).getStyle(attr);
3677
3678                 while (parent && this.patterns.transparent.test(val)) {
3679                     parent = parent.parentNode;
3680                     val = fly(parent).getStyle(attr);
3681                     if (parent.tagName.toUpperCase() == 'HTML') {
3682                         val = '#fff';
3683                     }
3684                 }
3685             }
3686         } else {
3687             val = superclass.getAttribute.call(this, attr);
3688         }
3689
3690         return val;
3691     };
3692
3693     proto.doMethod = function(attr, start, end) {
3694         var val;
3695
3696         if (this.patterns.color.test(attr)) {
3697             val = [];
3698             for (var i = 0, len = start.length; i < len; ++i) {
3699                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3700             }
3701
3702             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3703         }
3704         else {
3705             val = superclass.doMethod.call(this, attr, start, end);
3706         }
3707
3708         return val;
3709     };
3710
3711     proto.setRuntimeAttribute = function(attr) {
3712         superclass.setRuntimeAttribute.call(this, attr);
3713
3714         if (this.patterns.color.test(attr)) {
3715             var attributes = this.attributes;
3716             var start = this.parseColor(this.runtimeAttributes[attr].start);
3717             var end = this.parseColor(this.runtimeAttributes[attr].end);
3718
3719             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3720                 end = this.parseColor(attributes[attr].by);
3721
3722                 for (var i = 0, len = start.length; i < len; ++i) {
3723                     end[i] = start[i] + end[i];
3724                 }
3725             }
3726
3727             this.runtimeAttributes[attr].start = start;
3728             this.runtimeAttributes[attr].end = end;
3729         }
3730     };
3731 })();
3732
3733 /*
3734  * Portions of this file are based on pieces of Yahoo User Interface Library
3735  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3736  * YUI licensed under the BSD License:
3737  * http://developer.yahoo.net/yui/license.txt
3738  * <script type="text/javascript">
3739  *
3740  */
3741 Roo.lib.Easing = {
3742
3743
3744     easeNone: function (t, b, c, d) {
3745         return c * t / d + b;
3746     },
3747
3748
3749     easeIn: function (t, b, c, d) {
3750         return c * (t /= d) * t + b;
3751     },
3752
3753
3754     easeOut: function (t, b, c, d) {
3755         return -c * (t /= d) * (t - 2) + b;
3756     },
3757
3758
3759     easeBoth: function (t, b, c, d) {
3760         if ((t /= d / 2) < 1) {
3761             return c / 2 * t * t + b;
3762         }
3763
3764         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3765     },
3766
3767
3768     easeInStrong: function (t, b, c, d) {
3769         return c * (t /= d) * t * t * t + b;
3770     },
3771
3772
3773     easeOutStrong: function (t, b, c, d) {
3774         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3775     },
3776
3777
3778     easeBothStrong: function (t, b, c, d) {
3779         if ((t /= d / 2) < 1) {
3780             return c / 2 * t * t * t * t + b;
3781         }
3782
3783         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3784     },
3785
3786
3787
3788     elasticIn: function (t, b, c, d, a, p) {
3789         if (t == 0) {
3790             return b;
3791         }
3792         if ((t /= d) == 1) {
3793             return b + c;
3794         }
3795         if (!p) {
3796             p = d * .3;
3797         }
3798
3799         if (!a || a < Math.abs(c)) {
3800             a = c;
3801             var s = p / 4;
3802         }
3803         else {
3804             var s = p / (2 * Math.PI) * Math.asin(c / a);
3805         }
3806
3807         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3808     },
3809
3810
3811     elasticOut: function (t, b, c, d, a, p) {
3812         if (t == 0) {
3813             return b;
3814         }
3815         if ((t /= d) == 1) {
3816             return b + c;
3817         }
3818         if (!p) {
3819             p = d * .3;
3820         }
3821
3822         if (!a || a < Math.abs(c)) {
3823             a = c;
3824             var s = p / 4;
3825         }
3826         else {
3827             var s = p / (2 * Math.PI) * Math.asin(c / a);
3828         }
3829
3830         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3831     },
3832
3833
3834     elasticBoth: function (t, b, c, d, a, p) {
3835         if (t == 0) {
3836             return b;
3837         }
3838
3839         if ((t /= d / 2) == 2) {
3840             return b + c;
3841         }
3842
3843         if (!p) {
3844             p = d * (.3 * 1.5);
3845         }
3846
3847         if (!a || a < Math.abs(c)) {
3848             a = c;
3849             var s = p / 4;
3850         }
3851         else {
3852             var s = p / (2 * Math.PI) * Math.asin(c / a);
3853         }
3854
3855         if (t < 1) {
3856             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3857                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3858         }
3859         return a * Math.pow(2, -10 * (t -= 1)) *
3860                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3861     },
3862
3863
3864
3865     backIn: function (t, b, c, d, s) {
3866         if (typeof s == 'undefined') {
3867             s = 1.70158;
3868         }
3869         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3870     },
3871
3872
3873     backOut: function (t, b, c, d, s) {
3874         if (typeof s == 'undefined') {
3875             s = 1.70158;
3876         }
3877         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3878     },
3879
3880
3881     backBoth: function (t, b, c, d, s) {
3882         if (typeof s == 'undefined') {
3883             s = 1.70158;
3884         }
3885
3886         if ((t /= d / 2 ) < 1) {
3887             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3888         }
3889         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3890     },
3891
3892
3893     bounceIn: function (t, b, c, d) {
3894         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3895     },
3896
3897
3898     bounceOut: function (t, b, c, d) {
3899         if ((t /= d) < (1 / 2.75)) {
3900             return c * (7.5625 * t * t) + b;
3901         } else if (t < (2 / 2.75)) {
3902             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3903         } else if (t < (2.5 / 2.75)) {
3904             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3905         }
3906         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3907     },
3908
3909
3910     bounceBoth: function (t, b, c, d) {
3911         if (t < d / 2) {
3912             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3913         }
3914         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3915     }
3916 };/*
3917  * Portions of this file are based on pieces of Yahoo User Interface Library
3918  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3919  * YUI licensed under the BSD License:
3920  * http://developer.yahoo.net/yui/license.txt
3921  * <script type="text/javascript">
3922  *
3923  */
3924     (function() {
3925         Roo.lib.Motion = function(el, attributes, duration, method) {
3926             if (el) {
3927                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3928             }
3929         };
3930
3931         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3932
3933
3934         var Y = Roo.lib;
3935         var superclass = Y.Motion.superclass;
3936         var proto = Y.Motion.prototype;
3937
3938         proto.toString = function() {
3939             var el = this.getEl();
3940             var id = el.id || el.tagName;
3941             return ("Motion " + id);
3942         };
3943
3944         proto.patterns.points = /^points$/i;
3945
3946         proto.setAttribute = function(attr, val, unit) {
3947             if (this.patterns.points.test(attr)) {
3948                 unit = unit || 'px';
3949                 superclass.setAttribute.call(this, 'left', val[0], unit);
3950                 superclass.setAttribute.call(this, 'top', val[1], unit);
3951             } else {
3952                 superclass.setAttribute.call(this, attr, val, unit);
3953             }
3954         };
3955
3956         proto.getAttribute = function(attr) {
3957             if (this.patterns.points.test(attr)) {
3958                 var val = [
3959                         superclass.getAttribute.call(this, 'left'),
3960                         superclass.getAttribute.call(this, 'top')
3961                         ];
3962             } else {
3963                 val = superclass.getAttribute.call(this, attr);
3964             }
3965
3966             return val;
3967         };
3968
3969         proto.doMethod = function(attr, start, end) {
3970             var val = null;
3971
3972             if (this.patterns.points.test(attr)) {
3973                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3974                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3975             } else {
3976                 val = superclass.doMethod.call(this, attr, start, end);
3977             }
3978             return val;
3979         };
3980
3981         proto.setRuntimeAttribute = function(attr) {
3982             if (this.patterns.points.test(attr)) {
3983                 var el = this.getEl();
3984                 var attributes = this.attributes;
3985                 var start;
3986                 var control = attributes['points']['control'] || [];
3987                 var end;
3988                 var i, len;
3989
3990                 if (control.length > 0 && !(control[0] instanceof Array)) {
3991                     control = [control];
3992                 } else {
3993                     var tmp = [];
3994                     for (i = 0,len = control.length; i < len; ++i) {
3995                         tmp[i] = control[i];
3996                     }
3997                     control = tmp;
3998                 }
3999
4000                 Roo.fly(el).position();
4001
4002                 if (isset(attributes['points']['from'])) {
4003                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4004                 }
4005                 else {
4006                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4007                 }
4008
4009                 start = this.getAttribute('points');
4010
4011
4012                 if (isset(attributes['points']['to'])) {
4013                     end = translateValues.call(this, attributes['points']['to'], start);
4014
4015                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4016                     for (i = 0,len = control.length; i < len; ++i) {
4017                         control[i] = translateValues.call(this, control[i], start);
4018                     }
4019
4020
4021                 } else if (isset(attributes['points']['by'])) {
4022                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4023
4024                     for (i = 0,len = control.length; i < len; ++i) {
4025                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4026                     }
4027                 }
4028
4029                 this.runtimeAttributes[attr] = [start];
4030
4031                 if (control.length > 0) {
4032                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4033                 }
4034
4035                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4036             }
4037             else {
4038                 superclass.setRuntimeAttribute.call(this, attr);
4039             }
4040         };
4041
4042         var translateValues = function(val, start) {
4043             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4044             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4045
4046             return val;
4047         };
4048
4049         var isset = function(prop) {
4050             return (typeof prop !== 'undefined');
4051         };
4052     })();
4053 /*
4054  * Portions of this file are based on pieces of Yahoo User Interface Library
4055  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4056  * YUI licensed under the BSD License:
4057  * http://developer.yahoo.net/yui/license.txt
4058  * <script type="text/javascript">
4059  *
4060  */
4061     (function() {
4062         Roo.lib.Scroll = function(el, attributes, duration, method) {
4063             if (el) {
4064                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4065             }
4066         };
4067
4068         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4069
4070
4071         var Y = Roo.lib;
4072         var superclass = Y.Scroll.superclass;
4073         var proto = Y.Scroll.prototype;
4074
4075         proto.toString = function() {
4076             var el = this.getEl();
4077             var id = el.id || el.tagName;
4078             return ("Scroll " + id);
4079         };
4080
4081         proto.doMethod = function(attr, start, end) {
4082             var val = null;
4083
4084             if (attr == 'scroll') {
4085                 val = [
4086                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4087                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4088                         ];
4089
4090             } else {
4091                 val = superclass.doMethod.call(this, attr, start, end);
4092             }
4093             return val;
4094         };
4095
4096         proto.getAttribute = function(attr) {
4097             var val = null;
4098             var el = this.getEl();
4099
4100             if (attr == 'scroll') {
4101                 val = [ el.scrollLeft, el.scrollTop ];
4102             } else {
4103                 val = superclass.getAttribute.call(this, attr);
4104             }
4105
4106             return val;
4107         };
4108
4109         proto.setAttribute = function(attr, val, unit) {
4110             var el = this.getEl();
4111
4112             if (attr == 'scroll') {
4113                 el.scrollLeft = val[0];
4114                 el.scrollTop = val[1];
4115             } else {
4116                 superclass.setAttribute.call(this, attr, val, unit);
4117             }
4118         };
4119     })();
4120 /*
4121  * Based on:
4122  * Ext JS Library 1.1.1
4123  * Copyright(c) 2006-2007, Ext JS, LLC.
4124  *
4125  * Originally Released Under LGPL - original licence link has changed is not relivant.
4126  *
4127  * Fork - LGPL
4128  * <script type="text/javascript">
4129  */
4130
4131
4132 // nasty IE9 hack - what a pile of crap that is..
4133
4134  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4135     Range.prototype.createContextualFragment = function (html) {
4136         var doc = window.document;
4137         var container = doc.createElement("div");
4138         container.innerHTML = html;
4139         var frag = doc.createDocumentFragment(), n;
4140         while ((n = container.firstChild)) {
4141             frag.appendChild(n);
4142         }
4143         return frag;
4144     };
4145 }
4146
4147 /**
4148  * @class Roo.DomHelper
4149  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4150  * 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>.
4151  * @singleton
4152  */
4153 Roo.DomHelper = function(){
4154     var tempTableEl = null;
4155     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4156     var tableRe = /^table|tbody|tr|td$/i;
4157     var xmlns = {};
4158     // build as innerHTML where available
4159     /** @ignore */
4160     var createHtml = function(o){
4161         if(typeof o == 'string'){
4162             return o;
4163         }
4164         var b = "";
4165         if(!o.tag){
4166             o.tag = "div";
4167         }
4168         b += "<" + o.tag;
4169         for(var attr in o){
4170             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4171             if(attr == "style"){
4172                 var s = o["style"];
4173                 if(typeof s == "function"){
4174                     s = s.call();
4175                 }
4176                 if(typeof s == "string"){
4177                     b += ' style="' + s + '"';
4178                 }else if(typeof s == "object"){
4179                     b += ' style="';
4180                     for(var key in s){
4181                         if(typeof s[key] != "function"){
4182                             b += key + ":" + s[key] + ";";
4183                         }
4184                     }
4185                     b += '"';
4186                 }
4187             }else{
4188                 if(attr == "cls"){
4189                     b += ' class="' + o["cls"] + '"';
4190                 }else if(attr == "htmlFor"){
4191                     b += ' for="' + o["htmlFor"] + '"';
4192                 }else{
4193                     b += " " + attr + '="' + o[attr] + '"';
4194                 }
4195             }
4196         }
4197         if(emptyTags.test(o.tag)){
4198             b += "/>";
4199         }else{
4200             b += ">";
4201             var cn = o.children || o.cn;
4202             if(cn){
4203                 //http://bugs.kde.org/show_bug.cgi?id=71506
4204                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4205                     for(var i = 0, len = cn.length; i < len; i++) {
4206                         b += createHtml(cn[i], b);
4207                     }
4208                 }else{
4209                     b += createHtml(cn, b);
4210                 }
4211             }
4212             if(o.html){
4213                 b += o.html;
4214             }
4215             b += "</" + o.tag + ">";
4216         }
4217         return b;
4218     };
4219
4220     // build as dom
4221     /** @ignore */
4222     var createDom = function(o, parentNode){
4223          
4224         // defininition craeted..
4225         var ns = false;
4226         if (o.ns && o.ns != 'html') {
4227                
4228             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4229                 xmlns[o.ns] = o.xmlns;
4230                 ns = o.xmlns;
4231             }
4232             if (typeof(xmlns[o.ns]) == 'undefined') {
4233                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4234             }
4235             ns = xmlns[o.ns];
4236         }
4237         
4238         
4239         if (typeof(o) == 'string') {
4240             return parentNode.appendChild(document.createTextNode(o));
4241         }
4242         o.tag = o.tag || div;
4243         if (o.ns && Roo.isIE) {
4244             ns = false;
4245             o.tag = o.ns + ':' + o.tag;
4246             
4247         }
4248         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4249         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4250         for(var attr in o){
4251             
4252             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4253                     attr == "style" || typeof o[attr] == "function") { continue; }
4254                     
4255             if(attr=="cls" && Roo.isIE){
4256                 el.className = o["cls"];
4257             }else{
4258                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4259                 else { 
4260                     el[attr] = o[attr];
4261                 }
4262             }
4263         }
4264         Roo.DomHelper.applyStyles(el, o.style);
4265         var cn = o.children || o.cn;
4266         if(cn){
4267             //http://bugs.kde.org/show_bug.cgi?id=71506
4268              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4269                 for(var i = 0, len = cn.length; i < len; i++) {
4270                     createDom(cn[i], el);
4271                 }
4272             }else{
4273                 createDom(cn, el);
4274             }
4275         }
4276         if(o.html){
4277             el.innerHTML = o.html;
4278         }
4279         if(parentNode){
4280            parentNode.appendChild(el);
4281         }
4282         return el;
4283     };
4284
4285     var ieTable = function(depth, s, h, e){
4286         tempTableEl.innerHTML = [s, h, e].join('');
4287         var i = -1, el = tempTableEl;
4288         while(++i < depth){
4289             el = el.firstChild;
4290         }
4291         return el;
4292     };
4293
4294     // kill repeat to save bytes
4295     var ts = '<table>',
4296         te = '</table>',
4297         tbs = ts+'<tbody>',
4298         tbe = '</tbody>'+te,
4299         trs = tbs + '<tr>',
4300         tre = '</tr>'+tbe;
4301
4302     /**
4303      * @ignore
4304      * Nasty code for IE's broken table implementation
4305      */
4306     var insertIntoTable = function(tag, where, el, html){
4307         if(!tempTableEl){
4308             tempTableEl = document.createElement('div');
4309         }
4310         var node;
4311         var before = null;
4312         if(tag == 'td'){
4313             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4314                 return;
4315             }
4316             if(where == 'beforebegin'){
4317                 before = el;
4318                 el = el.parentNode;
4319             } else{
4320                 before = el.nextSibling;
4321                 el = el.parentNode;
4322             }
4323             node = ieTable(4, trs, html, tre);
4324         }
4325         else if(tag == 'tr'){
4326             if(where == 'beforebegin'){
4327                 before = el;
4328                 el = el.parentNode;
4329                 node = ieTable(3, tbs, html, tbe);
4330             } else if(where == 'afterend'){
4331                 before = el.nextSibling;
4332                 el = el.parentNode;
4333                 node = ieTable(3, tbs, html, tbe);
4334             } else{ // INTO a TR
4335                 if(where == 'afterbegin'){
4336                     before = el.firstChild;
4337                 }
4338                 node = ieTable(4, trs, html, tre);
4339             }
4340         } else if(tag == 'tbody'){
4341             if(where == 'beforebegin'){
4342                 before = el;
4343                 el = el.parentNode;
4344                 node = ieTable(2, ts, html, te);
4345             } else if(where == 'afterend'){
4346                 before = el.nextSibling;
4347                 el = el.parentNode;
4348                 node = ieTable(2, ts, html, te);
4349             } else{
4350                 if(where == 'afterbegin'){
4351                     before = el.firstChild;
4352                 }
4353                 node = ieTable(3, tbs, html, tbe);
4354             }
4355         } else{ // TABLE
4356             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4357                 return;
4358             }
4359             if(where == 'afterbegin'){
4360                 before = el.firstChild;
4361             }
4362             node = ieTable(2, ts, html, te);
4363         }
4364         el.insertBefore(node, before);
4365         return node;
4366     };
4367
4368     return {
4369     /** True to force the use of DOM instead of html fragments @type Boolean */
4370     useDom : false,
4371
4372     /**
4373      * Returns the markup for the passed Element(s) config
4374      * @param {Object} o The Dom object spec (and children)
4375      * @return {String}
4376      */
4377     markup : function(o){
4378         return createHtml(o);
4379     },
4380
4381     /**
4382      * Applies a style specification to an element
4383      * @param {String/HTMLElement} el The element to apply styles to
4384      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4385      * a function which returns such a specification.
4386      */
4387     applyStyles : function(el, styles){
4388         if(styles){
4389            el = Roo.fly(el);
4390            if(typeof styles == "string"){
4391                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4392                var matches;
4393                while ((matches = re.exec(styles)) != null){
4394                    el.setStyle(matches[1], matches[2]);
4395                }
4396            }else if (typeof styles == "object"){
4397                for (var style in styles){
4398                   el.setStyle(style, styles[style]);
4399                }
4400            }else if (typeof styles == "function"){
4401                 Roo.DomHelper.applyStyles(el, styles.call());
4402            }
4403         }
4404     },
4405
4406     /**
4407      * Inserts an HTML fragment into the Dom
4408      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4409      * @param {HTMLElement} el The context element
4410      * @param {String} html The HTML fragmenet
4411      * @return {HTMLElement} The new node
4412      */
4413     insertHtml : function(where, el, html){
4414         where = where.toLowerCase();
4415         if(el.insertAdjacentHTML){
4416             if(tableRe.test(el.tagName)){
4417                 var rs;
4418                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4419                     return rs;
4420                 }
4421             }
4422             switch(where){
4423                 case "beforebegin":
4424                     el.insertAdjacentHTML('BeforeBegin', html);
4425                     return el.previousSibling;
4426                 case "afterbegin":
4427                     el.insertAdjacentHTML('AfterBegin', html);
4428                     return el.firstChild;
4429                 case "beforeend":
4430                     el.insertAdjacentHTML('BeforeEnd', html);
4431                     return el.lastChild;
4432                 case "afterend":
4433                     el.insertAdjacentHTML('AfterEnd', html);
4434                     return el.nextSibling;
4435             }
4436             throw 'Illegal insertion point -> "' + where + '"';
4437         }
4438         var range = el.ownerDocument.createRange();
4439         var frag;
4440         switch(where){
4441              case "beforebegin":
4442                 range.setStartBefore(el);
4443                 frag = range.createContextualFragment(html);
4444                 el.parentNode.insertBefore(frag, el);
4445                 return el.previousSibling;
4446              case "afterbegin":
4447                 if(el.firstChild){
4448                     range.setStartBefore(el.firstChild);
4449                     frag = range.createContextualFragment(html);
4450                     el.insertBefore(frag, el.firstChild);
4451                     return el.firstChild;
4452                 }else{
4453                     el.innerHTML = html;
4454                     return el.firstChild;
4455                 }
4456             case "beforeend":
4457                 if(el.lastChild){
4458                     range.setStartAfter(el.lastChild);
4459                     frag = range.createContextualFragment(html);
4460                     el.appendChild(frag);
4461                     return el.lastChild;
4462                 }else{
4463                     el.innerHTML = html;
4464                     return el.lastChild;
4465                 }
4466             case "afterend":
4467                 range.setStartAfter(el);
4468                 frag = range.createContextualFragment(html);
4469                 el.parentNode.insertBefore(frag, el.nextSibling);
4470                 return el.nextSibling;
4471             }
4472             throw 'Illegal insertion point -> "' + where + '"';
4473     },
4474
4475     /**
4476      * Creates new Dom element(s) and inserts them before el
4477      * @param {String/HTMLElement/Element} el The context element
4478      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4479      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4480      * @return {HTMLElement/Roo.Element} The new node
4481      */
4482     insertBefore : function(el, o, returnElement){
4483         return this.doInsert(el, o, returnElement, "beforeBegin");
4484     },
4485
4486     /**
4487      * Creates new Dom element(s) and inserts them after el
4488      * @param {String/HTMLElement/Element} el The context element
4489      * @param {Object} o The Dom object spec (and children)
4490      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4491      * @return {HTMLElement/Roo.Element} The new node
4492      */
4493     insertAfter : function(el, o, returnElement){
4494         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4495     },
4496
4497     /**
4498      * Creates new Dom element(s) and inserts them as the first child of el
4499      * @param {String/HTMLElement/Element} el The context element
4500      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4501      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4502      * @return {HTMLElement/Roo.Element} The new node
4503      */
4504     insertFirst : function(el, o, returnElement){
4505         return this.doInsert(el, o, returnElement, "afterBegin");
4506     },
4507
4508     // private
4509     doInsert : function(el, o, returnElement, pos, sibling){
4510         el = Roo.getDom(el);
4511         var newNode;
4512         if(this.useDom || o.ns){
4513             newNode = createDom(o, null);
4514             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4515         }else{
4516             var html = createHtml(o);
4517             newNode = this.insertHtml(pos, el, html);
4518         }
4519         return returnElement ? Roo.get(newNode, true) : newNode;
4520     },
4521
4522     /**
4523      * Creates new Dom element(s) and appends them to el
4524      * @param {String/HTMLElement/Element} el The context element
4525      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4526      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4527      * @return {HTMLElement/Roo.Element} The new node
4528      */
4529     append : function(el, o, returnElement){
4530         el = Roo.getDom(el);
4531         var newNode;
4532         if(this.useDom || o.ns){
4533             newNode = createDom(o, null);
4534             el.appendChild(newNode);
4535         }else{
4536             var html = createHtml(o);
4537             newNode = this.insertHtml("beforeEnd", el, html);
4538         }
4539         return returnElement ? Roo.get(newNode, true) : newNode;
4540     },
4541
4542     /**
4543      * Creates new Dom element(s) and overwrites the contents of el with them
4544      * @param {String/HTMLElement/Element} el The context element
4545      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4546      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4547      * @return {HTMLElement/Roo.Element} The new node
4548      */
4549     overwrite : function(el, o, returnElement){
4550         el = Roo.getDom(el);
4551         if (o.ns) {
4552           
4553             while (el.childNodes.length) {
4554                 el.removeChild(el.firstChild);
4555             }
4556             createDom(o, el);
4557         } else {
4558             el.innerHTML = createHtml(o);   
4559         }
4560         
4561         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4562     },
4563
4564     /**
4565      * Creates a new Roo.DomHelper.Template from the Dom object spec
4566      * @param {Object} o The Dom object spec (and children)
4567      * @return {Roo.DomHelper.Template} The new template
4568      */
4569     createTemplate : function(o){
4570         var html = createHtml(o);
4571         return new Roo.Template(html);
4572     }
4573     };
4574 }();
4575 /*
4576  * Based on:
4577  * Ext JS Library 1.1.1
4578  * Copyright(c) 2006-2007, Ext JS, LLC.
4579  *
4580  * Originally Released Under LGPL - original licence link has changed is not relivant.
4581  *
4582  * Fork - LGPL
4583  * <script type="text/javascript">
4584  */
4585  
4586 /**
4587 * @class Roo.Template
4588 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4589 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4590 * Usage:
4591 <pre><code>
4592 var t = new Roo.Template({
4593     html :  '&lt;div name="{id}"&gt;' + 
4594         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4595         '&lt;/div&gt;',
4596     myformat: function (value, allValues) {
4597         return 'XX' + value;
4598     }
4599 });
4600 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4601 </code></pre>
4602 * For more information see this blog post with examples:
4603 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4604      - Create Elements using DOM, HTML fragments and Templates</a>. 
4605 * @constructor
4606 * @param {Object} cfg - Configuration object.
4607 */
4608 Roo.Template = function(cfg){
4609     // BC!
4610     if(cfg instanceof Array){
4611         cfg = cfg.join("");
4612     }else if(arguments.length > 1){
4613         cfg = Array.prototype.join.call(arguments, "");
4614     }
4615     
4616     
4617     if (typeof(cfg) == 'object') {
4618         Roo.apply(this,cfg)
4619     } else {
4620         // bc
4621         this.html = cfg;
4622     }
4623     if (this.url) {
4624         this.load();
4625     }
4626     
4627 };
4628 Roo.Template.prototype = {
4629     
4630     /**
4631      * @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..
4632      *                    it should be fixed so that template is observable...
4633      */
4634     url : false,
4635     /**
4636      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4637      */
4638     html : '',
4639     /**
4640      * Returns an HTML fragment of this template with the specified values applied.
4641      * @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'})
4642      * @return {String} The HTML fragment
4643      */
4644     applyTemplate : function(values){
4645         try {
4646            
4647             if(this.compiled){
4648                 return this.compiled(values);
4649             }
4650             var useF = this.disableFormats !== true;
4651             var fm = Roo.util.Format, tpl = this;
4652             var fn = function(m, name, format, args){
4653                 if(format && useF){
4654                     if(format.substr(0, 5) == "this."){
4655                         return tpl.call(format.substr(5), values[name], values);
4656                     }else{
4657                         if(args){
4658                             // quoted values are required for strings in compiled templates, 
4659                             // but for non compiled we need to strip them
4660                             // quoted reversed for jsmin
4661                             var re = /^\s*['"](.*)["']\s*$/;
4662                             args = args.split(',');
4663                             for(var i = 0, len = args.length; i < len; i++){
4664                                 args[i] = args[i].replace(re, "$1");
4665                             }
4666                             args = [values[name]].concat(args);
4667                         }else{
4668                             args = [values[name]];
4669                         }
4670                         return fm[format].apply(fm, args);
4671                     }
4672                 }else{
4673                     return values[name] !== undefined ? values[name] : "";
4674                 }
4675             };
4676             return this.html.replace(this.re, fn);
4677         } catch (e) {
4678             Roo.log(e);
4679             throw e;
4680         }
4681          
4682     },
4683     
4684     loading : false,
4685       
4686     load : function ()
4687     {
4688          
4689         if (this.loading) {
4690             return;
4691         }
4692         var _t = this;
4693         
4694         this.loading = true;
4695         this.compiled = false;
4696         
4697         var cx = new Roo.data.Connection();
4698         cx.request({
4699             url : this.url,
4700             method : 'GET',
4701             success : function (response) {
4702                 _t.loading = false;
4703                 _t.html = response.responseText;
4704                 _t.url = false;
4705                 _t.compile();
4706              },
4707             failure : function(response) {
4708                 Roo.log("Template failed to load from " + _t.url);
4709                 _t.loading = false;
4710             }
4711         });
4712     },
4713
4714     /**
4715      * Sets the HTML used as the template and optionally compiles it.
4716      * @param {String} html
4717      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4718      * @return {Roo.Template} this
4719      */
4720     set : function(html, compile){
4721         this.html = html;
4722         this.compiled = null;
4723         if(compile){
4724             this.compile();
4725         }
4726         return this;
4727     },
4728     
4729     /**
4730      * True to disable format functions (defaults to false)
4731      * @type Boolean
4732      */
4733     disableFormats : false,
4734     
4735     /**
4736     * The regular expression used to match template variables 
4737     * @type RegExp
4738     * @property 
4739     */
4740     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4741     
4742     /**
4743      * Compiles the template into an internal function, eliminating the RegEx overhead.
4744      * @return {Roo.Template} this
4745      */
4746     compile : function(){
4747         var fm = Roo.util.Format;
4748         var useF = this.disableFormats !== true;
4749         var sep = Roo.isGecko ? "+" : ",";
4750         var fn = function(m, name, format, args){
4751             if(format && useF){
4752                 args = args ? ',' + args : "";
4753                 if(format.substr(0, 5) != "this."){
4754                     format = "fm." + format + '(';
4755                 }else{
4756                     format = 'this.call("'+ format.substr(5) + '", ';
4757                     args = ", values";
4758                 }
4759             }else{
4760                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4761             }
4762             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4763         };
4764         var body;
4765         // branched to use + in gecko and [].join() in others
4766         if(Roo.isGecko){
4767             body = "this.compiled = function(values){ return '" +
4768                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4769                     "';};";
4770         }else{
4771             body = ["this.compiled = function(values){ return ['"];
4772             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4773             body.push("'].join('');};");
4774             body = body.join('');
4775         }
4776         /**
4777          * eval:var:values
4778          * eval:var:fm
4779          */
4780         eval(body);
4781         return this;
4782     },
4783     
4784     // private function used to call members
4785     call : function(fnName, value, allValues){
4786         return this[fnName](value, allValues);
4787     },
4788     
4789     /**
4790      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4791      * @param {String/HTMLElement/Roo.Element} el The context element
4792      * @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'})
4793      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4794      * @return {HTMLElement/Roo.Element} The new node or Element
4795      */
4796     insertFirst: function(el, values, returnElement){
4797         return this.doInsert('afterBegin', el, values, returnElement);
4798     },
4799
4800     /**
4801      * Applies the supplied values to the template and inserts the new node(s) before el.
4802      * @param {String/HTMLElement/Roo.Element} el The context element
4803      * @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'})
4804      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4805      * @return {HTMLElement/Roo.Element} The new node or Element
4806      */
4807     insertBefore: function(el, values, returnElement){
4808         return this.doInsert('beforeBegin', el, values, returnElement);
4809     },
4810
4811     /**
4812      * Applies the supplied values to the template and inserts the new node(s) after el.
4813      * @param {String/HTMLElement/Roo.Element} el The context element
4814      * @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'})
4815      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4816      * @return {HTMLElement/Roo.Element} The new node or Element
4817      */
4818     insertAfter : function(el, values, returnElement){
4819         return this.doInsert('afterEnd', el, values, returnElement);
4820     },
4821     
4822     /**
4823      * Applies the supplied values to the template and appends the new node(s) to el.
4824      * @param {String/HTMLElement/Roo.Element} el The context element
4825      * @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'})
4826      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4827      * @return {HTMLElement/Roo.Element} The new node or Element
4828      */
4829     append : function(el, values, returnElement){
4830         return this.doInsert('beforeEnd', el, values, returnElement);
4831     },
4832
4833     doInsert : function(where, el, values, returnEl){
4834         el = Roo.getDom(el);
4835         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4836         return returnEl ? Roo.get(newNode, true) : newNode;
4837     },
4838
4839     /**
4840      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4841      * @param {String/HTMLElement/Roo.Element} el The context element
4842      * @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'})
4843      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4844      * @return {HTMLElement/Roo.Element} The new node or Element
4845      */
4846     overwrite : function(el, values, returnElement){
4847         el = Roo.getDom(el);
4848         el.innerHTML = this.applyTemplate(values);
4849         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4850     }
4851 };
4852 /**
4853  * Alias for {@link #applyTemplate}
4854  * @method
4855  */
4856 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4857
4858 // backwards compat
4859 Roo.DomHelper.Template = Roo.Template;
4860
4861 /**
4862  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4863  * @param {String/HTMLElement} el A DOM element or its id
4864  * @returns {Roo.Template} The created template
4865  * @static
4866  */
4867 Roo.Template.from = function(el){
4868     el = Roo.getDom(el);
4869     return new Roo.Template(el.value || el.innerHTML);
4870 };/*
4871  * Based on:
4872  * Ext JS Library 1.1.1
4873  * Copyright(c) 2006-2007, Ext JS, LLC.
4874  *
4875  * Originally Released Under LGPL - original licence link has changed is not relivant.
4876  *
4877  * Fork - LGPL
4878  * <script type="text/javascript">
4879  */
4880  
4881
4882 /*
4883  * This is code is also distributed under MIT license for use
4884  * with jQuery and prototype JavaScript libraries.
4885  */
4886 /**
4887  * @class Roo.DomQuery
4888 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).
4889 <p>
4890 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>
4891
4892 <p>
4893 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.
4894 </p>
4895 <h4>Element Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>*</b> any element</li>
4898     <li> <b>E</b> an element with the tag E</li>
4899     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4900     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4901     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4902     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4903 </ul>
4904 <h4>Attribute Selectors:</h4>
4905 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4906 <ul class="list">
4907     <li> <b>E[foo]</b> has an attribute "foo"</li>
4908     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4909     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4910     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4911     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4912     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4913     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4914 </ul>
4915 <h4>Pseudo Classes:</h4>
4916 <ul class="list">
4917     <li> <b>E:first-child</b> E is the first child of its parent</li>
4918     <li> <b>E:last-child</b> E is the last child of its parent</li>
4919     <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>
4920     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4921     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4922     <li> <b>E:only-child</b> E is the only child of its parent</li>
4923     <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>
4924     <li> <b>E:first</b> the first E in the resultset</li>
4925     <li> <b>E:last</b> the last E in the resultset</li>
4926     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4927     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4928     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4929     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4930     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4931     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4932     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4933     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4934     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4935 </ul>
4936 <h4>CSS Value Selectors:</h4>
4937 <ul class="list">
4938     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4939     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4940     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4941     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4942     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4943     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4944 </ul>
4945  * @singleton
4946  */
4947 Roo.DomQuery = function(){
4948     var cache = {}, simpleCache = {}, valueCache = {};
4949     var nonSpace = /\S/;
4950     var trimRe = /^\s+|\s+$/g;
4951     var tplRe = /\{(\d+)\}/g;
4952     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4953     var tagTokenRe = /^(#)?([\w-\*]+)/;
4954     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4955
4956     function child(p, index){
4957         var i = 0;
4958         var n = p.firstChild;
4959         while(n){
4960             if(n.nodeType == 1){
4961                if(++i == index){
4962                    return n;
4963                }
4964             }
4965             n = n.nextSibling;
4966         }
4967         return null;
4968     };
4969
4970     function next(n){
4971         while((n = n.nextSibling) && n.nodeType != 1);
4972         return n;
4973     };
4974
4975     function prev(n){
4976         while((n = n.previousSibling) && n.nodeType != 1);
4977         return n;
4978     };
4979
4980     function children(d){
4981         var n = d.firstChild, ni = -1;
4982             while(n){
4983                 var nx = n.nextSibling;
4984                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4985                     d.removeChild(n);
4986                 }else{
4987                     n.nodeIndex = ++ni;
4988                 }
4989                 n = nx;
4990             }
4991             return this;
4992         };
4993
4994     function byClassName(c, a, v){
4995         if(!v){
4996             return c;
4997         }
4998         var r = [], ri = -1, cn;
4999         for(var i = 0, ci; ci = c[i]; i++){
5000             if((' '+ci.className+' ').indexOf(v) != -1){
5001                 r[++ri] = ci;
5002             }
5003         }
5004         return r;
5005     };
5006
5007     function attrValue(n, attr){
5008         if(!n.tagName && typeof n.length != "undefined"){
5009             n = n[0];
5010         }
5011         if(!n){
5012             return null;
5013         }
5014         if(attr == "for"){
5015             return n.htmlFor;
5016         }
5017         if(attr == "class" || attr == "className"){
5018             return n.className;
5019         }
5020         return n.getAttribute(attr) || n[attr];
5021
5022     };
5023
5024     function getNodes(ns, mode, tagName){
5025         var result = [], ri = -1, cs;
5026         if(!ns){
5027             return result;
5028         }
5029         tagName = tagName || "*";
5030         if(typeof ns.getElementsByTagName != "undefined"){
5031             ns = [ns];
5032         }
5033         if(!mode){
5034             for(var i = 0, ni; ni = ns[i]; i++){
5035                 cs = ni.getElementsByTagName(tagName);
5036                 for(var j = 0, ci; ci = cs[j]; j++){
5037                     result[++ri] = ci;
5038                 }
5039             }
5040         }else if(mode == "/" || mode == ">"){
5041             var utag = tagName.toUpperCase();
5042             for(var i = 0, ni, cn; ni = ns[i]; i++){
5043                 cn = ni.children || ni.childNodes;
5044                 for(var j = 0, cj; cj = cn[j]; j++){
5045                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5046                         result[++ri] = cj;
5047                     }
5048                 }
5049             }
5050         }else if(mode == "+"){
5051             var utag = tagName.toUpperCase();
5052             for(var i = 0, n; n = ns[i]; i++){
5053                 while((n = n.nextSibling) && n.nodeType != 1);
5054                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5055                     result[++ri] = n;
5056                 }
5057             }
5058         }else if(mode == "~"){
5059             for(var i = 0, n; n = ns[i]; i++){
5060                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5061                 if(n){
5062                     result[++ri] = n;
5063                 }
5064             }
5065         }
5066         return result;
5067     };
5068
5069     function concat(a, b){
5070         if(b.slice){
5071             return a.concat(b);
5072         }
5073         for(var i = 0, l = b.length; i < l; i++){
5074             a[a.length] = b[i];
5075         }
5076         return a;
5077     }
5078
5079     function byTag(cs, tagName){
5080         if(cs.tagName || cs == document){
5081             cs = [cs];
5082         }
5083         if(!tagName){
5084             return cs;
5085         }
5086         var r = [], ri = -1;
5087         tagName = tagName.toLowerCase();
5088         for(var i = 0, ci; ci = cs[i]; i++){
5089             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byId(cs, attr, id){
5097         if(cs.tagName || cs == document){
5098             cs = [cs];
5099         }
5100         if(!id){
5101             return cs;
5102         }
5103         var r = [], ri = -1;
5104         for(var i = 0,ci; ci = cs[i]; i++){
5105             if(ci && ci.id == id){
5106                 r[++ri] = ci;
5107                 return r;
5108             }
5109         }
5110         return r;
5111     };
5112
5113     function byAttribute(cs, attr, value, op, custom){
5114         var r = [], ri = -1, st = custom=="{";
5115         var f = Roo.DomQuery.operators[op];
5116         for(var i = 0, ci; ci = cs[i]; i++){
5117             var a;
5118             if(st){
5119                 a = Roo.DomQuery.getStyle(ci, attr);
5120             }
5121             else if(attr == "class" || attr == "className"){
5122                 a = ci.className;
5123             }else if(attr == "for"){
5124                 a = ci.htmlFor;
5125             }else if(attr == "href"){
5126                 a = ci.getAttribute("href", 2);
5127             }else{
5128                 a = ci.getAttribute(attr);
5129             }
5130             if((f && f(a, value)) || (!f && a)){
5131                 r[++ri] = ci;
5132             }
5133         }
5134         return r;
5135     };
5136
5137     function byPseudo(cs, name, value){
5138         return Roo.DomQuery.pseudos[name](cs, value);
5139     };
5140
5141     // This is for IE MSXML which does not support expandos.
5142     // IE runs the same speed using setAttribute, however FF slows way down
5143     // and Safari completely fails so they need to continue to use expandos.
5144     var isIE = window.ActiveXObject ? true : false;
5145
5146     // this eval is stop the compressor from
5147     // renaming the variable to something shorter
5148     
5149     /** eval:var:batch */
5150     var batch = 30803; 
5151
5152     var key = 30803;
5153
5154     function nodupIEXml(cs){
5155         var d = ++key;
5156         cs[0].setAttribute("_nodup", d);
5157         var r = [cs[0]];
5158         for(var i = 1, len = cs.length; i < len; i++){
5159             var c = cs[i];
5160             if(!c.getAttribute("_nodup") != d){
5161                 c.setAttribute("_nodup", d);
5162                 r[r.length] = c;
5163             }
5164         }
5165         for(var i = 0, len = cs.length; i < len; i++){
5166             cs[i].removeAttribute("_nodup");
5167         }
5168         return r;
5169     }
5170
5171     function nodup(cs){
5172         if(!cs){
5173             return [];
5174         }
5175         var len = cs.length, c, i, r = cs, cj, ri = -1;
5176         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5177             return cs;
5178         }
5179         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5180             return nodupIEXml(cs);
5181         }
5182         var d = ++key;
5183         cs[0]._nodup = d;
5184         for(i = 1; c = cs[i]; i++){
5185             if(c._nodup != d){
5186                 c._nodup = d;
5187             }else{
5188                 r = [];
5189                 for(var j = 0; j < i; j++){
5190                     r[++ri] = cs[j];
5191                 }
5192                 for(j = i+1; cj = cs[j]; j++){
5193                     if(cj._nodup != d){
5194                         cj._nodup = d;
5195                         r[++ri] = cj;
5196                     }
5197                 }
5198                 return r;
5199             }
5200         }
5201         return r;
5202     }
5203
5204     function quickDiffIEXml(c1, c2){
5205         var d = ++key;
5206         for(var i = 0, len = c1.length; i < len; i++){
5207             c1[i].setAttribute("_qdiff", d);
5208         }
5209         var r = [];
5210         for(var i = 0, len = c2.length; i < len; i++){
5211             if(c2[i].getAttribute("_qdiff") != d){
5212                 r[r.length] = c2[i];
5213             }
5214         }
5215         for(var i = 0, len = c1.length; i < len; i++){
5216            c1[i].removeAttribute("_qdiff");
5217         }
5218         return r;
5219     }
5220
5221     function quickDiff(c1, c2){
5222         var len1 = c1.length;
5223         if(!len1){
5224             return c2;
5225         }
5226         if(isIE && c1[0].selectSingleNode){
5227             return quickDiffIEXml(c1, c2);
5228         }
5229         var d = ++key;
5230         for(var i = 0; i < len1; i++){
5231             c1[i]._qdiff = d;
5232         }
5233         var r = [];
5234         for(var i = 0, len = c2.length; i < len; i++){
5235             if(c2[i]._qdiff != d){
5236                 r[r.length] = c2[i];
5237             }
5238         }
5239         return r;
5240     }
5241
5242     function quickId(ns, mode, root, id){
5243         if(ns == root){
5244            var d = root.ownerDocument || root;
5245            return d.getElementById(id);
5246         }
5247         ns = getNodes(ns, mode, "*");
5248         return byId(ns, null, id);
5249     }
5250
5251     return {
5252         getStyle : function(el, name){
5253             return Roo.fly(el).getStyle(name);
5254         },
5255         /**
5256          * Compiles a selector/xpath query into a reusable function. The returned function
5257          * takes one parameter "root" (optional), which is the context node from where the query should start.
5258          * @param {String} selector The selector/xpath query
5259          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5260          * @return {Function}
5261          */
5262         compile : function(path, type){
5263             type = type || "select";
5264             
5265             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5266             var q = path, mode, lq;
5267             var tk = Roo.DomQuery.matchers;
5268             var tklen = tk.length;
5269             var mm;
5270
5271             // accept leading mode switch
5272             var lmode = q.match(modeRe);
5273             if(lmode && lmode[1]){
5274                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5275                 q = q.replace(lmode[1], "");
5276             }
5277             // strip leading slashes
5278             while(path.substr(0, 1)=="/"){
5279                 path = path.substr(1);
5280             }
5281
5282             while(q && lq != q){
5283                 lq = q;
5284                 var tm = q.match(tagTokenRe);
5285                 if(type == "select"){
5286                     if(tm){
5287                         if(tm[1] == "#"){
5288                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5289                         }else{
5290                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5291                         }
5292                         q = q.replace(tm[0], "");
5293                     }else if(q.substr(0, 1) != '@'){
5294                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5295                     }
5296                 }else{
5297                     if(tm){
5298                         if(tm[1] == "#"){
5299                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5300                         }else{
5301                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5302                         }
5303                         q = q.replace(tm[0], "");
5304                     }
5305                 }
5306                 while(!(mm = q.match(modeRe))){
5307                     var matched = false;
5308                     for(var j = 0; j < tklen; j++){
5309                         var t = tk[j];
5310                         var m = q.match(t.re);
5311                         if(m){
5312                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5313                                                     return m[i];
5314                                                 });
5315                             q = q.replace(m[0], "");
5316                             matched = true;
5317                             break;
5318                         }
5319                     }
5320                     // prevent infinite loop on bad selector
5321                     if(!matched){
5322                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5323                     }
5324                 }
5325                 if(mm[1]){
5326                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5327                     q = q.replace(mm[1], "");
5328                 }
5329             }
5330             fn[fn.length] = "return nodup(n);\n}";
5331             
5332              /** 
5333               * list of variables that need from compression as they are used by eval.
5334              *  eval:var:batch 
5335              *  eval:var:nodup
5336              *  eval:var:byTag
5337              *  eval:var:ById
5338              *  eval:var:getNodes
5339              *  eval:var:quickId
5340              *  eval:var:mode
5341              *  eval:var:root
5342              *  eval:var:n
5343              *  eval:var:byClassName
5344              *  eval:var:byPseudo
5345              *  eval:var:byAttribute
5346              *  eval:var:attrValue
5347              * 
5348              **/ 
5349             eval(fn.join(""));
5350             return f;
5351         },
5352
5353         /**
5354          * Selects a group of elements.
5355          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5356          * @param {Node} root (optional) The start of the query (defaults to document).
5357          * @return {Array}
5358          */
5359         select : function(path, root, type){
5360             if(!root || root == document){
5361                 root = document;
5362             }
5363             if(typeof root == "string"){
5364                 root = document.getElementById(root);
5365             }
5366             var paths = path.split(",");
5367             var results = [];
5368             for(var i = 0, len = paths.length; i < len; i++){
5369                 var p = paths[i].replace(trimRe, "");
5370                 if(!cache[p]){
5371                     cache[p] = Roo.DomQuery.compile(p);
5372                     if(!cache[p]){
5373                         throw p + " is not a valid selector";
5374                     }
5375                 }
5376                 var result = cache[p](root);
5377                 if(result && result != document){
5378                     results = results.concat(result);
5379                 }
5380             }
5381             if(paths.length > 1){
5382                 return nodup(results);
5383             }
5384             return results;
5385         },
5386
5387         /**
5388          * Selects a single element.
5389          * @param {String} selector The selector/xpath query
5390          * @param {Node} root (optional) The start of the query (defaults to document).
5391          * @return {Element}
5392          */
5393         selectNode : function(path, root){
5394             return Roo.DomQuery.select(path, root)[0];
5395         },
5396
5397         /**
5398          * Selects the value of a node, optionally replacing null with the defaultValue.
5399          * @param {String} selector The selector/xpath query
5400          * @param {Node} root (optional) The start of the query (defaults to document).
5401          * @param {String} defaultValue
5402          */
5403         selectValue : function(path, root, defaultValue){
5404             path = path.replace(trimRe, "");
5405             if(!valueCache[path]){
5406                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5407             }
5408             var n = valueCache[path](root);
5409             n = n[0] ? n[0] : n;
5410             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5411             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5412         },
5413
5414         /**
5415          * Selects the value of a node, parsing integers and floats.
5416          * @param {String} selector The selector/xpath query
5417          * @param {Node} root (optional) The start of the query (defaults to document).
5418          * @param {Number} defaultValue
5419          * @return {Number}
5420          */
5421         selectNumber : function(path, root, defaultValue){
5422             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5423             return parseFloat(v);
5424         },
5425
5426         /**
5427          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5428          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5429          * @param {String} selector The simple selector to test
5430          * @return {Boolean}
5431          */
5432         is : function(el, ss){
5433             if(typeof el == "string"){
5434                 el = document.getElementById(el);
5435             }
5436             var isArray = (el instanceof Array);
5437             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5438             return isArray ? (result.length == el.length) : (result.length > 0);
5439         },
5440
5441         /**
5442          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5443          * @param {Array} el An array of elements to filter
5444          * @param {String} selector The simple selector to test
5445          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5446          * the selector instead of the ones that match
5447          * @return {Array}
5448          */
5449         filter : function(els, ss, nonMatches){
5450             ss = ss.replace(trimRe, "");
5451             if(!simpleCache[ss]){
5452                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5453             }
5454             var result = simpleCache[ss](els);
5455             return nonMatches ? quickDiff(result, els) : result;
5456         },
5457
5458         /**
5459          * Collection of matching regular expressions and code snippets.
5460          */
5461         matchers : [{
5462                 re: /^\.([\w-]+)/,
5463                 select: 'n = byClassName(n, null, " {1} ");'
5464             }, {
5465                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5466                 select: 'n = byPseudo(n, "{1}", "{2}");'
5467             },{
5468                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5469                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5470             }, {
5471                 re: /^#([\w-]+)/,
5472                 select: 'n = byId(n, null, "{1}");'
5473             },{
5474                 re: /^@([\w-]+)/,
5475                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5476             }
5477         ],
5478
5479         /**
5480          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5481          * 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;.
5482          */
5483         operators : {
5484             "=" : function(a, v){
5485                 return a == v;
5486             },
5487             "!=" : function(a, v){
5488                 return a != v;
5489             },
5490             "^=" : function(a, v){
5491                 return a && a.substr(0, v.length) == v;
5492             },
5493             "$=" : function(a, v){
5494                 return a && a.substr(a.length-v.length) == v;
5495             },
5496             "*=" : function(a, v){
5497                 return a && a.indexOf(v) !== -1;
5498             },
5499             "%=" : function(a, v){
5500                 return (a % v) == 0;
5501             },
5502             "|=" : function(a, v){
5503                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5504             },
5505             "~=" : function(a, v){
5506                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5507             }
5508         },
5509
5510         /**
5511          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5512          * and the argument (if any) supplied in the selector.
5513          */
5514         pseudos : {
5515             "first-child" : function(c){
5516                 var r = [], ri = -1, n;
5517                 for(var i = 0, ci; ci = n = c[i]; i++){
5518                     while((n = n.previousSibling) && n.nodeType != 1);
5519                     if(!n){
5520                         r[++ri] = ci;
5521                     }
5522                 }
5523                 return r;
5524             },
5525
5526             "last-child" : function(c){
5527                 var r = [], ri = -1, n;
5528                 for(var i = 0, ci; ci = n = c[i]; i++){
5529                     while((n = n.nextSibling) && n.nodeType != 1);
5530                     if(!n){
5531                         r[++ri] = ci;
5532                     }
5533                 }
5534                 return r;
5535             },
5536
5537             "nth-child" : function(c, a) {
5538                 var r = [], ri = -1;
5539                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5540                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5541                 for(var i = 0, n; n = c[i]; i++){
5542                     var pn = n.parentNode;
5543                     if (batch != pn._batch) {
5544                         var j = 0;
5545                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5546                             if(cn.nodeType == 1){
5547                                cn.nodeIndex = ++j;
5548                             }
5549                         }
5550                         pn._batch = batch;
5551                     }
5552                     if (f == 1) {
5553                         if (l == 0 || n.nodeIndex == l){
5554                             r[++ri] = n;
5555                         }
5556                     } else if ((n.nodeIndex + l) % f == 0){
5557                         r[++ri] = n;
5558                     }
5559                 }
5560
5561                 return r;
5562             },
5563
5564             "only-child" : function(c){
5565                 var r = [], ri = -1;;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if(!prev(ci) && !next(ci)){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "empty" : function(c){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     var cns = ci.childNodes, j = 0, cn, empty = true;
5578                     while(cn = cns[j]){
5579                         ++j;
5580                         if(cn.nodeType == 1 || cn.nodeType == 3){
5581                             empty = false;
5582                             break;
5583                         }
5584                     }
5585                     if(empty){
5586                         r[++ri] = ci;
5587                     }
5588                 }
5589                 return r;
5590             },
5591
5592             "contains" : function(c, v){
5593                 var r = [], ri = -1;
5594                 for(var i = 0, ci; ci = c[i]; i++){
5595                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5596                         r[++ri] = ci;
5597                     }
5598                 }
5599                 return r;
5600             },
5601
5602             "nodeValue" : function(c, v){
5603                 var r = [], ri = -1;
5604                 for(var i = 0, ci; ci = c[i]; i++){
5605                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5606                         r[++ri] = ci;
5607                     }
5608                 }
5609                 return r;
5610             },
5611
5612             "checked" : function(c){
5613                 var r = [], ri = -1;
5614                 for(var i = 0, ci; ci = c[i]; i++){
5615                     if(ci.checked == true){
5616                         r[++ri] = ci;
5617                     }
5618                 }
5619                 return r;
5620             },
5621
5622             "not" : function(c, ss){
5623                 return Roo.DomQuery.filter(c, ss, true);
5624             },
5625
5626             "odd" : function(c){
5627                 return this["nth-child"](c, "odd");
5628             },
5629
5630             "even" : function(c){
5631                 return this["nth-child"](c, "even");
5632             },
5633
5634             "nth" : function(c, a){
5635                 return c[a-1] || [];
5636             },
5637
5638             "first" : function(c){
5639                 return c[0] || [];
5640             },
5641
5642             "last" : function(c){
5643                 return c[c.length-1] || [];
5644             },
5645
5646             "has" : function(c, ss){
5647                 var s = Roo.DomQuery.select;
5648                 var r = [], ri = -1;
5649                 for(var i = 0, ci; ci = c[i]; i++){
5650                     if(s(ss, ci).length > 0){
5651                         r[++ri] = ci;
5652                     }
5653                 }
5654                 return r;
5655             },
5656
5657             "next" : function(c, ss){
5658                 var is = Roo.DomQuery.is;
5659                 var r = [], ri = -1;
5660                 for(var i = 0, ci; ci = c[i]; i++){
5661                     var n = next(ci);
5662                     if(n && is(n, ss)){
5663                         r[++ri] = ci;
5664                     }
5665                 }
5666                 return r;
5667             },
5668
5669             "prev" : function(c, ss){
5670                 var is = Roo.DomQuery.is;
5671                 var r = [], ri = -1;
5672                 for(var i = 0, ci; ci = c[i]; i++){
5673                     var n = prev(ci);
5674                     if(n && is(n, ss)){
5675                         r[++ri] = ci;
5676                     }
5677                 }
5678                 return r;
5679             }
5680         }
5681     };
5682 }();
5683
5684 /**
5685  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5686  * @param {String} path The selector/xpath query
5687  * @param {Node} root (optional) The start of the query (defaults to document).
5688  * @return {Array}
5689  * @member Roo
5690  * @method query
5691  */
5692 Roo.query = Roo.DomQuery.select;
5693 /*
5694  * Based on:
5695  * Ext JS Library 1.1.1
5696  * Copyright(c) 2006-2007, Ext JS, LLC.
5697  *
5698  * Originally Released Under LGPL - original licence link has changed is not relivant.
5699  *
5700  * Fork - LGPL
5701  * <script type="text/javascript">
5702  */
5703
5704 /**
5705  * @class Roo.util.Observable
5706  * Base class that provides a common interface for publishing events. Subclasses are expected to
5707  * to have a property "events" with all the events defined.<br>
5708  * For example:
5709  * <pre><code>
5710  Employee = function(name){
5711     this.name = name;
5712     this.addEvents({
5713         "fired" : true,
5714         "quit" : true
5715     });
5716  }
5717  Roo.extend(Employee, Roo.util.Observable);
5718 </code></pre>
5719  * @param {Object} config properties to use (incuding events / listeners)
5720  */
5721
5722 Roo.util.Observable = function(cfg){
5723     
5724     cfg = cfg|| {};
5725     this.addEvents(cfg.events || {});
5726     if (cfg.events) {
5727         delete cfg.events; // make sure
5728     }
5729      
5730     Roo.apply(this, cfg);
5731     
5732     if(this.listeners){
5733         this.on(this.listeners);
5734         delete this.listeners;
5735     }
5736 };
5737 Roo.util.Observable.prototype = {
5738     /** 
5739  * @cfg {Object} listeners  list of events and functions to call for this object, 
5740  * For example :
5741  * <pre><code>
5742     listeners :  { 
5743        'click' : function(e) {
5744            ..... 
5745         } ,
5746         .... 
5747     } 
5748   </code></pre>
5749  */
5750     
5751     
5752     /**
5753      * Fires the specified event with the passed parameters (minus the event name).
5754      * @param {String} eventName
5755      * @param {Object...} args Variable number of parameters are passed to handlers
5756      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5757      */
5758     fireEvent : function(){
5759         var ce = this.events[arguments[0].toLowerCase()];
5760         if(typeof ce == "object"){
5761             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5762         }else{
5763             return true;
5764         }
5765     },
5766
5767     // private
5768     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5769
5770     /**
5771      * Appends an event handler to this component
5772      * @param {String}   eventName The type of event to listen for
5773      * @param {Function} handler The method the event invokes
5774      * @param {Object}   scope (optional) The scope in which to execute the handler
5775      * function. The handler function's "this" context.
5776      * @param {Object}   options (optional) An object containing handler configuration
5777      * properties. This may contain any of the following properties:<ul>
5778      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5779      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5780      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5781      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5782      * by the specified number of milliseconds. If the event fires again within that time, the original
5783      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5784      * </ul><br>
5785      * <p>
5786      * <b>Combining Options</b><br>
5787      * Using the options argument, it is possible to combine different types of listeners:<br>
5788      * <br>
5789      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5790                 <pre><code>
5791                 el.on('click', this.onClick, this, {
5792                         single: true,
5793                 delay: 100,
5794                 forumId: 4
5795                 });
5796                 </code></pre>
5797      * <p>
5798      * <b>Attaching multiple handlers in 1 call</b><br>
5799      * The method also allows for a single argument to be passed which is a config object containing properties
5800      * which specify multiple handlers.
5801      * <pre><code>
5802                 el.on({
5803                         'click': {
5804                         fn: this.onClick,
5805                         scope: this,
5806                         delay: 100
5807                 }, 
5808                 'mouseover': {
5809                         fn: this.onMouseOver,
5810                         scope: this
5811                 },
5812                 'mouseout': {
5813                         fn: this.onMouseOut,
5814                         scope: this
5815                 }
5816                 });
5817                 </code></pre>
5818      * <p>
5819      * Or a shorthand syntax which passes the same scope object to all handlers:
5820         <pre><code>
5821                 el.on({
5822                         'click': this.onClick,
5823                 'mouseover': this.onMouseOver,
5824                 'mouseout': this.onMouseOut,
5825                 scope: this
5826                 });
5827                 </code></pre>
5828      */
5829     addListener : function(eventName, fn, scope, o){
5830         if(typeof eventName == "object"){
5831             o = eventName;
5832             for(var e in o){
5833                 if(this.filterOptRe.test(e)){
5834                     continue;
5835                 }
5836                 if(typeof o[e] == "function"){
5837                     // shared options
5838                     this.addListener(e, o[e], o.scope,  o);
5839                 }else{
5840                     // individual options
5841                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5842                 }
5843             }
5844             return;
5845         }
5846         o = (!o || typeof o == "boolean") ? {} : o;
5847         eventName = eventName.toLowerCase();
5848         var ce = this.events[eventName] || true;
5849         if(typeof ce == "boolean"){
5850             ce = new Roo.util.Event(this, eventName);
5851             this.events[eventName] = ce;
5852         }
5853         ce.addListener(fn, scope, o);
5854     },
5855
5856     /**
5857      * Removes a listener
5858      * @param {String}   eventName     The type of event to listen for
5859      * @param {Function} handler        The handler to remove
5860      * @param {Object}   scope  (optional) The scope (this object) for the handler
5861      */
5862     removeListener : function(eventName, fn, scope){
5863         var ce = this.events[eventName.toLowerCase()];
5864         if(typeof ce == "object"){
5865             ce.removeListener(fn, scope);
5866         }
5867     },
5868
5869     /**
5870      * Removes all listeners for this object
5871      */
5872     purgeListeners : function(){
5873         for(var evt in this.events){
5874             if(typeof this.events[evt] == "object"){
5875                  this.events[evt].clearListeners();
5876             }
5877         }
5878     },
5879
5880     relayEvents : function(o, events){
5881         var createHandler = function(ename){
5882             return function(){
5883                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5884             };
5885         };
5886         for(var i = 0, len = events.length; i < len; i++){
5887             var ename = events[i];
5888             if(!this.events[ename]){ this.events[ename] = true; };
5889             o.on(ename, createHandler(ename), this);
5890         }
5891     },
5892
5893     /**
5894      * Used to define events on this Observable
5895      * @param {Object} object The object with the events defined
5896      */
5897     addEvents : function(o){
5898         if(!this.events){
5899             this.events = {};
5900         }
5901         Roo.applyIf(this.events, o);
5902     },
5903
5904     /**
5905      * Checks to see if this object has any listeners for a specified event
5906      * @param {String} eventName The name of the event to check for
5907      * @return {Boolean} True if the event is being listened for, else false
5908      */
5909     hasListener : function(eventName){
5910         var e = this.events[eventName];
5911         return typeof e == "object" && e.listeners.length > 0;
5912     }
5913 };
5914 /**
5915  * Appends an event handler to this element (shorthand for addListener)
5916  * @param {String}   eventName     The type of event to listen for
5917  * @param {Function} handler        The method the event invokes
5918  * @param {Object}   scope (optional) The scope in which to execute the handler
5919  * function. The handler function's "this" context.
5920  * @param {Object}   options  (optional)
5921  * @method
5922  */
5923 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5924 /**
5925  * Removes a listener (shorthand for removeListener)
5926  * @param {String}   eventName     The type of event to listen for
5927  * @param {Function} handler        The handler to remove
5928  * @param {Object}   scope  (optional) The scope (this object) for the handler
5929  * @method
5930  */
5931 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5932
5933 /**
5934  * Starts capture on the specified Observable. All events will be passed
5935  * to the supplied function with the event name + standard signature of the event
5936  * <b>before</b> the event is fired. If the supplied function returns false,
5937  * the event will not fire.
5938  * @param {Observable} o The Observable to capture
5939  * @param {Function} fn The function to call
5940  * @param {Object} scope (optional) The scope (this object) for the fn
5941  * @static
5942  */
5943 Roo.util.Observable.capture = function(o, fn, scope){
5944     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5945 };
5946
5947 /**
5948  * Removes <b>all</b> added captures from the Observable.
5949  * @param {Observable} o The Observable to release
5950  * @static
5951  */
5952 Roo.util.Observable.releaseCapture = function(o){
5953     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5954 };
5955
5956 (function(){
5957
5958     var createBuffered = function(h, o, scope){
5959         var task = new Roo.util.DelayedTask();
5960         return function(){
5961             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5962         };
5963     };
5964
5965     var createSingle = function(h, e, fn, scope){
5966         return function(){
5967             e.removeListener(fn, scope);
5968             return h.apply(scope, arguments);
5969         };
5970     };
5971
5972     var createDelayed = function(h, o, scope){
5973         return function(){
5974             var args = Array.prototype.slice.call(arguments, 0);
5975             setTimeout(function(){
5976                 h.apply(scope, args);
5977             }, o.delay || 10);
5978         };
5979     };
5980
5981     Roo.util.Event = function(obj, name){
5982         this.name = name;
5983         this.obj = obj;
5984         this.listeners = [];
5985     };
5986
5987     Roo.util.Event.prototype = {
5988         addListener : function(fn, scope, options){
5989             var o = options || {};
5990             scope = scope || this.obj;
5991             if(!this.isListening(fn, scope)){
5992                 var l = {fn: fn, scope: scope, options: o};
5993                 var h = fn;
5994                 if(o.delay){
5995                     h = createDelayed(h, o, scope);
5996                 }
5997                 if(o.single){
5998                     h = createSingle(h, this, fn, scope);
5999                 }
6000                 if(o.buffer){
6001                     h = createBuffered(h, o, scope);
6002                 }
6003                 l.fireFn = h;
6004                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6005                     this.listeners.push(l);
6006                 }else{
6007                     this.listeners = this.listeners.slice(0);
6008                     this.listeners.push(l);
6009                 }
6010             }
6011         },
6012
6013         findListener : function(fn, scope){
6014             scope = scope || this.obj;
6015             var ls = this.listeners;
6016             for(var i = 0, len = ls.length; i < len; i++){
6017                 var l = ls[i];
6018                 if(l.fn == fn && l.scope == scope){
6019                     return i;
6020                 }
6021             }
6022             return -1;
6023         },
6024
6025         isListening : function(fn, scope){
6026             return this.findListener(fn, scope) != -1;
6027         },
6028
6029         removeListener : function(fn, scope){
6030             var index;
6031             if((index = this.findListener(fn, scope)) != -1){
6032                 if(!this.firing){
6033                     this.listeners.splice(index, 1);
6034                 }else{
6035                     this.listeners = this.listeners.slice(0);
6036                     this.listeners.splice(index, 1);
6037                 }
6038                 return true;
6039             }
6040             return false;
6041         },
6042
6043         clearListeners : function(){
6044             this.listeners = [];
6045         },
6046
6047         fire : function(){
6048             var ls = this.listeners, scope, len = ls.length;
6049             if(len > 0){
6050                 this.firing = true;
6051                 var args = Array.prototype.slice.call(arguments, 0);
6052                 for(var i = 0; i < len; i++){
6053                     var l = ls[i];
6054                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6055                         this.firing = false;
6056                         return false;
6057                     }
6058                 }
6059                 this.firing = false;
6060             }
6061             return true;
6062         }
6063     };
6064 })();/*
6065  * RooJS Library 
6066  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6067  *
6068  * Licence LGPL 
6069  *
6070  */
6071  
6072 /**
6073  * @class Roo.Document
6074  * @extends Roo.util.Observable
6075  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6076  * 
6077  * @param {Object} config the methods and properties of the 'base' class for the application.
6078  * 
6079  *  Generic Page handler - implement this to start your app..
6080  * 
6081  * eg.
6082  *  MyProject = new Roo.Document({
6083         events : {
6084             'load' : true // your events..
6085         },
6086         listeners : {
6087             'ready' : function() {
6088                 // fired on Roo.onReady()
6089             }
6090         }
6091  * 
6092  */
6093 Roo.Document = function(cfg) {
6094      
6095     this.addEvents({ 
6096         'ready' : true
6097     });
6098     Roo.util.Observable.call(this,cfg);
6099     
6100     var _this = this;
6101     
6102     Roo.onReady(function() {
6103         _this.fireEvent('ready');
6104     },null,false);
6105     
6106     
6107 }
6108
6109 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6110  * Based on:
6111  * Ext JS Library 1.1.1
6112  * Copyright(c) 2006-2007, Ext JS, LLC.
6113  *
6114  * Originally Released Under LGPL - original licence link has changed is not relivant.
6115  *
6116  * Fork - LGPL
6117  * <script type="text/javascript">
6118  */
6119
6120 /**
6121  * @class Roo.EventManager
6122  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6123  * several useful events directly.
6124  * See {@link Roo.EventObject} for more details on normalized event objects.
6125  * @singleton
6126  */
6127 Roo.EventManager = function(){
6128     var docReadyEvent, docReadyProcId, docReadyState = false;
6129     var resizeEvent, resizeTask, textEvent, textSize;
6130     var E = Roo.lib.Event;
6131     var D = Roo.lib.Dom;
6132
6133     
6134     
6135
6136     var fireDocReady = function(){
6137         if(!docReadyState){
6138             docReadyState = true;
6139             Roo.isReady = true;
6140             if(docReadyProcId){
6141                 clearInterval(docReadyProcId);
6142             }
6143             if(Roo.isGecko || Roo.isOpera) {
6144                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6145             }
6146             if(Roo.isIE){
6147                 var defer = document.getElementById("ie-deferred-loader");
6148                 if(defer){
6149                     defer.onreadystatechange = null;
6150                     defer.parentNode.removeChild(defer);
6151                 }
6152             }
6153             if(docReadyEvent){
6154                 docReadyEvent.fire();
6155                 docReadyEvent.clearListeners();
6156             }
6157         }
6158     };
6159     
6160     var initDocReady = function(){
6161         docReadyEvent = new Roo.util.Event();
6162         if(Roo.isGecko || Roo.isOpera) {
6163             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6164         }else if(Roo.isIE){
6165             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6166             var defer = document.getElementById("ie-deferred-loader");
6167             defer.onreadystatechange = function(){
6168                 if(this.readyState == "complete"){
6169                     fireDocReady();
6170                 }
6171             };
6172         }else if(Roo.isSafari){ 
6173             docReadyProcId = setInterval(function(){
6174                 var rs = document.readyState;
6175                 if(rs == "complete") {
6176                     fireDocReady();     
6177                  }
6178             }, 10);
6179         }
6180         // no matter what, make sure it fires on load
6181         E.on(window, "load", fireDocReady);
6182     };
6183
6184     var createBuffered = function(h, o){
6185         var task = new Roo.util.DelayedTask(h);
6186         return function(e){
6187             // create new event object impl so new events don't wipe out properties
6188             e = new Roo.EventObjectImpl(e);
6189             task.delay(o.buffer, h, null, [e]);
6190         };
6191     };
6192
6193     var createSingle = function(h, el, ename, fn){
6194         return function(e){
6195             Roo.EventManager.removeListener(el, ename, fn);
6196             h(e);
6197         };
6198     };
6199
6200     var createDelayed = function(h, o){
6201         return function(e){
6202             // create new event object impl so new events don't wipe out properties
6203             e = new Roo.EventObjectImpl(e);
6204             setTimeout(function(){
6205                 h(e);
6206             }, o.delay || 10);
6207         };
6208     };
6209     var transitionEndVal = false;
6210     
6211     var transitionEnd = function()
6212     {
6213         if (transitionEndVal) {
6214             return transitionEndVal;
6215         }
6216         var el = document.createElement('div');
6217
6218         var transEndEventNames = {
6219             WebkitTransition : 'webkitTransitionEnd',
6220             MozTransition    : 'transitionend',
6221             OTransition      : 'oTransitionEnd otransitionend',
6222             transition       : 'transitionend'
6223         };
6224     
6225         for (var name in transEndEventNames) {
6226             if (el.style[name] !== undefined) {
6227                 transitionEndVal = transEndEventNames[name];
6228                 return  transitionEndVal ;
6229             }
6230         }
6231     }
6232     
6233
6234     var listen = function(element, ename, opt, fn, scope){
6235         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6236         fn = fn || o.fn; scope = scope || o.scope;
6237         var el = Roo.getDom(element);
6238         
6239         
6240         if(!el){
6241             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6242         }
6243         
6244         if (ename == 'transitionend') {
6245             ename = transitionEnd();
6246         }
6247         var h = function(e){
6248             e = Roo.EventObject.setEvent(e);
6249             var t;
6250             if(o.delegate){
6251                 t = e.getTarget(o.delegate, el);
6252                 if(!t){
6253                     return;
6254                 }
6255             }else{
6256                 t = e.target;
6257             }
6258             if(o.stopEvent === true){
6259                 e.stopEvent();
6260             }
6261             if(o.preventDefault === true){
6262                e.preventDefault();
6263             }
6264             if(o.stopPropagation === true){
6265                 e.stopPropagation();
6266             }
6267
6268             if(o.normalized === false){
6269                 e = e.browserEvent;
6270             }
6271
6272             fn.call(scope || el, e, t, o);
6273         };
6274         if(o.delay){
6275             h = createDelayed(h, o);
6276         }
6277         if(o.single){
6278             h = createSingle(h, el, ename, fn);
6279         }
6280         if(o.buffer){
6281             h = createBuffered(h, o);
6282         }
6283         fn._handlers = fn._handlers || [];
6284         
6285         
6286         fn._handlers.push([Roo.id(el), ename, h]);
6287         
6288         
6289          
6290         E.on(el, ename, h);
6291         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6292             el.addEventListener("DOMMouseScroll", h, false);
6293             E.on(window, 'unload', function(){
6294                 el.removeEventListener("DOMMouseScroll", h, false);
6295             });
6296         }
6297         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6298             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6299         }
6300         return h;
6301     };
6302
6303     var stopListening = function(el, ename, fn){
6304         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6305         if(hds){
6306             for(var i = 0, len = hds.length; i < len; i++){
6307                 var h = hds[i];
6308                 if(h[0] == id && h[1] == ename){
6309                     hd = h[2];
6310                     hds.splice(i, 1);
6311                     break;
6312                 }
6313             }
6314         }
6315         E.un(el, ename, hd);
6316         el = Roo.getDom(el);
6317         if(ename == "mousewheel" && el.addEventListener){
6318             el.removeEventListener("DOMMouseScroll", hd, false);
6319         }
6320         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6321             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6322         }
6323     };
6324
6325     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6326     
6327     var pub = {
6328         
6329         
6330         /** 
6331          * Fix for doc tools
6332          * @scope Roo.EventManager
6333          */
6334         
6335         
6336         /** 
6337          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6338          * object with a Roo.EventObject
6339          * @param {Function} fn        The method the event invokes
6340          * @param {Object}   scope    An object that becomes the scope of the handler
6341          * @param {boolean}  override If true, the obj passed in becomes
6342          *                             the execution scope of the listener
6343          * @return {Function} The wrapped function
6344          * @deprecated
6345          */
6346         wrap : function(fn, scope, override){
6347             return function(e){
6348                 Roo.EventObject.setEvent(e);
6349                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6350             };
6351         },
6352         
6353         /**
6354      * Appends an event handler to an element (shorthand for addListener)
6355      * @param {String/HTMLElement}   element        The html element or id to assign the
6356      * @param {String}   eventName The type of event to listen for
6357      * @param {Function} handler The method the event invokes
6358      * @param {Object}   scope (optional) The scope in which to execute the handler
6359      * function. The handler function's "this" context.
6360      * @param {Object}   options (optional) An object containing handler configuration
6361      * properties. This may contain any of the following properties:<ul>
6362      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6363      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6364      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6365      * <li>preventDefault {Boolean} True to prevent the default action</li>
6366      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6367      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6368      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6369      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6370      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6371      * by the specified number of milliseconds. If the event fires again within that time, the original
6372      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6373      * </ul><br>
6374      * <p>
6375      * <b>Combining Options</b><br>
6376      * Using the options argument, it is possible to combine different types of listeners:<br>
6377      * <br>
6378      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6379      * Code:<pre><code>
6380 el.on('click', this.onClick, this, {
6381     single: true,
6382     delay: 100,
6383     stopEvent : true,
6384     forumId: 4
6385 });</code></pre>
6386      * <p>
6387      * <b>Attaching multiple handlers in 1 call</b><br>
6388       * The method also allows for a single argument to be passed which is a config object containing properties
6389      * which specify multiple handlers.
6390      * <p>
6391      * Code:<pre><code>
6392 el.on({
6393     'click' : {
6394         fn: this.onClick
6395         scope: this,
6396         delay: 100
6397     },
6398     'mouseover' : {
6399         fn: this.onMouseOver
6400         scope: this
6401     },
6402     'mouseout' : {
6403         fn: this.onMouseOut
6404         scope: this
6405     }
6406 });</code></pre>
6407      * <p>
6408      * Or a shorthand syntax:<br>
6409      * Code:<pre><code>
6410 el.on({
6411     'click' : this.onClick,
6412     'mouseover' : this.onMouseOver,
6413     'mouseout' : this.onMouseOut
6414     scope: this
6415 });</code></pre>
6416      */
6417         addListener : function(element, eventName, fn, scope, options){
6418             if(typeof eventName == "object"){
6419                 var o = eventName;
6420                 for(var e in o){
6421                     if(propRe.test(e)){
6422                         continue;
6423                     }
6424                     if(typeof o[e] == "function"){
6425                         // shared options
6426                         listen(element, e, o, o[e], o.scope);
6427                     }else{
6428                         // individual options
6429                         listen(element, e, o[e]);
6430                     }
6431                 }
6432                 return;
6433             }
6434             return listen(element, eventName, options, fn, scope);
6435         },
6436         
6437         /**
6438          * Removes an event handler
6439          *
6440          * @param {String/HTMLElement}   element        The id or html element to remove the 
6441          *                             event from
6442          * @param {String}   eventName     The type of event
6443          * @param {Function} fn
6444          * @return {Boolean} True if a listener was actually removed
6445          */
6446         removeListener : function(element, eventName, fn){
6447             return stopListening(element, eventName, fn);
6448         },
6449         
6450         /**
6451          * Fires when the document is ready (before onload and before images are loaded). Can be 
6452          * accessed shorthanded Roo.onReady().
6453          * @param {Function} fn        The method the event invokes
6454          * @param {Object}   scope    An  object that becomes the scope of the handler
6455          * @param {boolean}  options
6456          */
6457         onDocumentReady : function(fn, scope, options){
6458             if(docReadyState){ // if it already fired
6459                 docReadyEvent.addListener(fn, scope, options);
6460                 docReadyEvent.fire();
6461                 docReadyEvent.clearListeners();
6462                 return;
6463             }
6464             if(!docReadyEvent){
6465                 initDocReady();
6466             }
6467             docReadyEvent.addListener(fn, scope, options);
6468         },
6469         
6470         /**
6471          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6472          * @param {Function} fn        The method the event invokes
6473          * @param {Object}   scope    An object that becomes the scope of the handler
6474          * @param {boolean}  options
6475          */
6476         onWindowResize : function(fn, scope, options){
6477             if(!resizeEvent){
6478                 resizeEvent = new Roo.util.Event();
6479                 resizeTask = new Roo.util.DelayedTask(function(){
6480                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6481                 });
6482                 E.on(window, "resize", function(){
6483                     if(Roo.isIE){
6484                         resizeTask.delay(50);
6485                     }else{
6486                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6487                     }
6488                 });
6489             }
6490             resizeEvent.addListener(fn, scope, options);
6491         },
6492
6493         /**
6494          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6495          * @param {Function} fn        The method the event invokes
6496          * @param {Object}   scope    An object that becomes the scope of the handler
6497          * @param {boolean}  options
6498          */
6499         onTextResize : function(fn, scope, options){
6500             if(!textEvent){
6501                 textEvent = new Roo.util.Event();
6502                 var textEl = new Roo.Element(document.createElement('div'));
6503                 textEl.dom.className = 'x-text-resize';
6504                 textEl.dom.innerHTML = 'X';
6505                 textEl.appendTo(document.body);
6506                 textSize = textEl.dom.offsetHeight;
6507                 setInterval(function(){
6508                     if(textEl.dom.offsetHeight != textSize){
6509                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6510                     }
6511                 }, this.textResizeInterval);
6512             }
6513             textEvent.addListener(fn, scope, options);
6514         },
6515
6516         /**
6517          * Removes the passed window resize listener.
6518          * @param {Function} fn        The method the event invokes
6519          * @param {Object}   scope    The scope of handler
6520          */
6521         removeResizeListener : function(fn, scope){
6522             if(resizeEvent){
6523                 resizeEvent.removeListener(fn, scope);
6524             }
6525         },
6526
6527         // private
6528         fireResize : function(){
6529             if(resizeEvent){
6530                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6531             }   
6532         },
6533         /**
6534          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6535          */
6536         ieDeferSrc : false,
6537         /**
6538          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6539          */
6540         textResizeInterval : 50
6541     };
6542     
6543     /**
6544      * Fix for doc tools
6545      * @scopeAlias pub=Roo.EventManager
6546      */
6547     
6548      /**
6549      * Appends an event handler to an element (shorthand for addListener)
6550      * @param {String/HTMLElement}   element        The html element or id to assign the
6551      * @param {String}   eventName The type of event to listen for
6552      * @param {Function} handler The method the event invokes
6553      * @param {Object}   scope (optional) The scope in which to execute the handler
6554      * function. The handler function's "this" context.
6555      * @param {Object}   options (optional) An object containing handler configuration
6556      * properties. This may contain any of the following properties:<ul>
6557      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6558      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6559      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6560      * <li>preventDefault {Boolean} True to prevent the default action</li>
6561      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6562      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6563      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6564      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6565      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6566      * by the specified number of milliseconds. If the event fires again within that time, the original
6567      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6568      * </ul><br>
6569      * <p>
6570      * <b>Combining Options</b><br>
6571      * Using the options argument, it is possible to combine different types of listeners:<br>
6572      * <br>
6573      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6574      * Code:<pre><code>
6575 el.on('click', this.onClick, this, {
6576     single: true,
6577     delay: 100,
6578     stopEvent : true,
6579     forumId: 4
6580 });</code></pre>
6581      * <p>
6582      * <b>Attaching multiple handlers in 1 call</b><br>
6583       * The method also allows for a single argument to be passed which is a config object containing properties
6584      * which specify multiple handlers.
6585      * <p>
6586      * Code:<pre><code>
6587 el.on({
6588     'click' : {
6589         fn: this.onClick
6590         scope: this,
6591         delay: 100
6592     },
6593     'mouseover' : {
6594         fn: this.onMouseOver
6595         scope: this
6596     },
6597     'mouseout' : {
6598         fn: this.onMouseOut
6599         scope: this
6600     }
6601 });</code></pre>
6602      * <p>
6603      * Or a shorthand syntax:<br>
6604      * Code:<pre><code>
6605 el.on({
6606     'click' : this.onClick,
6607     'mouseover' : this.onMouseOver,
6608     'mouseout' : this.onMouseOut
6609     scope: this
6610 });</code></pre>
6611      */
6612     pub.on = pub.addListener;
6613     pub.un = pub.removeListener;
6614
6615     pub.stoppedMouseDownEvent = new Roo.util.Event();
6616     return pub;
6617 }();
6618 /**
6619   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6620   * @param {Function} fn        The method the event invokes
6621   * @param {Object}   scope    An  object that becomes the scope of the handler
6622   * @param {boolean}  override If true, the obj passed in becomes
6623   *                             the execution scope of the listener
6624   * @member Roo
6625   * @method onReady
6626  */
6627 Roo.onReady = Roo.EventManager.onDocumentReady;
6628
6629 Roo.onReady(function(){
6630     var bd = Roo.get(document.body);
6631     if(!bd){ return; }
6632
6633     var cls = [
6634             Roo.isIE ? "roo-ie"
6635             : Roo.isIE11 ? "roo-ie11"
6636             : Roo.isEdge ? "roo-edge"
6637             : Roo.isGecko ? "roo-gecko"
6638             : Roo.isOpera ? "roo-opera"
6639             : Roo.isSafari ? "roo-safari" : ""];
6640
6641     if(Roo.isMac){
6642         cls.push("roo-mac");
6643     }
6644     if(Roo.isLinux){
6645         cls.push("roo-linux");
6646     }
6647     if(Roo.isIOS){
6648         cls.push("roo-ios");
6649     }
6650     if(Roo.isTouch){
6651         cls.push("roo-touch");
6652     }
6653     if(Roo.isBorderBox){
6654         cls.push('roo-border-box');
6655     }
6656     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6657         var p = bd.dom.parentNode;
6658         if(p){
6659             p.className += ' roo-strict';
6660         }
6661     }
6662     bd.addClass(cls.join(' '));
6663 });
6664
6665 /**
6666  * @class Roo.EventObject
6667  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6668  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6669  * Example:
6670  * <pre><code>
6671  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6672     e.preventDefault();
6673     var target = e.getTarget();
6674     ...
6675  }
6676  var myDiv = Roo.get("myDiv");
6677  myDiv.on("click", handleClick);
6678  //or
6679  Roo.EventManager.on("myDiv", 'click', handleClick);
6680  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6681  </code></pre>
6682  * @singleton
6683  */
6684 Roo.EventObject = function(){
6685     
6686     var E = Roo.lib.Event;
6687     
6688     // safari keypress events for special keys return bad keycodes
6689     var safariKeys = {
6690         63234 : 37, // left
6691         63235 : 39, // right
6692         63232 : 38, // up
6693         63233 : 40, // down
6694         63276 : 33, // page up
6695         63277 : 34, // page down
6696         63272 : 46, // delete
6697         63273 : 36, // home
6698         63275 : 35  // end
6699     };
6700
6701     // normalize button clicks
6702     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6703                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6704
6705     Roo.EventObjectImpl = function(e){
6706         if(e){
6707             this.setEvent(e.browserEvent || e);
6708         }
6709     };
6710     Roo.EventObjectImpl.prototype = {
6711         /**
6712          * Used to fix doc tools.
6713          * @scope Roo.EventObject.prototype
6714          */
6715             
6716
6717         
6718         
6719         /** The normal browser event */
6720         browserEvent : null,
6721         /** The button pressed in a mouse event */
6722         button : -1,
6723         /** True if the shift key was down during the event */
6724         shiftKey : false,
6725         /** True if the control key was down during the event */
6726         ctrlKey : false,
6727         /** True if the alt key was down during the event */
6728         altKey : false,
6729
6730         /** Key constant 
6731         * @type Number */
6732         BACKSPACE : 8,
6733         /** Key constant 
6734         * @type Number */
6735         TAB : 9,
6736         /** Key constant 
6737         * @type Number */
6738         RETURN : 13,
6739         /** Key constant 
6740         * @type Number */
6741         ENTER : 13,
6742         /** Key constant 
6743         * @type Number */
6744         SHIFT : 16,
6745         /** Key constant 
6746         * @type Number */
6747         CONTROL : 17,
6748         /** Key constant 
6749         * @type Number */
6750         ESC : 27,
6751         /** Key constant 
6752         * @type Number */
6753         SPACE : 32,
6754         /** Key constant 
6755         * @type Number */
6756         PAGEUP : 33,
6757         /** Key constant 
6758         * @type Number */
6759         PAGEDOWN : 34,
6760         /** Key constant 
6761         * @type Number */
6762         END : 35,
6763         /** Key constant 
6764         * @type Number */
6765         HOME : 36,
6766         /** Key constant 
6767         * @type Number */
6768         LEFT : 37,
6769         /** Key constant 
6770         * @type Number */
6771         UP : 38,
6772         /** Key constant 
6773         * @type Number */
6774         RIGHT : 39,
6775         /** Key constant 
6776         * @type Number */
6777         DOWN : 40,
6778         /** Key constant 
6779         * @type Number */
6780         DELETE : 46,
6781         /** Key constant 
6782         * @type Number */
6783         F5 : 116,
6784
6785            /** @private */
6786         setEvent : function(e){
6787             if(e == this || (e && e.browserEvent)){ // already wrapped
6788                 return e;
6789             }
6790             this.browserEvent = e;
6791             if(e){
6792                 // normalize buttons
6793                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6794                 if(e.type == 'click' && this.button == -1){
6795                     this.button = 0;
6796                 }
6797                 this.type = e.type;
6798                 this.shiftKey = e.shiftKey;
6799                 // mac metaKey behaves like ctrlKey
6800                 this.ctrlKey = e.ctrlKey || e.metaKey;
6801                 this.altKey = e.altKey;
6802                 // in getKey these will be normalized for the mac
6803                 this.keyCode = e.keyCode;
6804                 // keyup warnings on firefox.
6805                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6806                 // cache the target for the delayed and or buffered events
6807                 this.target = E.getTarget(e);
6808                 // same for XY
6809                 this.xy = E.getXY(e);
6810             }else{
6811                 this.button = -1;
6812                 this.shiftKey = false;
6813                 this.ctrlKey = false;
6814                 this.altKey = false;
6815                 this.keyCode = 0;
6816                 this.charCode =0;
6817                 this.target = null;
6818                 this.xy = [0, 0];
6819             }
6820             return this;
6821         },
6822
6823         /**
6824          * Stop the event (preventDefault and stopPropagation)
6825          */
6826         stopEvent : function(){
6827             if(this.browserEvent){
6828                 if(this.browserEvent.type == 'mousedown'){
6829                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6830                 }
6831                 E.stopEvent(this.browserEvent);
6832             }
6833         },
6834
6835         /**
6836          * Prevents the browsers default handling of the event.
6837          */
6838         preventDefault : function(){
6839             if(this.browserEvent){
6840                 E.preventDefault(this.browserEvent);
6841             }
6842         },
6843
6844         /** @private */
6845         isNavKeyPress : function(){
6846             var k = this.keyCode;
6847             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6848             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6849         },
6850
6851         isSpecialKey : function(){
6852             var k = this.keyCode;
6853             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6854             (k == 16) || (k == 17) ||
6855             (k >= 18 && k <= 20) ||
6856             (k >= 33 && k <= 35) ||
6857             (k >= 36 && k <= 39) ||
6858             (k >= 44 && k <= 45);
6859         },
6860         /**
6861          * Cancels bubbling of the event.
6862          */
6863         stopPropagation : function(){
6864             if(this.browserEvent){
6865                 if(this.type == 'mousedown'){
6866                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6867                 }
6868                 E.stopPropagation(this.browserEvent);
6869             }
6870         },
6871
6872         /**
6873          * Gets the key code for the event.
6874          * @return {Number}
6875          */
6876         getCharCode : function(){
6877             return this.charCode || this.keyCode;
6878         },
6879
6880         /**
6881          * Returns a normalized keyCode for the event.
6882          * @return {Number} The key code
6883          */
6884         getKey : function(){
6885             var k = this.keyCode || this.charCode;
6886             return Roo.isSafari ? (safariKeys[k] || k) : k;
6887         },
6888
6889         /**
6890          * Gets the x coordinate of the event.
6891          * @return {Number}
6892          */
6893         getPageX : function(){
6894             return this.xy[0];
6895         },
6896
6897         /**
6898          * Gets the y coordinate of the event.
6899          * @return {Number}
6900          */
6901         getPageY : function(){
6902             return this.xy[1];
6903         },
6904
6905         /**
6906          * Gets the time of the event.
6907          * @return {Number}
6908          */
6909         getTime : function(){
6910             if(this.browserEvent){
6911                 return E.getTime(this.browserEvent);
6912             }
6913             return null;
6914         },
6915
6916         /**
6917          * Gets the page coordinates of the event.
6918          * @return {Array} The xy values like [x, y]
6919          */
6920         getXY : function(){
6921             return this.xy;
6922         },
6923
6924         /**
6925          * Gets the target for the event.
6926          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6927          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6928                 search as a number or element (defaults to 10 || document.body)
6929          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6930          * @return {HTMLelement}
6931          */
6932         getTarget : function(selector, maxDepth, returnEl){
6933             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6934         },
6935         /**
6936          * Gets the related target.
6937          * @return {HTMLElement}
6938          */
6939         getRelatedTarget : function(){
6940             if(this.browserEvent){
6941                 return E.getRelatedTarget(this.browserEvent);
6942             }
6943             return null;
6944         },
6945
6946         /**
6947          * Normalizes mouse wheel delta across browsers
6948          * @return {Number} The delta
6949          */
6950         getWheelDelta : function(){
6951             var e = this.browserEvent;
6952             var delta = 0;
6953             if(e.wheelDelta){ /* IE/Opera. */
6954                 delta = e.wheelDelta/120;
6955             }else if(e.detail){ /* Mozilla case. */
6956                 delta = -e.detail/3;
6957             }
6958             return delta;
6959         },
6960
6961         /**
6962          * Returns true if the control, meta, shift or alt key was pressed during this event.
6963          * @return {Boolean}
6964          */
6965         hasModifier : function(){
6966             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6967         },
6968
6969         /**
6970          * Returns true if the target of this event equals el or is a child of el
6971          * @param {String/HTMLElement/Element} el
6972          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6973          * @return {Boolean}
6974          */
6975         within : function(el, related){
6976             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6977             return t && Roo.fly(el).contains(t);
6978         },
6979
6980         getPoint : function(){
6981             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6982         }
6983     };
6984
6985     return new Roo.EventObjectImpl();
6986 }();
6987             
6988     /*
6989  * Based on:
6990  * Ext JS Library 1.1.1
6991  * Copyright(c) 2006-2007, Ext JS, LLC.
6992  *
6993  * Originally Released Under LGPL - original licence link has changed is not relivant.
6994  *
6995  * Fork - LGPL
6996  * <script type="text/javascript">
6997  */
6998
6999  
7000 // was in Composite Element!??!?!
7001  
7002 (function(){
7003     var D = Roo.lib.Dom;
7004     var E = Roo.lib.Event;
7005     var A = Roo.lib.Anim;
7006
7007     // local style camelizing for speed
7008     var propCache = {};
7009     var camelRe = /(-[a-z])/gi;
7010     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7011     var view = document.defaultView;
7012
7013 /**
7014  * @class Roo.Element
7015  * Represents an Element in the DOM.<br><br>
7016  * Usage:<br>
7017 <pre><code>
7018 var el = Roo.get("my-div");
7019
7020 // or with getEl
7021 var el = getEl("my-div");
7022
7023 // or with a DOM element
7024 var el = Roo.get(myDivElement);
7025 </code></pre>
7026  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7027  * each call instead of constructing a new one.<br><br>
7028  * <b>Animations</b><br />
7029  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7030  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7031 <pre>
7032 Option    Default   Description
7033 --------- --------  ---------------------------------------------
7034 duration  .35       The duration of the animation in seconds
7035 easing    easeOut   The YUI easing method
7036 callback  none      A function to execute when the anim completes
7037 scope     this      The scope (this) of the callback function
7038 </pre>
7039 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7040 * manipulate the animation. Here's an example:
7041 <pre><code>
7042 var el = Roo.get("my-div");
7043
7044 // no animation
7045 el.setWidth(100);
7046
7047 // default animation
7048 el.setWidth(100, true);
7049
7050 // animation with some options set
7051 el.setWidth(100, {
7052     duration: 1,
7053     callback: this.foo,
7054     scope: this
7055 });
7056
7057 // using the "anim" property to get the Anim object
7058 var opt = {
7059     duration: 1,
7060     callback: this.foo,
7061     scope: this
7062 };
7063 el.setWidth(100, opt);
7064 ...
7065 if(opt.anim.isAnimated()){
7066     opt.anim.stop();
7067 }
7068 </code></pre>
7069 * <b> Composite (Collections of) Elements</b><br />
7070  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7071  * @constructor Create a new Element directly.
7072  * @param {String/HTMLElement} element
7073  * @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).
7074  */
7075     Roo.Element = function(element, forceNew){
7076         var dom = typeof element == "string" ?
7077                 document.getElementById(element) : element;
7078         if(!dom){ // invalid id/element
7079             return null;
7080         }
7081         var id = dom.id;
7082         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7083             return Roo.Element.cache[id];
7084         }
7085
7086         /**
7087          * The DOM element
7088          * @type HTMLElement
7089          */
7090         this.dom = dom;
7091
7092         /**
7093          * The DOM element ID
7094          * @type String
7095          */
7096         this.id = id || Roo.id(dom);
7097     };
7098
7099     var El = Roo.Element;
7100
7101     El.prototype = {
7102         /**
7103          * The element's default display mode  (defaults to "")
7104          * @type String
7105          */
7106         originalDisplay : "",
7107
7108         visibilityMode : 1,
7109         /**
7110          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7111          * @type String
7112          */
7113         defaultUnit : "px",
7114         
7115         /**
7116          * Sets the element's visibility mode. When setVisible() is called it
7117          * will use this to determine whether to set the visibility or the display property.
7118          * @param visMode Element.VISIBILITY or Element.DISPLAY
7119          * @return {Roo.Element} this
7120          */
7121         setVisibilityMode : function(visMode){
7122             this.visibilityMode = visMode;
7123             return this;
7124         },
7125         /**
7126          * Convenience method for setVisibilityMode(Element.DISPLAY)
7127          * @param {String} display (optional) What to set display to when visible
7128          * @return {Roo.Element} this
7129          */
7130         enableDisplayMode : function(display){
7131             this.setVisibilityMode(El.DISPLAY);
7132             if(typeof display != "undefined") { this.originalDisplay = display; }
7133             return this;
7134         },
7135
7136         /**
7137          * 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)
7138          * @param {String} selector The simple selector to test
7139          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7140                 search as a number or element (defaults to 10 || document.body)
7141          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7142          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7143          */
7144         findParent : function(simpleSelector, maxDepth, returnEl){
7145             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7146             maxDepth = maxDepth || 50;
7147             if(typeof maxDepth != "number"){
7148                 stopEl = Roo.getDom(maxDepth);
7149                 maxDepth = 10;
7150             }
7151             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7152                 if(dq.is(p, simpleSelector)){
7153                     return returnEl ? Roo.get(p) : p;
7154                 }
7155                 depth++;
7156                 p = p.parentNode;
7157             }
7158             return null;
7159         },
7160
7161
7162         /**
7163          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7164          * @param {String} selector The simple selector to test
7165          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7166                 search as a number or element (defaults to 10 || document.body)
7167          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7168          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7169          */
7170         findParentNode : function(simpleSelector, maxDepth, returnEl){
7171             var p = Roo.fly(this.dom.parentNode, '_internal');
7172             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7173         },
7174         
7175         /**
7176          * Looks at  the scrollable parent element
7177          */
7178         findScrollableParent : function()
7179         {
7180             var overflowRegex = /(auto|scroll)/;
7181             
7182             if(this.getStyle('position') === 'fixed'){
7183                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7184             }
7185             
7186             var excludeStaticParent = this.getStyle('position') === "absolute";
7187             
7188             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7189                 
7190                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7191                     continue;
7192                 }
7193                 
7194                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7195                     return parent;
7196                 }
7197                 
7198                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7199                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7200                 }
7201             }
7202             
7203             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7204         },
7205
7206         /**
7207          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7208          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7209          * @param {String} selector The simple selector to test
7210          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7211                 search as a number or element (defaults to 10 || document.body)
7212          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7213          */
7214         up : function(simpleSelector, maxDepth){
7215             return this.findParentNode(simpleSelector, maxDepth, true);
7216         },
7217
7218
7219
7220         /**
7221          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7222          * @param {String} selector The simple selector to test
7223          * @return {Boolean} True if this element matches the selector, else false
7224          */
7225         is : function(simpleSelector){
7226             return Roo.DomQuery.is(this.dom, simpleSelector);
7227         },
7228
7229         /**
7230          * Perform animation on this element.
7231          * @param {Object} args The YUI animation control args
7232          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7233          * @param {Function} onComplete (optional) Function to call when animation completes
7234          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7235          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7236          * @return {Roo.Element} this
7237          */
7238         animate : function(args, duration, onComplete, easing, animType){
7239             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7240             return this;
7241         },
7242
7243         /*
7244          * @private Internal animation call
7245          */
7246         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7247             animType = animType || 'run';
7248             opt = opt || {};
7249             var anim = Roo.lib.Anim[animType](
7250                 this.dom, args,
7251                 (opt.duration || defaultDur) || .35,
7252                 (opt.easing || defaultEase) || 'easeOut',
7253                 function(){
7254                     Roo.callback(cb, this);
7255                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7256                 },
7257                 this
7258             );
7259             opt.anim = anim;
7260             return anim;
7261         },
7262
7263         // private legacy anim prep
7264         preanim : function(a, i){
7265             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7266         },
7267
7268         /**
7269          * Removes worthless text nodes
7270          * @param {Boolean} forceReclean (optional) By default the element
7271          * keeps track if it has been cleaned already so
7272          * you can call this over and over. However, if you update the element and
7273          * need to force a reclean, you can pass true.
7274          */
7275         clean : function(forceReclean){
7276             if(this.isCleaned && forceReclean !== true){
7277                 return this;
7278             }
7279             var ns = /\S/;
7280             var d = this.dom, n = d.firstChild, ni = -1;
7281             while(n){
7282                 var nx = n.nextSibling;
7283                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7284                     d.removeChild(n);
7285                 }else{
7286                     n.nodeIndex = ++ni;
7287                 }
7288                 n = nx;
7289             }
7290             this.isCleaned = true;
7291             return this;
7292         },
7293
7294         // private
7295         calcOffsetsTo : function(el){
7296             el = Roo.get(el);
7297             var d = el.dom;
7298             var restorePos = false;
7299             if(el.getStyle('position') == 'static'){
7300                 el.position('relative');
7301                 restorePos = true;
7302             }
7303             var x = 0, y =0;
7304             var op = this.dom;
7305             while(op && op != d && op.tagName != 'HTML'){
7306                 x+= op.offsetLeft;
7307                 y+= op.offsetTop;
7308                 op = op.offsetParent;
7309             }
7310             if(restorePos){
7311                 el.position('static');
7312             }
7313             return [x, y];
7314         },
7315
7316         /**
7317          * Scrolls this element into view within the passed container.
7318          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7319          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7320          * @return {Roo.Element} this
7321          */
7322         scrollIntoView : function(container, hscroll){
7323             var c = Roo.getDom(container) || document.body;
7324             var el = this.dom;
7325
7326             var o = this.calcOffsetsTo(c),
7327                 l = o[0],
7328                 t = o[1],
7329                 b = t+el.offsetHeight,
7330                 r = l+el.offsetWidth;
7331
7332             var ch = c.clientHeight;
7333             var ct = parseInt(c.scrollTop, 10);
7334             var cl = parseInt(c.scrollLeft, 10);
7335             var cb = ct + ch;
7336             var cr = cl + c.clientWidth;
7337
7338             if(t < ct){
7339                 c.scrollTop = t;
7340             }else if(b > cb){
7341                 c.scrollTop = b-ch;
7342             }
7343
7344             if(hscroll !== false){
7345                 if(l < cl){
7346                     c.scrollLeft = l;
7347                 }else if(r > cr){
7348                     c.scrollLeft = r-c.clientWidth;
7349                 }
7350             }
7351             return this;
7352         },
7353
7354         // private
7355         scrollChildIntoView : function(child, hscroll){
7356             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7357         },
7358
7359         /**
7360          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7361          * the new height may not be available immediately.
7362          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7363          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7364          * @param {Function} onComplete (optional) Function to call when animation completes
7365          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7366          * @return {Roo.Element} this
7367          */
7368         autoHeight : function(animate, duration, onComplete, easing){
7369             var oldHeight = this.getHeight();
7370             this.clip();
7371             this.setHeight(1); // force clipping
7372             setTimeout(function(){
7373                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7374                 if(!animate){
7375                     this.setHeight(height);
7376                     this.unclip();
7377                     if(typeof onComplete == "function"){
7378                         onComplete();
7379                     }
7380                 }else{
7381                     this.setHeight(oldHeight); // restore original height
7382                     this.setHeight(height, animate, duration, function(){
7383                         this.unclip();
7384                         if(typeof onComplete == "function") { onComplete(); }
7385                     }.createDelegate(this), easing);
7386                 }
7387             }.createDelegate(this), 0);
7388             return this;
7389         },
7390
7391         /**
7392          * Returns true if this element is an ancestor of the passed element
7393          * @param {HTMLElement/String} el The element to check
7394          * @return {Boolean} True if this element is an ancestor of el, else false
7395          */
7396         contains : function(el){
7397             if(!el){return false;}
7398             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7399         },
7400
7401         /**
7402          * Checks whether the element is currently visible using both visibility and display properties.
7403          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7404          * @return {Boolean} True if the element is currently visible, else false
7405          */
7406         isVisible : function(deep) {
7407             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7408             if(deep !== true || !vis){
7409                 return vis;
7410             }
7411             var p = this.dom.parentNode;
7412             while(p && p.tagName.toLowerCase() != "body"){
7413                 if(!Roo.fly(p, '_isVisible').isVisible()){
7414                     return false;
7415                 }
7416                 p = p.parentNode;
7417             }
7418             return true;
7419         },
7420
7421         /**
7422          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7423          * @param {String} selector The CSS selector
7424          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7425          * @return {CompositeElement/CompositeElementLite} The composite element
7426          */
7427         select : function(selector, unique){
7428             return El.select(selector, unique, this.dom);
7429         },
7430
7431         /**
7432          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7433          * @param {String} selector The CSS selector
7434          * @return {Array} An array of the matched nodes
7435          */
7436         query : function(selector, unique){
7437             return Roo.DomQuery.select(selector, this.dom);
7438         },
7439
7440         /**
7441          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7442          * @param {String} selector The CSS selector
7443          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7444          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7445          */
7446         child : function(selector, returnDom){
7447             var n = Roo.DomQuery.selectNode(selector, this.dom);
7448             return returnDom ? n : Roo.get(n);
7449         },
7450
7451         /**
7452          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7453          * @param {String} selector The CSS selector
7454          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7455          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7456          */
7457         down : function(selector, returnDom){
7458             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7459             return returnDom ? n : Roo.get(n);
7460         },
7461
7462         /**
7463          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7464          * @param {String} group The group the DD object is member of
7465          * @param {Object} config The DD config object
7466          * @param {Object} overrides An object containing methods to override/implement on the DD object
7467          * @return {Roo.dd.DD} The DD object
7468          */
7469         initDD : function(group, config, overrides){
7470             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7471             return Roo.apply(dd, overrides);
7472         },
7473
7474         /**
7475          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7476          * @param {String} group The group the DDProxy object is member of
7477          * @param {Object} config The DDProxy config object
7478          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7479          * @return {Roo.dd.DDProxy} The DDProxy object
7480          */
7481         initDDProxy : function(group, config, overrides){
7482             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7483             return Roo.apply(dd, overrides);
7484         },
7485
7486         /**
7487          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7488          * @param {String} group The group the DDTarget object is member of
7489          * @param {Object} config The DDTarget config object
7490          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7491          * @return {Roo.dd.DDTarget} The DDTarget object
7492          */
7493         initDDTarget : function(group, config, overrides){
7494             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7495             return Roo.apply(dd, overrides);
7496         },
7497
7498         /**
7499          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7500          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7501          * @param {Boolean} visible Whether the element is visible
7502          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7503          * @return {Roo.Element} this
7504          */
7505          setVisible : function(visible, animate){
7506             if(!animate || !A){
7507                 if(this.visibilityMode == El.DISPLAY){
7508                     this.setDisplayed(visible);
7509                 }else{
7510                     this.fixDisplay();
7511                     this.dom.style.visibility = visible ? "visible" : "hidden";
7512                 }
7513             }else{
7514                 // closure for composites
7515                 var dom = this.dom;
7516                 var visMode = this.visibilityMode;
7517                 if(visible){
7518                     this.setOpacity(.01);
7519                     this.setVisible(true);
7520                 }
7521                 this.anim({opacity: { to: (visible?1:0) }},
7522                       this.preanim(arguments, 1),
7523                       null, .35, 'easeIn', function(){
7524                          if(!visible){
7525                              if(visMode == El.DISPLAY){
7526                                  dom.style.display = "none";
7527                              }else{
7528                                  dom.style.visibility = "hidden";
7529                              }
7530                              Roo.get(dom).setOpacity(1);
7531                          }
7532                      });
7533             }
7534             return this;
7535         },
7536
7537         /**
7538          * Returns true if display is not "none"
7539          * @return {Boolean}
7540          */
7541         isDisplayed : function() {
7542             return this.getStyle("display") != "none";
7543         },
7544
7545         /**
7546          * Toggles the element's visibility or display, depending on visibility mode.
7547          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7548          * @return {Roo.Element} this
7549          */
7550         toggle : function(animate){
7551             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7552             return this;
7553         },
7554
7555         /**
7556          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7557          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7558          * @return {Roo.Element} this
7559          */
7560         setDisplayed : function(value) {
7561             if(typeof value == "boolean"){
7562                value = value ? this.originalDisplay : "none";
7563             }
7564             this.setStyle("display", value);
7565             return this;
7566         },
7567
7568         /**
7569          * Tries to focus the element. Any exceptions are caught and ignored.
7570          * @return {Roo.Element} this
7571          */
7572         focus : function() {
7573             try{
7574                 this.dom.focus();
7575             }catch(e){}
7576             return this;
7577         },
7578
7579         /**
7580          * Tries to blur the element. Any exceptions are caught and ignored.
7581          * @return {Roo.Element} this
7582          */
7583         blur : function() {
7584             try{
7585                 this.dom.blur();
7586             }catch(e){}
7587             return this;
7588         },
7589
7590         /**
7591          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7592          * @param {String/Array} className The CSS class to add, or an array of classes
7593          * @return {Roo.Element} this
7594          */
7595         addClass : function(className){
7596             if(className instanceof Array){
7597                 for(var i = 0, len = className.length; i < len; i++) {
7598                     this.addClass(className[i]);
7599                 }
7600             }else{
7601                 if(className && !this.hasClass(className)){
7602                     this.dom.className = this.dom.className + " " + className;
7603                 }
7604             }
7605             return this;
7606         },
7607
7608         /**
7609          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7610          * @param {String/Array} className The CSS class to add, or an array of classes
7611          * @return {Roo.Element} this
7612          */
7613         radioClass : function(className){
7614             var siblings = this.dom.parentNode.childNodes;
7615             for(var i = 0; i < siblings.length; i++) {
7616                 var s = siblings[i];
7617                 if(s.nodeType == 1){
7618                     Roo.get(s).removeClass(className);
7619                 }
7620             }
7621             this.addClass(className);
7622             return this;
7623         },
7624
7625         /**
7626          * Removes one or more CSS classes from the element.
7627          * @param {String/Array} className The CSS class to remove, or an array of classes
7628          * @return {Roo.Element} this
7629          */
7630         removeClass : function(className){
7631             if(!className || !this.dom.className){
7632                 return this;
7633             }
7634             if(className instanceof Array){
7635                 for(var i = 0, len = className.length; i < len; i++) {
7636                     this.removeClass(className[i]);
7637                 }
7638             }else{
7639                 if(this.hasClass(className)){
7640                     var re = this.classReCache[className];
7641                     if (!re) {
7642                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7643                        this.classReCache[className] = re;
7644                     }
7645                     this.dom.className =
7646                         this.dom.className.replace(re, " ");
7647                 }
7648             }
7649             return this;
7650         },
7651
7652         // private
7653         classReCache: {},
7654
7655         /**
7656          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7657          * @param {String} className The CSS class to toggle
7658          * @return {Roo.Element} this
7659          */
7660         toggleClass : function(className){
7661             if(this.hasClass(className)){
7662                 this.removeClass(className);
7663             }else{
7664                 this.addClass(className);
7665             }
7666             return this;
7667         },
7668
7669         /**
7670          * Checks if the specified CSS class exists on this element's DOM node.
7671          * @param {String} className The CSS class to check for
7672          * @return {Boolean} True if the class exists, else false
7673          */
7674         hasClass : function(className){
7675             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7676         },
7677
7678         /**
7679          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7680          * @param {String} oldClassName The CSS class to replace
7681          * @param {String} newClassName The replacement CSS class
7682          * @return {Roo.Element} this
7683          */
7684         replaceClass : function(oldClassName, newClassName){
7685             this.removeClass(oldClassName);
7686             this.addClass(newClassName);
7687             return this;
7688         },
7689
7690         /**
7691          * Returns an object with properties matching the styles requested.
7692          * For example, el.getStyles('color', 'font-size', 'width') might return
7693          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7694          * @param {String} style1 A style name
7695          * @param {String} style2 A style name
7696          * @param {String} etc.
7697          * @return {Object} The style object
7698          */
7699         getStyles : function(){
7700             var a = arguments, len = a.length, r = {};
7701             for(var i = 0; i < len; i++){
7702                 r[a[i]] = this.getStyle(a[i]);
7703             }
7704             return r;
7705         },
7706
7707         /**
7708          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7709          * @param {String} property The style property whose value is returned.
7710          * @return {String} The current value of the style property for this element.
7711          */
7712         getStyle : function(){
7713             return view && view.getComputedStyle ?
7714                 function(prop){
7715                     var el = this.dom, v, cs, camel;
7716                     if(prop == 'float'){
7717                         prop = "cssFloat";
7718                     }
7719                     if(el.style && (v = el.style[prop])){
7720                         return v;
7721                     }
7722                     if(cs = view.getComputedStyle(el, "")){
7723                         if(!(camel = propCache[prop])){
7724                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7725                         }
7726                         return cs[camel];
7727                     }
7728                     return null;
7729                 } :
7730                 function(prop){
7731                     var el = this.dom, v, cs, camel;
7732                     if(prop == 'opacity'){
7733                         if(typeof el.style.filter == 'string'){
7734                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7735                             if(m){
7736                                 var fv = parseFloat(m[1]);
7737                                 if(!isNaN(fv)){
7738                                     return fv ? fv / 100 : 0;
7739                                 }
7740                             }
7741                         }
7742                         return 1;
7743                     }else if(prop == 'float'){
7744                         prop = "styleFloat";
7745                     }
7746                     if(!(camel = propCache[prop])){
7747                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7748                     }
7749                     if(v = el.style[camel]){
7750                         return v;
7751                     }
7752                     if(cs = el.currentStyle){
7753                         return cs[camel];
7754                     }
7755                     return null;
7756                 };
7757         }(),
7758
7759         /**
7760          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7761          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7762          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7763          * @return {Roo.Element} this
7764          */
7765         setStyle : function(prop, value){
7766             if(typeof prop == "string"){
7767                 
7768                 if (prop == 'float') {
7769                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7770                     return this;
7771                 }
7772                 
7773                 var camel;
7774                 if(!(camel = propCache[prop])){
7775                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7776                 }
7777                 
7778                 if(camel == 'opacity') {
7779                     this.setOpacity(value);
7780                 }else{
7781                     this.dom.style[camel] = value;
7782                 }
7783             }else{
7784                 for(var style in prop){
7785                     if(typeof prop[style] != "function"){
7786                        this.setStyle(style, prop[style]);
7787                     }
7788                 }
7789             }
7790             return this;
7791         },
7792
7793         /**
7794          * More flexible version of {@link #setStyle} for setting style properties.
7795          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7796          * a function which returns such a specification.
7797          * @return {Roo.Element} this
7798          */
7799         applyStyles : function(style){
7800             Roo.DomHelper.applyStyles(this.dom, style);
7801             return this;
7802         },
7803
7804         /**
7805           * 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).
7806           * @return {Number} The X position of the element
7807           */
7808         getX : function(){
7809             return D.getX(this.dom);
7810         },
7811
7812         /**
7813           * 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).
7814           * @return {Number} The Y position of the element
7815           */
7816         getY : function(){
7817             return D.getY(this.dom);
7818         },
7819
7820         /**
7821           * 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).
7822           * @return {Array} The XY position of the element
7823           */
7824         getXY : function(){
7825             return D.getXY(this.dom);
7826         },
7827
7828         /**
7829          * 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).
7830          * @param {Number} The X position of the element
7831          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7832          * @return {Roo.Element} this
7833          */
7834         setX : function(x, animate){
7835             if(!animate || !A){
7836                 D.setX(this.dom, x);
7837             }else{
7838                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7839             }
7840             return this;
7841         },
7842
7843         /**
7844          * 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).
7845          * @param {Number} The Y position of the element
7846          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7847          * @return {Roo.Element} this
7848          */
7849         setY : function(y, animate){
7850             if(!animate || !A){
7851                 D.setY(this.dom, y);
7852             }else{
7853                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7854             }
7855             return this;
7856         },
7857
7858         /**
7859          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7860          * @param {String} left The left CSS property value
7861          * @return {Roo.Element} this
7862          */
7863         setLeft : function(left){
7864             this.setStyle("left", this.addUnits(left));
7865             return this;
7866         },
7867
7868         /**
7869          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7870          * @param {String} top The top CSS property value
7871          * @return {Roo.Element} this
7872          */
7873         setTop : function(top){
7874             this.setStyle("top", this.addUnits(top));
7875             return this;
7876         },
7877
7878         /**
7879          * Sets the element's CSS right style.
7880          * @param {String} right The right CSS property value
7881          * @return {Roo.Element} this
7882          */
7883         setRight : function(right){
7884             this.setStyle("right", this.addUnits(right));
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the element's CSS bottom style.
7890          * @param {String} bottom The bottom CSS property value
7891          * @return {Roo.Element} this
7892          */
7893         setBottom : function(bottom){
7894             this.setStyle("bottom", this.addUnits(bottom));
7895             return this;
7896         },
7897
7898         /**
7899          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7900          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7901          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7902          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7903          * @return {Roo.Element} this
7904          */
7905         setXY : function(pos, animate){
7906             if(!animate || !A){
7907                 D.setXY(this.dom, pos);
7908             }else{
7909                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7910             }
7911             return this;
7912         },
7913
7914         /**
7915          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7916          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7917          * @param {Number} x X value for new position (coordinates are page-based)
7918          * @param {Number} y Y value for new position (coordinates are page-based)
7919          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920          * @return {Roo.Element} this
7921          */
7922         setLocation : function(x, y, animate){
7923             this.setXY([x, y], this.preanim(arguments, 2));
7924             return this;
7925         },
7926
7927         /**
7928          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7929          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7930          * @param {Number} x X value for new position (coordinates are page-based)
7931          * @param {Number} y Y value for new position (coordinates are page-based)
7932          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         moveTo : function(x, y, animate){
7936             this.setXY([x, y], this.preanim(arguments, 2));
7937             return this;
7938         },
7939
7940         /**
7941          * Returns the region of the given element.
7942          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7943          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7944          */
7945         getRegion : function(){
7946             return D.getRegion(this.dom);
7947         },
7948
7949         /**
7950          * Returns the offset height of the element
7951          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7952          * @return {Number} The element's height
7953          */
7954         getHeight : function(contentHeight){
7955             var h = this.dom.offsetHeight || 0;
7956             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7957         },
7958
7959         /**
7960          * Returns the offset width of the element
7961          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7962          * @return {Number} The element's width
7963          */
7964         getWidth : function(contentWidth){
7965             var w = this.dom.offsetWidth || 0;
7966             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7967         },
7968
7969         /**
7970          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7971          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7972          * if a height has not been set using CSS.
7973          * @return {Number}
7974          */
7975         getComputedHeight : function(){
7976             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7977             if(!h){
7978                 h = parseInt(this.getStyle('height'), 10) || 0;
7979                 if(!this.isBorderBox()){
7980                     h += this.getFrameWidth('tb');
7981                 }
7982             }
7983             return h;
7984         },
7985
7986         /**
7987          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7988          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7989          * if a width has not been set using CSS.
7990          * @return {Number}
7991          */
7992         getComputedWidth : function(){
7993             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7994             if(!w){
7995                 w = parseInt(this.getStyle('width'), 10) || 0;
7996                 if(!this.isBorderBox()){
7997                     w += this.getFrameWidth('lr');
7998                 }
7999             }
8000             return w;
8001         },
8002
8003         /**
8004          * Returns the size of the element.
8005          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8006          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8007          */
8008         getSize : function(contentSize){
8009             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8010         },
8011
8012         /**
8013          * Returns the width and height of the viewport.
8014          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8015          */
8016         getViewSize : function(){
8017             var d = this.dom, doc = document, aw = 0, ah = 0;
8018             if(d == doc || d == doc.body){
8019                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8020             }else{
8021                 return {
8022                     width : d.clientWidth,
8023                     height: d.clientHeight
8024                 };
8025             }
8026         },
8027
8028         /**
8029          * Returns the value of the "value" attribute
8030          * @param {Boolean} asNumber true to parse the value as a number
8031          * @return {String/Number}
8032          */
8033         getValue : function(asNumber){
8034             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8035         },
8036
8037         // private
8038         adjustWidth : function(width){
8039             if(typeof width == "number"){
8040                 if(this.autoBoxAdjust && !this.isBorderBox()){
8041                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8042                 }
8043                 if(width < 0){
8044                     width = 0;
8045                 }
8046             }
8047             return width;
8048         },
8049
8050         // private
8051         adjustHeight : function(height){
8052             if(typeof height == "number"){
8053                if(this.autoBoxAdjust && !this.isBorderBox()){
8054                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8055                }
8056                if(height < 0){
8057                    height = 0;
8058                }
8059             }
8060             return height;
8061         },
8062
8063         /**
8064          * Set the width of the element
8065          * @param {Number} width The new width
8066          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8067          * @return {Roo.Element} this
8068          */
8069         setWidth : function(width, animate){
8070             width = this.adjustWidth(width);
8071             if(!animate || !A){
8072                 this.dom.style.width = this.addUnits(width);
8073             }else{
8074                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8075             }
8076             return this;
8077         },
8078
8079         /**
8080          * Set the height of the element
8081          * @param {Number} height The new height
8082          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083          * @return {Roo.Element} this
8084          */
8085          setHeight : function(height, animate){
8086             height = this.adjustHeight(height);
8087             if(!animate || !A){
8088                 this.dom.style.height = this.addUnits(height);
8089             }else{
8090                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8091             }
8092             return this;
8093         },
8094
8095         /**
8096          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8097          * @param {Number} width The new width
8098          * @param {Number} height The new height
8099          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100          * @return {Roo.Element} this
8101          */
8102          setSize : function(width, height, animate){
8103             if(typeof width == "object"){ // in case of object from getSize()
8104                 height = width.height; width = width.width;
8105             }
8106             width = this.adjustWidth(width); height = this.adjustHeight(height);
8107             if(!animate || !A){
8108                 this.dom.style.width = this.addUnits(width);
8109                 this.dom.style.height = this.addUnits(height);
8110             }else{
8111                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8112             }
8113             return this;
8114         },
8115
8116         /**
8117          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8118          * @param {Number} x X value for new position (coordinates are page-based)
8119          * @param {Number} y Y value for new position (coordinates are page-based)
8120          * @param {Number} width The new width
8121          * @param {Number} height The new height
8122          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8123          * @return {Roo.Element} this
8124          */
8125         setBounds : function(x, y, width, height, animate){
8126             if(!animate || !A){
8127                 this.setSize(width, height);
8128                 this.setLocation(x, y);
8129             }else{
8130                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8131                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8132                               this.preanim(arguments, 4), 'motion');
8133             }
8134             return this;
8135         },
8136
8137         /**
8138          * 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.
8139          * @param {Roo.lib.Region} region The region to fill
8140          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8141          * @return {Roo.Element} this
8142          */
8143         setRegion : function(region, animate){
8144             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8145             return this;
8146         },
8147
8148         /**
8149          * Appends an event handler
8150          *
8151          * @param {String}   eventName     The type of event to append
8152          * @param {Function} fn        The method the event invokes
8153          * @param {Object} scope       (optional) The scope (this object) of the fn
8154          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8155          */
8156         addListener : function(eventName, fn, scope, options){
8157             if (this.dom) {
8158                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8159             }
8160         },
8161
8162         /**
8163          * Removes an event handler from this element
8164          * @param {String} eventName the type of event to remove
8165          * @param {Function} fn the method the event invokes
8166          * @return {Roo.Element} this
8167          */
8168         removeListener : function(eventName, fn){
8169             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8170             return this;
8171         },
8172
8173         /**
8174          * Removes all previous added listeners from this element
8175          * @return {Roo.Element} this
8176          */
8177         removeAllListeners : function(){
8178             E.purgeElement(this.dom);
8179             return this;
8180         },
8181
8182         relayEvent : function(eventName, observable){
8183             this.on(eventName, function(e){
8184                 observable.fireEvent(eventName, e);
8185             });
8186         },
8187
8188         /**
8189          * Set the opacity of the element
8190          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8191          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8192          * @return {Roo.Element} this
8193          */
8194          setOpacity : function(opacity, animate){
8195             if(!animate || !A){
8196                 var s = this.dom.style;
8197                 if(Roo.isIE){
8198                     s.zoom = 1;
8199                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8200                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8201                 }else{
8202                     s.opacity = opacity;
8203                 }
8204             }else{
8205                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8206             }
8207             return this;
8208         },
8209
8210         /**
8211          * Gets the left X coordinate
8212          * @param {Boolean} local True to get the local css position instead of page coordinate
8213          * @return {Number}
8214          */
8215         getLeft : function(local){
8216             if(!local){
8217                 return this.getX();
8218             }else{
8219                 return parseInt(this.getStyle("left"), 10) || 0;
8220             }
8221         },
8222
8223         /**
8224          * Gets the right X coordinate of the element (element X position + element width)
8225          * @param {Boolean} local True to get the local css position instead of page coordinate
8226          * @return {Number}
8227          */
8228         getRight : function(local){
8229             if(!local){
8230                 return this.getX() + this.getWidth();
8231             }else{
8232                 return (this.getLeft(true) + this.getWidth()) || 0;
8233             }
8234         },
8235
8236         /**
8237          * Gets the top Y coordinate
8238          * @param {Boolean} local True to get the local css position instead of page coordinate
8239          * @return {Number}
8240          */
8241         getTop : function(local) {
8242             if(!local){
8243                 return this.getY();
8244             }else{
8245                 return parseInt(this.getStyle("top"), 10) || 0;
8246             }
8247         },
8248
8249         /**
8250          * Gets the bottom Y coordinate of the element (element Y position + element height)
8251          * @param {Boolean} local True to get the local css position instead of page coordinate
8252          * @return {Number}
8253          */
8254         getBottom : function(local){
8255             if(!local){
8256                 return this.getY() + this.getHeight();
8257             }else{
8258                 return (this.getTop(true) + this.getHeight()) || 0;
8259             }
8260         },
8261
8262         /**
8263         * Initializes positioning on this element. If a desired position is not passed, it will make the
8264         * the element positioned relative IF it is not already positioned.
8265         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8266         * @param {Number} zIndex (optional) The zIndex to apply
8267         * @param {Number} x (optional) Set the page X position
8268         * @param {Number} y (optional) Set the page Y position
8269         */
8270         position : function(pos, zIndex, x, y){
8271             if(!pos){
8272                if(this.getStyle('position') == 'static'){
8273                    this.setStyle('position', 'relative');
8274                }
8275             }else{
8276                 this.setStyle("position", pos);
8277             }
8278             if(zIndex){
8279                 this.setStyle("z-index", zIndex);
8280             }
8281             if(x !== undefined && y !== undefined){
8282                 this.setXY([x, y]);
8283             }else if(x !== undefined){
8284                 this.setX(x);
8285             }else if(y !== undefined){
8286                 this.setY(y);
8287             }
8288         },
8289
8290         /**
8291         * Clear positioning back to the default when the document was loaded
8292         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8293         * @return {Roo.Element} this
8294          */
8295         clearPositioning : function(value){
8296             value = value ||'';
8297             this.setStyle({
8298                 "left": value,
8299                 "right": value,
8300                 "top": value,
8301                 "bottom": value,
8302                 "z-index": "",
8303                 "position" : "static"
8304             });
8305             return this;
8306         },
8307
8308         /**
8309         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8310         * snapshot before performing an update and then restoring the element.
8311         * @return {Object}
8312         */
8313         getPositioning : function(){
8314             var l = this.getStyle("left");
8315             var t = this.getStyle("top");
8316             return {
8317                 "position" : this.getStyle("position"),
8318                 "left" : l,
8319                 "right" : l ? "" : this.getStyle("right"),
8320                 "top" : t,
8321                 "bottom" : t ? "" : this.getStyle("bottom"),
8322                 "z-index" : this.getStyle("z-index")
8323             };
8324         },
8325
8326         /**
8327          * Gets the width of the border(s) for the specified side(s)
8328          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8329          * passing lr would get the border (l)eft width + the border (r)ight width.
8330          * @return {Number} The width of the sides passed added together
8331          */
8332         getBorderWidth : function(side){
8333             return this.addStyles(side, El.borders);
8334         },
8335
8336         /**
8337          * Gets the width of the padding(s) for the specified side(s)
8338          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8339          * passing lr would get the padding (l)eft + the padding (r)ight.
8340          * @return {Number} The padding of the sides passed added together
8341          */
8342         getPadding : function(side){
8343             return this.addStyles(side, El.paddings);
8344         },
8345
8346         /**
8347         * Set positioning with an object returned by getPositioning().
8348         * @param {Object} posCfg
8349         * @return {Roo.Element} this
8350          */
8351         setPositioning : function(pc){
8352             this.applyStyles(pc);
8353             if(pc.right == "auto"){
8354                 this.dom.style.right = "";
8355             }
8356             if(pc.bottom == "auto"){
8357                 this.dom.style.bottom = "";
8358             }
8359             return this;
8360         },
8361
8362         // private
8363         fixDisplay : function(){
8364             if(this.getStyle("display") == "none"){
8365                 this.setStyle("visibility", "hidden");
8366                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8367                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8368                     this.setStyle("display", "block");
8369                 }
8370             }
8371         },
8372
8373         /**
8374          * Quick set left and top adding default units
8375          * @param {String} left The left CSS property value
8376          * @param {String} top The top CSS property value
8377          * @return {Roo.Element} this
8378          */
8379          setLeftTop : function(left, top){
8380             this.dom.style.left = this.addUnits(left);
8381             this.dom.style.top = this.addUnits(top);
8382             return this;
8383         },
8384
8385         /**
8386          * Move this element relative to its current position.
8387          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8388          * @param {Number} distance How far to move the element in pixels
8389          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8390          * @return {Roo.Element} this
8391          */
8392          move : function(direction, distance, animate){
8393             var xy = this.getXY();
8394             direction = direction.toLowerCase();
8395             switch(direction){
8396                 case "l":
8397                 case "left":
8398                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8399                     break;
8400                case "r":
8401                case "right":
8402                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8403                     break;
8404                case "t":
8405                case "top":
8406                case "up":
8407                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8408                     break;
8409                case "b":
8410                case "bottom":
8411                case "down":
8412                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8413                     break;
8414             }
8415             return this;
8416         },
8417
8418         /**
8419          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8420          * @return {Roo.Element} this
8421          */
8422         clip : function(){
8423             if(!this.isClipped){
8424                this.isClipped = true;
8425                this.originalClip = {
8426                    "o": this.getStyle("overflow"),
8427                    "x": this.getStyle("overflow-x"),
8428                    "y": this.getStyle("overflow-y")
8429                };
8430                this.setStyle("overflow", "hidden");
8431                this.setStyle("overflow-x", "hidden");
8432                this.setStyle("overflow-y", "hidden");
8433             }
8434             return this;
8435         },
8436
8437         /**
8438          *  Return clipping (overflow) to original clipping before clip() was called
8439          * @return {Roo.Element} this
8440          */
8441         unclip : function(){
8442             if(this.isClipped){
8443                 this.isClipped = false;
8444                 var o = this.originalClip;
8445                 if(o.o){this.setStyle("overflow", o.o);}
8446                 if(o.x){this.setStyle("overflow-x", o.x);}
8447                 if(o.y){this.setStyle("overflow-y", o.y);}
8448             }
8449             return this;
8450         },
8451
8452
8453         /**
8454          * Gets the x,y coordinates specified by the anchor position on the element.
8455          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8456          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8457          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8458          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8459          * @return {Array} [x, y] An array containing the element's x and y coordinates
8460          */
8461         getAnchorXY : function(anchor, local, s){
8462             //Passing a different size is useful for pre-calculating anchors,
8463             //especially for anchored animations that change the el size.
8464
8465             var w, h, vp = false;
8466             if(!s){
8467                 var d = this.dom;
8468                 if(d == document.body || d == document){
8469                     vp = true;
8470                     w = D.getViewWidth(); h = D.getViewHeight();
8471                 }else{
8472                     w = this.getWidth(); h = this.getHeight();
8473                 }
8474             }else{
8475                 w = s.width;  h = s.height;
8476             }
8477             var x = 0, y = 0, r = Math.round;
8478             switch((anchor || "tl").toLowerCase()){
8479                 case "c":
8480                     x = r(w*.5);
8481                     y = r(h*.5);
8482                 break;
8483                 case "t":
8484                     x = r(w*.5);
8485                     y = 0;
8486                 break;
8487                 case "l":
8488                     x = 0;
8489                     y = r(h*.5);
8490                 break;
8491                 case "r":
8492                     x = w;
8493                     y = r(h*.5);
8494                 break;
8495                 case "b":
8496                     x = r(w*.5);
8497                     y = h;
8498                 break;
8499                 case "tl":
8500                     x = 0;
8501                     y = 0;
8502                 break;
8503                 case "bl":
8504                     x = 0;
8505                     y = h;
8506                 break;
8507                 case "br":
8508                     x = w;
8509                     y = h;
8510                 break;
8511                 case "tr":
8512                     x = w;
8513                     y = 0;
8514                 break;
8515             }
8516             if(local === true){
8517                 return [x, y];
8518             }
8519             if(vp){
8520                 var sc = this.getScroll();
8521                 return [x + sc.left, y + sc.top];
8522             }
8523             //Add the element's offset xy
8524             var o = this.getXY();
8525             return [x+o[0], y+o[1]];
8526         },
8527
8528         /**
8529          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8530          * supported position values.
8531          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8532          * @param {String} position The position to align to.
8533          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8534          * @return {Array} [x, y]
8535          */
8536         getAlignToXY : function(el, p, o){
8537             el = Roo.get(el);
8538             var d = this.dom;
8539             if(!el.dom){
8540                 throw "Element.alignTo with an element that doesn't exist";
8541             }
8542             var c = false; //constrain to viewport
8543             var p1 = "", p2 = "";
8544             o = o || [0,0];
8545
8546             if(!p){
8547                 p = "tl-bl";
8548             }else if(p == "?"){
8549                 p = "tl-bl?";
8550             }else if(p.indexOf("-") == -1){
8551                 p = "tl-" + p;
8552             }
8553             p = p.toLowerCase();
8554             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8555             if(!m){
8556                throw "Element.alignTo with an invalid alignment " + p;
8557             }
8558             p1 = m[1]; p2 = m[2]; c = !!m[3];
8559
8560             //Subtract the aligned el's internal xy from the target's offset xy
8561             //plus custom offset to get the aligned el's new offset xy
8562             var a1 = this.getAnchorXY(p1, true);
8563             var a2 = el.getAnchorXY(p2, false);
8564             var x = a2[0] - a1[0] + o[0];
8565             var y = a2[1] - a1[1] + o[1];
8566             if(c){
8567                 //constrain the aligned el to viewport if necessary
8568                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8569                 // 5px of margin for ie
8570                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8571
8572                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8573                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8574                 //otherwise swap the aligned el to the opposite border of the target.
8575                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8576                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8577                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8578                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8579
8580                var doc = document;
8581                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8582                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8583
8584                if((x+w) > dw + scrollX){
8585                     x = swapX ? r.left-w : dw+scrollX-w;
8586                 }
8587                if(x < scrollX){
8588                    x = swapX ? r.right : scrollX;
8589                }
8590                if((y+h) > dh + scrollY){
8591                     y = swapY ? r.top-h : dh+scrollY-h;
8592                 }
8593                if (y < scrollY){
8594                    y = swapY ? r.bottom : scrollY;
8595                }
8596             }
8597             return [x,y];
8598         },
8599
8600         // private
8601         getConstrainToXY : function(){
8602             var os = {top:0, left:0, bottom:0, right: 0};
8603
8604             return function(el, local, offsets, proposedXY){
8605                 el = Roo.get(el);
8606                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8607
8608                 var vw, vh, vx = 0, vy = 0;
8609                 if(el.dom == document.body || el.dom == document){
8610                     vw = Roo.lib.Dom.getViewWidth();
8611                     vh = Roo.lib.Dom.getViewHeight();
8612                 }else{
8613                     vw = el.dom.clientWidth;
8614                     vh = el.dom.clientHeight;
8615                     if(!local){
8616                         var vxy = el.getXY();
8617                         vx = vxy[0];
8618                         vy = vxy[1];
8619                     }
8620                 }
8621
8622                 var s = el.getScroll();
8623
8624                 vx += offsets.left + s.left;
8625                 vy += offsets.top + s.top;
8626
8627                 vw -= offsets.right;
8628                 vh -= offsets.bottom;
8629
8630                 var vr = vx+vw;
8631                 var vb = vy+vh;
8632
8633                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8634                 var x = xy[0], y = xy[1];
8635                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8636
8637                 // only move it if it needs it
8638                 var moved = false;
8639
8640                 // first validate right/bottom
8641                 if((x + w) > vr){
8642                     x = vr - w;
8643                     moved = true;
8644                 }
8645                 if((y + h) > vb){
8646                     y = vb - h;
8647                     moved = true;
8648                 }
8649                 // then make sure top/left isn't negative
8650                 if(x < vx){
8651                     x = vx;
8652                     moved = true;
8653                 }
8654                 if(y < vy){
8655                     y = vy;
8656                     moved = true;
8657                 }
8658                 return moved ? [x, y] : false;
8659             };
8660         }(),
8661
8662         // private
8663         adjustForConstraints : function(xy, parent, offsets){
8664             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8665         },
8666
8667         /**
8668          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8669          * document it aligns it to the viewport.
8670          * The position parameter is optional, and can be specified in any one of the following formats:
8671          * <ul>
8672          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8673          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8674          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8675          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8676          *   <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
8677          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8678          * </ul>
8679          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8680          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8681          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8682          * that specified in order to enforce the viewport constraints.
8683          * Following are all of the supported anchor positions:
8684     <pre>
8685     Value  Description
8686     -----  -----------------------------
8687     tl     The top left corner (default)
8688     t      The center of the top edge
8689     tr     The top right corner
8690     l      The center of the left edge
8691     c      In the center of the element
8692     r      The center of the right edge
8693     bl     The bottom left corner
8694     b      The center of the bottom edge
8695     br     The bottom right corner
8696     </pre>
8697     Example Usage:
8698     <pre><code>
8699     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8700     el.alignTo("other-el");
8701
8702     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8703     el.alignTo("other-el", "tr?");
8704
8705     // align the bottom right corner of el with the center left edge of other-el
8706     el.alignTo("other-el", "br-l?");
8707
8708     // align the center of el with the bottom left corner of other-el and
8709     // adjust the x position by -6 pixels (and the y position by 0)
8710     el.alignTo("other-el", "c-bl", [-6, 0]);
8711     </code></pre>
8712          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8713          * @param {String} position The position to align to.
8714          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8715          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8716          * @return {Roo.Element} this
8717          */
8718         alignTo : function(element, position, offsets, animate){
8719             var xy = this.getAlignToXY(element, position, offsets);
8720             this.setXY(xy, this.preanim(arguments, 3));
8721             return this;
8722         },
8723
8724         /**
8725          * Anchors an element to another element and realigns it when the window is resized.
8726          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8727          * @param {String} position The position to align to.
8728          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8729          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8730          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8731          * is a number, it is used as the buffer delay (defaults to 50ms).
8732          * @param {Function} callback The function to call after the animation finishes
8733          * @return {Roo.Element} this
8734          */
8735         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8736             var action = function(){
8737                 this.alignTo(el, alignment, offsets, animate);
8738                 Roo.callback(callback, this);
8739             };
8740             Roo.EventManager.onWindowResize(action, this);
8741             var tm = typeof monitorScroll;
8742             if(tm != 'undefined'){
8743                 Roo.EventManager.on(window, 'scroll', action, this,
8744                     {buffer: tm == 'number' ? monitorScroll : 50});
8745             }
8746             action.call(this); // align immediately
8747             return this;
8748         },
8749         /**
8750          * Clears any opacity settings from this element. Required in some cases for IE.
8751          * @return {Roo.Element} this
8752          */
8753         clearOpacity : function(){
8754             if (window.ActiveXObject) {
8755                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8756                     this.dom.style.filter = "";
8757                 }
8758             } else {
8759                 this.dom.style.opacity = "";
8760                 this.dom.style["-moz-opacity"] = "";
8761                 this.dom.style["-khtml-opacity"] = "";
8762             }
8763             return this;
8764         },
8765
8766         /**
8767          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8768          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8769          * @return {Roo.Element} this
8770          */
8771         hide : function(animate){
8772             this.setVisible(false, this.preanim(arguments, 0));
8773             return this;
8774         },
8775
8776         /**
8777         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8778         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8779          * @return {Roo.Element} this
8780          */
8781         show : function(animate){
8782             this.setVisible(true, this.preanim(arguments, 0));
8783             return this;
8784         },
8785
8786         /**
8787          * @private Test if size has a unit, otherwise appends the default
8788          */
8789         addUnits : function(size){
8790             return Roo.Element.addUnits(size, this.defaultUnit);
8791         },
8792
8793         /**
8794          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8795          * @return {Roo.Element} this
8796          */
8797         beginMeasure : function(){
8798             var el = this.dom;
8799             if(el.offsetWidth || el.offsetHeight){
8800                 return this; // offsets work already
8801             }
8802             var changed = [];
8803             var p = this.dom, b = document.body; // start with this element
8804             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8805                 var pe = Roo.get(p);
8806                 if(pe.getStyle('display') == 'none'){
8807                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8808                     p.style.visibility = "hidden";
8809                     p.style.display = "block";
8810                 }
8811                 p = p.parentNode;
8812             }
8813             this._measureChanged = changed;
8814             return this;
8815
8816         },
8817
8818         /**
8819          * Restores displays to before beginMeasure was called
8820          * @return {Roo.Element} this
8821          */
8822         endMeasure : function(){
8823             var changed = this._measureChanged;
8824             if(changed){
8825                 for(var i = 0, len = changed.length; i < len; i++) {
8826                     var r = changed[i];
8827                     r.el.style.visibility = r.visibility;
8828                     r.el.style.display = "none";
8829                 }
8830                 this._measureChanged = null;
8831             }
8832             return this;
8833         },
8834
8835         /**
8836         * Update the innerHTML of this element, optionally searching for and processing scripts
8837         * @param {String} html The new HTML
8838         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8839         * @param {Function} callback For async script loading you can be noticed when the update completes
8840         * @return {Roo.Element} this
8841          */
8842         update : function(html, loadScripts, callback){
8843             if(typeof html == "undefined"){
8844                 html = "";
8845             }
8846             if(loadScripts !== true){
8847                 this.dom.innerHTML = html;
8848                 if(typeof callback == "function"){
8849                     callback();
8850                 }
8851                 return this;
8852             }
8853             var id = Roo.id();
8854             var dom = this.dom;
8855
8856             html += '<span id="' + id + '"></span>';
8857
8858             E.onAvailable(id, function(){
8859                 var hd = document.getElementsByTagName("head")[0];
8860                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8861                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8862                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8863
8864                 var match;
8865                 while(match = re.exec(html)){
8866                     var attrs = match[1];
8867                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8868                     if(srcMatch && srcMatch[2]){
8869                        var s = document.createElement("script");
8870                        s.src = srcMatch[2];
8871                        var typeMatch = attrs.match(typeRe);
8872                        if(typeMatch && typeMatch[2]){
8873                            s.type = typeMatch[2];
8874                        }
8875                        hd.appendChild(s);
8876                     }else if(match[2] && match[2].length > 0){
8877                         if(window.execScript) {
8878                            window.execScript(match[2]);
8879                         } else {
8880                             /**
8881                              * eval:var:id
8882                              * eval:var:dom
8883                              * eval:var:html
8884                              * 
8885                              */
8886                            window.eval(match[2]);
8887                         }
8888                     }
8889                 }
8890                 var el = document.getElementById(id);
8891                 if(el){el.parentNode.removeChild(el);}
8892                 if(typeof callback == "function"){
8893                     callback();
8894                 }
8895             });
8896             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8897             return this;
8898         },
8899
8900         /**
8901          * Direct access to the UpdateManager update() method (takes the same parameters).
8902          * @param {String/Function} url The url for this request or a function to call to get the url
8903          * @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}
8904          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8905          * @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.
8906          * @return {Roo.Element} this
8907          */
8908         load : function(){
8909             var um = this.getUpdateManager();
8910             um.update.apply(um, arguments);
8911             return this;
8912         },
8913
8914         /**
8915         * Gets this element's UpdateManager
8916         * @return {Roo.UpdateManager} The UpdateManager
8917         */
8918         getUpdateManager : function(){
8919             if(!this.updateManager){
8920                 this.updateManager = new Roo.UpdateManager(this);
8921             }
8922             return this.updateManager;
8923         },
8924
8925         /**
8926          * Disables text selection for this element (normalized across browsers)
8927          * @return {Roo.Element} this
8928          */
8929         unselectable : function(){
8930             this.dom.unselectable = "on";
8931             this.swallowEvent("selectstart", true);
8932             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8933             this.addClass("x-unselectable");
8934             return this;
8935         },
8936
8937         /**
8938         * Calculates the x, y to center this element on the screen
8939         * @return {Array} The x, y values [x, y]
8940         */
8941         getCenterXY : function(){
8942             return this.getAlignToXY(document, 'c-c');
8943         },
8944
8945         /**
8946         * Centers the Element in either the viewport, or another Element.
8947         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8948         */
8949         center : function(centerIn){
8950             this.alignTo(centerIn || document, 'c-c');
8951             return this;
8952         },
8953
8954         /**
8955          * Tests various css rules/browsers to determine if this element uses a border box
8956          * @return {Boolean}
8957          */
8958         isBorderBox : function(){
8959             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8960         },
8961
8962         /**
8963          * Return a box {x, y, width, height} that can be used to set another elements
8964          * size/location to match this element.
8965          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8966          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8967          * @return {Object} box An object in the format {x, y, width, height}
8968          */
8969         getBox : function(contentBox, local){
8970             var xy;
8971             if(!local){
8972                 xy = this.getXY();
8973             }else{
8974                 var left = parseInt(this.getStyle("left"), 10) || 0;
8975                 var top = parseInt(this.getStyle("top"), 10) || 0;
8976                 xy = [left, top];
8977             }
8978             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8979             if(!contentBox){
8980                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8981             }else{
8982                 var l = this.getBorderWidth("l")+this.getPadding("l");
8983                 var r = this.getBorderWidth("r")+this.getPadding("r");
8984                 var t = this.getBorderWidth("t")+this.getPadding("t");
8985                 var b = this.getBorderWidth("b")+this.getPadding("b");
8986                 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)};
8987             }
8988             bx.right = bx.x + bx.width;
8989             bx.bottom = bx.y + bx.height;
8990             return bx;
8991         },
8992
8993         /**
8994          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8995          for more information about the sides.
8996          * @param {String} sides
8997          * @return {Number}
8998          */
8999         getFrameWidth : function(sides, onlyContentBox){
9000             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9001         },
9002
9003         /**
9004          * 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.
9005          * @param {Object} box The box to fill {x, y, width, height}
9006          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9007          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9008          * @return {Roo.Element} this
9009          */
9010         setBox : function(box, adjust, animate){
9011             var w = box.width, h = box.height;
9012             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9013                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9014                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9015             }
9016             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9017             return this;
9018         },
9019
9020         /**
9021          * Forces the browser to repaint this element
9022          * @return {Roo.Element} this
9023          */
9024          repaint : function(){
9025             var dom = this.dom;
9026             this.addClass("x-repaint");
9027             setTimeout(function(){
9028                 Roo.get(dom).removeClass("x-repaint");
9029             }, 1);
9030             return this;
9031         },
9032
9033         /**
9034          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9035          * then it returns the calculated width of the sides (see getPadding)
9036          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9037          * @return {Object/Number}
9038          */
9039         getMargins : function(side){
9040             if(!side){
9041                 return {
9042                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9043                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9044                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9045                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9046                 };
9047             }else{
9048                 return this.addStyles(side, El.margins);
9049              }
9050         },
9051
9052         // private
9053         addStyles : function(sides, styles){
9054             var val = 0, v, w;
9055             for(var i = 0, len = sides.length; i < len; i++){
9056                 v = this.getStyle(styles[sides.charAt(i)]);
9057                 if(v){
9058                      w = parseInt(v, 10);
9059                      if(w){ val += w; }
9060                 }
9061             }
9062             return val;
9063         },
9064
9065         /**
9066          * Creates a proxy element of this element
9067          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9068          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9069          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9070          * @return {Roo.Element} The new proxy element
9071          */
9072         createProxy : function(config, renderTo, matchBox){
9073             if(renderTo){
9074                 renderTo = Roo.getDom(renderTo);
9075             }else{
9076                 renderTo = document.body;
9077             }
9078             config = typeof config == "object" ?
9079                 config : {tag : "div", cls: config};
9080             var proxy = Roo.DomHelper.append(renderTo, config, true);
9081             if(matchBox){
9082                proxy.setBox(this.getBox());
9083             }
9084             return proxy;
9085         },
9086
9087         /**
9088          * Puts a mask over this element to disable user interaction. Requires core.css.
9089          * This method can only be applied to elements which accept child nodes.
9090          * @param {String} msg (optional) A message to display in the mask
9091          * @param {String} msgCls (optional) A css class to apply to the msg element
9092          * @return {Element} The mask  element
9093          */
9094         mask : function(msg, msgCls)
9095         {
9096             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9097                 this.setStyle("position", "relative");
9098             }
9099             if(!this._mask){
9100                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9101             }
9102             this.addClass("x-masked");
9103             this._mask.setDisplayed(true);
9104             
9105             // we wander
9106             var z = 0;
9107             var dom = this.dom;
9108             while (dom && dom.style) {
9109                 if (!isNaN(parseInt(dom.style.zIndex))) {
9110                     z = Math.max(z, parseInt(dom.style.zIndex));
9111                 }
9112                 dom = dom.parentNode;
9113             }
9114             // if we are masking the body - then it hides everything..
9115             if (this.dom == document.body) {
9116                 z = 1000000;
9117                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9118                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9119             }
9120            
9121             if(typeof msg == 'string'){
9122                 if(!this._maskMsg){
9123                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9124                 }
9125                 var mm = this._maskMsg;
9126                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9127                 if (mm.dom.firstChild) { // weird IE issue?
9128                     mm.dom.firstChild.innerHTML = msg;
9129                 }
9130                 mm.setDisplayed(true);
9131                 mm.center(this);
9132                 mm.setStyle('z-index', z + 102);
9133             }
9134             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9135                 this._mask.setHeight(this.getHeight());
9136             }
9137             this._mask.setStyle('z-index', z + 100);
9138             
9139             return this._mask;
9140         },
9141
9142         /**
9143          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9144          * it is cached for reuse.
9145          */
9146         unmask : function(removeEl){
9147             if(this._mask){
9148                 if(removeEl === true){
9149                     this._mask.remove();
9150                     delete this._mask;
9151                     if(this._maskMsg){
9152                         this._maskMsg.remove();
9153                         delete this._maskMsg;
9154                     }
9155                 }else{
9156                     this._mask.setDisplayed(false);
9157                     if(this._maskMsg){
9158                         this._maskMsg.setDisplayed(false);
9159                     }
9160                 }
9161             }
9162             this.removeClass("x-masked");
9163         },
9164
9165         /**
9166          * Returns true if this element is masked
9167          * @return {Boolean}
9168          */
9169         isMasked : function(){
9170             return this._mask && this._mask.isVisible();
9171         },
9172
9173         /**
9174          * Creates an iframe shim for this element to keep selects and other windowed objects from
9175          * showing through.
9176          * @return {Roo.Element} The new shim element
9177          */
9178         createShim : function(){
9179             var el = document.createElement('iframe');
9180             el.frameBorder = 'no';
9181             el.className = 'roo-shim';
9182             if(Roo.isIE && Roo.isSecure){
9183                 el.src = Roo.SSL_SECURE_URL;
9184             }
9185             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9186             shim.autoBoxAdjust = false;
9187             return shim;
9188         },
9189
9190         /**
9191          * Removes this element from the DOM and deletes it from the cache
9192          */
9193         remove : function(){
9194             if(this.dom.parentNode){
9195                 this.dom.parentNode.removeChild(this.dom);
9196             }
9197             delete El.cache[this.dom.id];
9198         },
9199
9200         /**
9201          * Sets up event handlers to add and remove a css class when the mouse is over this element
9202          * @param {String} className
9203          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9204          * mouseout events for children elements
9205          * @return {Roo.Element} this
9206          */
9207         addClassOnOver : function(className, preventFlicker){
9208             this.on("mouseover", function(){
9209                 Roo.fly(this, '_internal').addClass(className);
9210             }, this.dom);
9211             var removeFn = function(e){
9212                 if(preventFlicker !== true || !e.within(this, true)){
9213                     Roo.fly(this, '_internal').removeClass(className);
9214                 }
9215             };
9216             this.on("mouseout", removeFn, this.dom);
9217             return this;
9218         },
9219
9220         /**
9221          * Sets up event handlers to add and remove a css class when this element has the focus
9222          * @param {String} className
9223          * @return {Roo.Element} this
9224          */
9225         addClassOnFocus : function(className){
9226             this.on("focus", function(){
9227                 Roo.fly(this, '_internal').addClass(className);
9228             }, this.dom);
9229             this.on("blur", function(){
9230                 Roo.fly(this, '_internal').removeClass(className);
9231             }, this.dom);
9232             return this;
9233         },
9234         /**
9235          * 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)
9236          * @param {String} className
9237          * @return {Roo.Element} this
9238          */
9239         addClassOnClick : function(className){
9240             var dom = this.dom;
9241             this.on("mousedown", function(){
9242                 Roo.fly(dom, '_internal').addClass(className);
9243                 var d = Roo.get(document);
9244                 var fn = function(){
9245                     Roo.fly(dom, '_internal').removeClass(className);
9246                     d.removeListener("mouseup", fn);
9247                 };
9248                 d.on("mouseup", fn);
9249             });
9250             return this;
9251         },
9252
9253         /**
9254          * Stops the specified event from bubbling and optionally prevents the default action
9255          * @param {String} eventName
9256          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9257          * @return {Roo.Element} this
9258          */
9259         swallowEvent : function(eventName, preventDefault){
9260             var fn = function(e){
9261                 e.stopPropagation();
9262                 if(preventDefault){
9263                     e.preventDefault();
9264                 }
9265             };
9266             if(eventName instanceof Array){
9267                 for(var i = 0, len = eventName.length; i < len; i++){
9268                      this.on(eventName[i], fn);
9269                 }
9270                 return this;
9271             }
9272             this.on(eventName, fn);
9273             return this;
9274         },
9275
9276         /**
9277          * @private
9278          */
9279       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9280
9281         /**
9282          * Sizes this element to its parent element's dimensions performing
9283          * neccessary box adjustments.
9284          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9285          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9286          * @return {Roo.Element} this
9287          */
9288         fitToParent : function(monitorResize, targetParent) {
9289           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9290           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9291           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9292             return;
9293           }
9294           var p = Roo.get(targetParent || this.dom.parentNode);
9295           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9296           if (monitorResize === true) {
9297             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9298             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9299           }
9300           return this;
9301         },
9302
9303         /**
9304          * Gets the next sibling, skipping text nodes
9305          * @return {HTMLElement} The next sibling or null
9306          */
9307         getNextSibling : function(){
9308             var n = this.dom.nextSibling;
9309             while(n && n.nodeType != 1){
9310                 n = n.nextSibling;
9311             }
9312             return n;
9313         },
9314
9315         /**
9316          * Gets the previous sibling, skipping text nodes
9317          * @return {HTMLElement} The previous sibling or null
9318          */
9319         getPrevSibling : function(){
9320             var n = this.dom.previousSibling;
9321             while(n && n.nodeType != 1){
9322                 n = n.previousSibling;
9323             }
9324             return n;
9325         },
9326
9327
9328         /**
9329          * Appends the passed element(s) to this element
9330          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9331          * @return {Roo.Element} this
9332          */
9333         appendChild: function(el){
9334             el = Roo.get(el);
9335             el.appendTo(this);
9336             return this;
9337         },
9338
9339         /**
9340          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9341          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9342          * automatically generated with the specified attributes.
9343          * @param {HTMLElement} insertBefore (optional) a child element of this element
9344          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9345          * @return {Roo.Element} The new child element
9346          */
9347         createChild: function(config, insertBefore, returnDom){
9348             config = config || {tag:'div'};
9349             if(insertBefore){
9350                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9351             }
9352             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9353         },
9354
9355         /**
9356          * Appends this element to the passed element
9357          * @param {String/HTMLElement/Element} el The new parent element
9358          * @return {Roo.Element} this
9359          */
9360         appendTo: function(el){
9361             el = Roo.getDom(el);
9362             el.appendChild(this.dom);
9363             return this;
9364         },
9365
9366         /**
9367          * Inserts this element before the passed element in the DOM
9368          * @param {String/HTMLElement/Element} el The element to insert before
9369          * @return {Roo.Element} this
9370          */
9371         insertBefore: function(el){
9372             el = Roo.getDom(el);
9373             el.parentNode.insertBefore(this.dom, el);
9374             return this;
9375         },
9376
9377         /**
9378          * Inserts this element after the passed element in the DOM
9379          * @param {String/HTMLElement/Element} el The element to insert after
9380          * @return {Roo.Element} this
9381          */
9382         insertAfter: function(el){
9383             el = Roo.getDom(el);
9384             el.parentNode.insertBefore(this.dom, el.nextSibling);
9385             return this;
9386         },
9387
9388         /**
9389          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9390          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9391          * @return {Roo.Element} The new child
9392          */
9393         insertFirst: function(el, returnDom){
9394             el = el || {};
9395             if(typeof el == 'object' && !el.nodeType){ // dh config
9396                 return this.createChild(el, this.dom.firstChild, returnDom);
9397             }else{
9398                 el = Roo.getDom(el);
9399                 this.dom.insertBefore(el, this.dom.firstChild);
9400                 return !returnDom ? Roo.get(el) : el;
9401             }
9402         },
9403
9404         /**
9405          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9406          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9407          * @param {String} where (optional) 'before' or 'after' defaults to before
9408          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9409          * @return {Roo.Element} the inserted Element
9410          */
9411         insertSibling: function(el, where, returnDom){
9412             where = where ? where.toLowerCase() : 'before';
9413             el = el || {};
9414             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9415
9416             if(typeof el == 'object' && !el.nodeType){ // dh config
9417                 if(where == 'after' && !this.dom.nextSibling){
9418                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9419                 }else{
9420                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9421                 }
9422
9423             }else{
9424                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9425                             where == 'before' ? this.dom : this.dom.nextSibling);
9426                 if(!returnDom){
9427                     rt = Roo.get(rt);
9428                 }
9429             }
9430             return rt;
9431         },
9432
9433         /**
9434          * Creates and wraps this element with another element
9435          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9436          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9437          * @return {HTMLElement/Element} The newly created wrapper element
9438          */
9439         wrap: function(config, returnDom){
9440             if(!config){
9441                 config = {tag: "div"};
9442             }
9443             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9444             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9445             return newEl;
9446         },
9447
9448         /**
9449          * Replaces the passed element with this element
9450          * @param {String/HTMLElement/Element} el The element to replace
9451          * @return {Roo.Element} this
9452          */
9453         replace: function(el){
9454             el = Roo.get(el);
9455             this.insertBefore(el);
9456             el.remove();
9457             return this;
9458         },
9459
9460         /**
9461          * Inserts an html fragment into this element
9462          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9463          * @param {String} html The HTML fragment
9464          * @param {Boolean} returnEl True to return an Roo.Element
9465          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9466          */
9467         insertHtml : function(where, html, returnEl){
9468             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9469             return returnEl ? Roo.get(el) : el;
9470         },
9471
9472         /**
9473          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9474          * @param {Object} o The object with the attributes
9475          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9476          * @return {Roo.Element} this
9477          */
9478         set : function(o, useSet){
9479             var el = this.dom;
9480             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9481             for(var attr in o){
9482                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9483                 if(attr=="cls"){
9484                     el.className = o["cls"];
9485                 }else{
9486                     if(useSet) {
9487                         el.setAttribute(attr, o[attr]);
9488                     } else {
9489                         el[attr] = o[attr];
9490                     }
9491                 }
9492             }
9493             if(o.style){
9494                 Roo.DomHelper.applyStyles(el, o.style);
9495             }
9496             return this;
9497         },
9498
9499         /**
9500          * Convenience method for constructing a KeyMap
9501          * @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:
9502          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9503          * @param {Function} fn The function to call
9504          * @param {Object} scope (optional) The scope of the function
9505          * @return {Roo.KeyMap} The KeyMap created
9506          */
9507         addKeyListener : function(key, fn, scope){
9508             var config;
9509             if(typeof key != "object" || key instanceof Array){
9510                 config = {
9511                     key: key,
9512                     fn: fn,
9513                     scope: scope
9514                 };
9515             }else{
9516                 config = {
9517                     key : key.key,
9518                     shift : key.shift,
9519                     ctrl : key.ctrl,
9520                     alt : key.alt,
9521                     fn: fn,
9522                     scope: scope
9523                 };
9524             }
9525             return new Roo.KeyMap(this, config);
9526         },
9527
9528         /**
9529          * Creates a KeyMap for this element
9530          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9531          * @return {Roo.KeyMap} The KeyMap created
9532          */
9533         addKeyMap : function(config){
9534             return new Roo.KeyMap(this, config);
9535         },
9536
9537         /**
9538          * Returns true if this element is scrollable.
9539          * @return {Boolean}
9540          */
9541          isScrollable : function(){
9542             var dom = this.dom;
9543             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9544         },
9545
9546         /**
9547          * 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().
9548          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9549          * @param {Number} value The new scroll value
9550          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9551          * @return {Element} this
9552          */
9553
9554         scrollTo : function(side, value, animate){
9555             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9556             if(!animate || !A){
9557                 this.dom[prop] = value;
9558             }else{
9559                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9560                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9561             }
9562             return this;
9563         },
9564
9565         /**
9566          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9567          * within this element's scrollable range.
9568          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9569          * @param {Number} distance How far to scroll the element in pixels
9570          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9571          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9572          * was scrolled as far as it could go.
9573          */
9574          scroll : function(direction, distance, animate){
9575              if(!this.isScrollable()){
9576                  return;
9577              }
9578              var el = this.dom;
9579              var l = el.scrollLeft, t = el.scrollTop;
9580              var w = el.scrollWidth, h = el.scrollHeight;
9581              var cw = el.clientWidth, ch = el.clientHeight;
9582              direction = direction.toLowerCase();
9583              var scrolled = false;
9584              var a = this.preanim(arguments, 2);
9585              switch(direction){
9586                  case "l":
9587                  case "left":
9588                      if(w - l > cw){
9589                          var v = Math.min(l + distance, w-cw);
9590                          this.scrollTo("left", v, a);
9591                          scrolled = true;
9592                      }
9593                      break;
9594                 case "r":
9595                 case "right":
9596                      if(l > 0){
9597                          var v = Math.max(l - distance, 0);
9598                          this.scrollTo("left", v, a);
9599                          scrolled = true;
9600                      }
9601                      break;
9602                 case "t":
9603                 case "top":
9604                 case "up":
9605                      if(t > 0){
9606                          var v = Math.max(t - distance, 0);
9607                          this.scrollTo("top", v, a);
9608                          scrolled = true;
9609                      }
9610                      break;
9611                 case "b":
9612                 case "bottom":
9613                 case "down":
9614                      if(h - t > ch){
9615                          var v = Math.min(t + distance, h-ch);
9616                          this.scrollTo("top", v, a);
9617                          scrolled = true;
9618                      }
9619                      break;
9620              }
9621              return scrolled;
9622         },
9623
9624         /**
9625          * Translates the passed page coordinates into left/top css values for this element
9626          * @param {Number/Array} x The page x or an array containing [x, y]
9627          * @param {Number} y The page y
9628          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9629          */
9630         translatePoints : function(x, y){
9631             if(typeof x == 'object' || x instanceof Array){
9632                 y = x[1]; x = x[0];
9633             }
9634             var p = this.getStyle('position');
9635             var o = this.getXY();
9636
9637             var l = parseInt(this.getStyle('left'), 10);
9638             var t = parseInt(this.getStyle('top'), 10);
9639
9640             if(isNaN(l)){
9641                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9642             }
9643             if(isNaN(t)){
9644                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9645             }
9646
9647             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9648         },
9649
9650         /**
9651          * Returns the current scroll position of the element.
9652          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9653          */
9654         getScroll : function(){
9655             var d = this.dom, doc = document;
9656             if(d == doc || d == doc.body){
9657                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9658                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9659                 return {left: l, top: t};
9660             }else{
9661                 return {left: d.scrollLeft, top: d.scrollTop};
9662             }
9663         },
9664
9665         /**
9666          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9667          * are convert to standard 6 digit hex color.
9668          * @param {String} attr The css attribute
9669          * @param {String} defaultValue The default value to use when a valid color isn't found
9670          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9671          * YUI color anims.
9672          */
9673         getColor : function(attr, defaultValue, prefix){
9674             var v = this.getStyle(attr);
9675             if(!v || v == "transparent" || v == "inherit") {
9676                 return defaultValue;
9677             }
9678             var color = typeof prefix == "undefined" ? "#" : prefix;
9679             if(v.substr(0, 4) == "rgb("){
9680                 var rvs = v.slice(4, v.length -1).split(",");
9681                 for(var i = 0; i < 3; i++){
9682                     var h = parseInt(rvs[i]).toString(16);
9683                     if(h < 16){
9684                         h = "0" + h;
9685                     }
9686                     color += h;
9687                 }
9688             } else {
9689                 if(v.substr(0, 1) == "#"){
9690                     if(v.length == 4) {
9691                         for(var i = 1; i < 4; i++){
9692                             var c = v.charAt(i);
9693                             color +=  c + c;
9694                         }
9695                     }else if(v.length == 7){
9696                         color += v.substr(1);
9697                     }
9698                 }
9699             }
9700             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9701         },
9702
9703         /**
9704          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9705          * gradient background, rounded corners and a 4-way shadow.
9706          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9707          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9708          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9709          * @return {Roo.Element} this
9710          */
9711         boxWrap : function(cls){
9712             cls = cls || 'x-box';
9713             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9714             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9715             return el;
9716         },
9717
9718         /**
9719          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9720          * @param {String} namespace The namespace in which to look for the attribute
9721          * @param {String} name The attribute name
9722          * @return {String} The attribute value
9723          */
9724         getAttributeNS : Roo.isIE ? function(ns, name){
9725             var d = this.dom;
9726             var type = typeof d[ns+":"+name];
9727             if(type != 'undefined' && type != 'unknown'){
9728                 return d[ns+":"+name];
9729             }
9730             return d[name];
9731         } : function(ns, name){
9732             var d = this.dom;
9733             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9734         },
9735         
9736         
9737         /**
9738          * Sets or Returns the value the dom attribute value
9739          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9740          * @param {String} value (optional) The value to set the attribute to
9741          * @return {String} The attribute value
9742          */
9743         attr : function(name){
9744             if (arguments.length > 1) {
9745                 this.dom.setAttribute(name, arguments[1]);
9746                 return arguments[1];
9747             }
9748             if (typeof(name) == 'object') {
9749                 for(var i in name) {
9750                     this.attr(i, name[i]);
9751                 }
9752                 return name;
9753             }
9754             
9755             
9756             if (!this.dom.hasAttribute(name)) {
9757                 return undefined;
9758             }
9759             return this.dom.getAttribute(name);
9760         }
9761         
9762         
9763         
9764     };
9765
9766     var ep = El.prototype;
9767
9768     /**
9769      * Appends an event handler (Shorthand for addListener)
9770      * @param {String}   eventName     The type of event to append
9771      * @param {Function} fn        The method the event invokes
9772      * @param {Object} scope       (optional) The scope (this object) of the fn
9773      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9774      * @method
9775      */
9776     ep.on = ep.addListener;
9777         // backwards compat
9778     ep.mon = ep.addListener;
9779
9780     /**
9781      * Removes an event handler from this element (shorthand for removeListener)
9782      * @param {String} eventName the type of event to remove
9783      * @param {Function} fn the method the event invokes
9784      * @return {Roo.Element} this
9785      * @method
9786      */
9787     ep.un = ep.removeListener;
9788
9789     /**
9790      * true to automatically adjust width and height settings for box-model issues (default to true)
9791      */
9792     ep.autoBoxAdjust = true;
9793
9794     // private
9795     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9796
9797     // private
9798     El.addUnits = function(v, defaultUnit){
9799         if(v === "" || v == "auto"){
9800             return v;
9801         }
9802         if(v === undefined){
9803             return '';
9804         }
9805         if(typeof v == "number" || !El.unitPattern.test(v)){
9806             return v + (defaultUnit || 'px');
9807         }
9808         return v;
9809     };
9810
9811     // special markup used throughout Roo when box wrapping elements
9812     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>';
9813     /**
9814      * Visibility mode constant - Use visibility to hide element
9815      * @static
9816      * @type Number
9817      */
9818     El.VISIBILITY = 1;
9819     /**
9820      * Visibility mode constant - Use display to hide element
9821      * @static
9822      * @type Number
9823      */
9824     El.DISPLAY = 2;
9825
9826     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9827     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9828     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9829
9830
9831
9832     /**
9833      * @private
9834      */
9835     El.cache = {};
9836
9837     var docEl;
9838
9839     /**
9840      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9841      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9842      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9843      * @return {Element} The Element object
9844      * @static
9845      */
9846     El.get = function(el){
9847         var ex, elm, id;
9848         if(!el){ return null; }
9849         if(typeof el == "string"){ // element id
9850             if(!(elm = document.getElementById(el))){
9851                 return null;
9852             }
9853             if(ex = El.cache[el]){
9854                 ex.dom = elm;
9855             }else{
9856                 ex = El.cache[el] = new El(elm);
9857             }
9858             return ex;
9859         }else if(el.tagName){ // dom element
9860             if(!(id = el.id)){
9861                 id = Roo.id(el);
9862             }
9863             if(ex = El.cache[id]){
9864                 ex.dom = el;
9865             }else{
9866                 ex = El.cache[id] = new El(el);
9867             }
9868             return ex;
9869         }else if(el instanceof El){
9870             if(el != docEl){
9871                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9872                                                               // catch case where it hasn't been appended
9873                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9874             }
9875             return el;
9876         }else if(el.isComposite){
9877             return el;
9878         }else if(el instanceof Array){
9879             return El.select(el);
9880         }else if(el == document){
9881             // create a bogus element object representing the document object
9882             if(!docEl){
9883                 var f = function(){};
9884                 f.prototype = El.prototype;
9885                 docEl = new f();
9886                 docEl.dom = document;
9887             }
9888             return docEl;
9889         }
9890         return null;
9891     };
9892
9893     // private
9894     El.uncache = function(el){
9895         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9896             if(a[i]){
9897                 delete El.cache[a[i].id || a[i]];
9898             }
9899         }
9900     };
9901
9902     // private
9903     // Garbage collection - uncache elements/purge listeners on orphaned elements
9904     // so we don't hold a reference and cause the browser to retain them
9905     El.garbageCollect = function(){
9906         if(!Roo.enableGarbageCollector){
9907             clearInterval(El.collectorThread);
9908             return;
9909         }
9910         for(var eid in El.cache){
9911             var el = El.cache[eid], d = el.dom;
9912             // -------------------------------------------------------
9913             // Determining what is garbage:
9914             // -------------------------------------------------------
9915             // !d
9916             // dom node is null, definitely garbage
9917             // -------------------------------------------------------
9918             // !d.parentNode
9919             // no parentNode == direct orphan, definitely garbage
9920             // -------------------------------------------------------
9921             // !d.offsetParent && !document.getElementById(eid)
9922             // display none elements have no offsetParent so we will
9923             // also try to look it up by it's id. However, check
9924             // offsetParent first so we don't do unneeded lookups.
9925             // This enables collection of elements that are not orphans
9926             // directly, but somewhere up the line they have an orphan
9927             // parent.
9928             // -------------------------------------------------------
9929             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9930                 delete El.cache[eid];
9931                 if(d && Roo.enableListenerCollection){
9932                     E.purgeElement(d);
9933                 }
9934             }
9935         }
9936     }
9937     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9938
9939
9940     // dom is optional
9941     El.Flyweight = function(dom){
9942         this.dom = dom;
9943     };
9944     El.Flyweight.prototype = El.prototype;
9945
9946     El._flyweights = {};
9947     /**
9948      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9949      * the dom node can be overwritten by other code.
9950      * @param {String/HTMLElement} el The dom node or id
9951      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9952      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9953      * @static
9954      * @return {Element} The shared Element object
9955      */
9956     El.fly = function(el, named){
9957         named = named || '_global';
9958         el = Roo.getDom(el);
9959         if(!el){
9960             return null;
9961         }
9962         if(!El._flyweights[named]){
9963             El._flyweights[named] = new El.Flyweight();
9964         }
9965         El._flyweights[named].dom = el;
9966         return El._flyweights[named];
9967     };
9968
9969     /**
9970      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9971      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9972      * Shorthand of {@link Roo.Element#get}
9973      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9974      * @return {Element} The Element object
9975      * @member Roo
9976      * @method get
9977      */
9978     Roo.get = El.get;
9979     /**
9980      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9981      * the dom node can be overwritten by other code.
9982      * Shorthand of {@link Roo.Element#fly}
9983      * @param {String/HTMLElement} el The dom node or id
9984      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9985      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9986      * @static
9987      * @return {Element} The shared Element object
9988      * @member Roo
9989      * @method fly
9990      */
9991     Roo.fly = El.fly;
9992
9993     // speedy lookup for elements never to box adjust
9994     var noBoxAdjust = Roo.isStrict ? {
9995         select:1
9996     } : {
9997         input:1, select:1, textarea:1
9998     };
9999     if(Roo.isIE || Roo.isGecko){
10000         noBoxAdjust['button'] = 1;
10001     }
10002
10003
10004     Roo.EventManager.on(window, 'unload', function(){
10005         delete El.cache;
10006         delete El._flyweights;
10007     });
10008 })();
10009
10010
10011
10012
10013 if(Roo.DomQuery){
10014     Roo.Element.selectorFunction = Roo.DomQuery.select;
10015 }
10016
10017 Roo.Element.select = function(selector, unique, root){
10018     var els;
10019     if(typeof selector == "string"){
10020         els = Roo.Element.selectorFunction(selector, root);
10021     }else if(selector.length !== undefined){
10022         els = selector;
10023     }else{
10024         throw "Invalid selector";
10025     }
10026     if(unique === true){
10027         return new Roo.CompositeElement(els);
10028     }else{
10029         return new Roo.CompositeElementLite(els);
10030     }
10031 };
10032 /**
10033  * Selects elements based on the passed CSS selector to enable working on them as 1.
10034  * @param {String/Array} selector The CSS selector or an array of elements
10035  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10036  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10037  * @return {CompositeElementLite/CompositeElement}
10038  * @member Roo
10039  * @method select
10040  */
10041 Roo.select = Roo.Element.select;
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056 /*
10057  * Based on:
10058  * Ext JS Library 1.1.1
10059  * Copyright(c) 2006-2007, Ext JS, LLC.
10060  *
10061  * Originally Released Under LGPL - original licence link has changed is not relivant.
10062  *
10063  * Fork - LGPL
10064  * <script type="text/javascript">
10065  */
10066
10067
10068
10069 //Notifies Element that fx methods are available
10070 Roo.enableFx = true;
10071
10072 /**
10073  * @class Roo.Fx
10074  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10075  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10076  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10077  * Element effects to work.</p><br/>
10078  *
10079  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10080  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10081  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10082  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10083  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10084  * expected results and should be done with care.</p><br/>
10085  *
10086  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10087  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10088 <pre>
10089 Value  Description
10090 -----  -----------------------------
10091 tl     The top left corner
10092 t      The center of the top edge
10093 tr     The top right corner
10094 l      The center of the left edge
10095 r      The center of the right edge
10096 bl     The bottom left corner
10097 b      The center of the bottom edge
10098 br     The bottom right corner
10099 </pre>
10100  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10101  * below are common options that can be passed to any Fx method.</b>
10102  * @cfg {Function} callback A function called when the effect is finished
10103  * @cfg {Object} scope The scope of the effect function
10104  * @cfg {String} easing A valid Easing value for the effect
10105  * @cfg {String} afterCls A css class to apply after the effect
10106  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10107  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10108  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10109  * effects that end with the element being visually hidden, ignored otherwise)
10110  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10111  * a function which returns such a specification that will be applied to the Element after the effect finishes
10112  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10113  * @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
10114  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10115  */
10116 Roo.Fx = {
10117         /**
10118          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10119          * origin for the slide effect.  This function automatically handles wrapping the element with
10120          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10121          * Usage:
10122          *<pre><code>
10123 // default: slide the element in from the top
10124 el.slideIn();
10125
10126 // custom: slide the element in from the right with a 2-second duration
10127 el.slideIn('r', { duration: 2 });
10128
10129 // common config options shown with default values
10130 el.slideIn('t', {
10131     easing: 'easeOut',
10132     duration: .5
10133 });
10134 </code></pre>
10135          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10136          * @param {Object} options (optional) Object literal with any of the Fx config options
10137          * @return {Roo.Element} The Element
10138          */
10139     slideIn : function(anchor, o){
10140         var el = this.getFxEl();
10141         o = o || {};
10142
10143         el.queueFx(o, function(){
10144
10145             anchor = anchor || "t";
10146
10147             // fix display to visibility
10148             this.fixDisplay();
10149
10150             // restore values after effect
10151             var r = this.getFxRestore();
10152             var b = this.getBox();
10153             // fixed size for slide
10154             this.setSize(b);
10155
10156             // wrap if needed
10157             var wrap = this.fxWrap(r.pos, o, "hidden");
10158
10159             var st = this.dom.style;
10160             st.visibility = "visible";
10161             st.position = "absolute";
10162
10163             // clear out temp styles after slide and unwrap
10164             var after = function(){
10165                 el.fxUnwrap(wrap, r.pos, o);
10166                 st.width = r.width;
10167                 st.height = r.height;
10168                 el.afterFx(o);
10169             };
10170             // time to calc the positions
10171             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10172
10173             switch(anchor.toLowerCase()){
10174                 case "t":
10175                     wrap.setSize(b.width, 0);
10176                     st.left = st.bottom = "0";
10177                     a = {height: bh};
10178                 break;
10179                 case "l":
10180                     wrap.setSize(0, b.height);
10181                     st.right = st.top = "0";
10182                     a = {width: bw};
10183                 break;
10184                 case "r":
10185                     wrap.setSize(0, b.height);
10186                     wrap.setX(b.right);
10187                     st.left = st.top = "0";
10188                     a = {width: bw, points: pt};
10189                 break;
10190                 case "b":
10191                     wrap.setSize(b.width, 0);
10192                     wrap.setY(b.bottom);
10193                     st.left = st.top = "0";
10194                     a = {height: bh, points: pt};
10195                 break;
10196                 case "tl":
10197                     wrap.setSize(0, 0);
10198                     st.right = st.bottom = "0";
10199                     a = {width: bw, height: bh};
10200                 break;
10201                 case "bl":
10202                     wrap.setSize(0, 0);
10203                     wrap.setY(b.y+b.height);
10204                     st.right = st.top = "0";
10205                     a = {width: bw, height: bh, points: pt};
10206                 break;
10207                 case "br":
10208                     wrap.setSize(0, 0);
10209                     wrap.setXY([b.right, b.bottom]);
10210                     st.left = st.top = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213                 case "tr":
10214                     wrap.setSize(0, 0);
10215                     wrap.setX(b.x+b.width);
10216                     st.left = st.bottom = "0";
10217                     a = {width: bw, height: bh, points: pt};
10218                 break;
10219             }
10220             this.dom.style.visibility = "visible";
10221             wrap.show();
10222
10223             arguments.callee.anim = wrap.fxanim(a,
10224                 o,
10225                 'motion',
10226                 .5,
10227                 'easeOut', after);
10228         });
10229         return this;
10230     },
10231     
10232         /**
10233          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10234          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10235          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10236          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10237          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10238          * Usage:
10239          *<pre><code>
10240 // default: slide the element out to the top
10241 el.slideOut();
10242
10243 // custom: slide the element out to the right with a 2-second duration
10244 el.slideOut('r', { duration: 2 });
10245
10246 // common config options shown with default values
10247 el.slideOut('t', {
10248     easing: 'easeOut',
10249     duration: .5,
10250     remove: false,
10251     useDisplay: false
10252 });
10253 </code></pre>
10254          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10255          * @param {Object} options (optional) Object literal with any of the Fx config options
10256          * @return {Roo.Element} The Element
10257          */
10258     slideOut : function(anchor, o){
10259         var el = this.getFxEl();
10260         o = o || {};
10261
10262         el.queueFx(o, function(){
10263
10264             anchor = anchor || "t";
10265
10266             // restore values after effect
10267             var r = this.getFxRestore();
10268             
10269             var b = this.getBox();
10270             // fixed size for slide
10271             this.setSize(b);
10272
10273             // wrap if needed
10274             var wrap = this.fxWrap(r.pos, o, "visible");
10275
10276             var st = this.dom.style;
10277             st.visibility = "visible";
10278             st.position = "absolute";
10279
10280             wrap.setSize(b);
10281
10282             var after = function(){
10283                 if(o.useDisplay){
10284                     el.setDisplayed(false);
10285                 }else{
10286                     el.hide();
10287                 }
10288
10289                 el.fxUnwrap(wrap, r.pos, o);
10290
10291                 st.width = r.width;
10292                 st.height = r.height;
10293
10294                 el.afterFx(o);
10295             };
10296
10297             var a, zero = {to: 0};
10298             switch(anchor.toLowerCase()){
10299                 case "t":
10300                     st.left = st.bottom = "0";
10301                     a = {height: zero};
10302                 break;
10303                 case "l":
10304                     st.right = st.top = "0";
10305                     a = {width: zero};
10306                 break;
10307                 case "r":
10308                     st.left = st.top = "0";
10309                     a = {width: zero, points: {to:[b.right, b.y]}};
10310                 break;
10311                 case "b":
10312                     st.left = st.top = "0";
10313                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10314                 break;
10315                 case "tl":
10316                     st.right = st.bottom = "0";
10317                     a = {width: zero, height: zero};
10318                 break;
10319                 case "bl":
10320                     st.right = st.top = "0";
10321                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10322                 break;
10323                 case "br":
10324                     st.left = st.top = "0";
10325                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10326                 break;
10327                 case "tr":
10328                     st.left = st.bottom = "0";
10329                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10330                 break;
10331             }
10332
10333             arguments.callee.anim = wrap.fxanim(a,
10334                 o,
10335                 'motion',
10336                 .5,
10337                 "easeOut", after);
10338         });
10339         return this;
10340     },
10341
10342         /**
10343          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10344          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10345          * The element must be removed from the DOM using the 'remove' config option if desired.
10346          * Usage:
10347          *<pre><code>
10348 // default
10349 el.puff();
10350
10351 // common config options shown with default values
10352 el.puff({
10353     easing: 'easeOut',
10354     duration: .5,
10355     remove: false,
10356     useDisplay: false
10357 });
10358 </code></pre>
10359          * @param {Object} options (optional) Object literal with any of the Fx config options
10360          * @return {Roo.Element} The Element
10361          */
10362     puff : function(o){
10363         var el = this.getFxEl();
10364         o = o || {};
10365
10366         el.queueFx(o, function(){
10367             this.clearOpacity();
10368             this.show();
10369
10370             // restore values after effect
10371             var r = this.getFxRestore();
10372             var st = this.dom.style;
10373
10374             var after = function(){
10375                 if(o.useDisplay){
10376                     el.setDisplayed(false);
10377                 }else{
10378                     el.hide();
10379                 }
10380
10381                 el.clearOpacity();
10382
10383                 el.setPositioning(r.pos);
10384                 st.width = r.width;
10385                 st.height = r.height;
10386                 st.fontSize = '';
10387                 el.afterFx(o);
10388             };
10389
10390             var width = this.getWidth();
10391             var height = this.getHeight();
10392
10393             arguments.callee.anim = this.fxanim({
10394                     width : {to: this.adjustWidth(width * 2)},
10395                     height : {to: this.adjustHeight(height * 2)},
10396                     points : {by: [-(width * .5), -(height * .5)]},
10397                     opacity : {to: 0},
10398                     fontSize: {to:200, unit: "%"}
10399                 },
10400                 o,
10401                 'motion',
10402                 .5,
10403                 "easeOut", after);
10404         });
10405         return this;
10406     },
10407
10408         /**
10409          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10410          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10411          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10412          * Usage:
10413          *<pre><code>
10414 // default
10415 el.switchOff();
10416
10417 // all config options shown with default values
10418 el.switchOff({
10419     easing: 'easeIn',
10420     duration: .3,
10421     remove: false,
10422     useDisplay: false
10423 });
10424 </code></pre>
10425          * @param {Object} options (optional) Object literal with any of the Fx config options
10426          * @return {Roo.Element} The Element
10427          */
10428     switchOff : function(o){
10429         var el = this.getFxEl();
10430         o = o || {};
10431
10432         el.queueFx(o, function(){
10433             this.clearOpacity();
10434             this.clip();
10435
10436             // restore values after effect
10437             var r = this.getFxRestore();
10438             var st = this.dom.style;
10439
10440             var after = function(){
10441                 if(o.useDisplay){
10442                     el.setDisplayed(false);
10443                 }else{
10444                     el.hide();
10445                 }
10446
10447                 el.clearOpacity();
10448                 el.setPositioning(r.pos);
10449                 st.width = r.width;
10450                 st.height = r.height;
10451
10452                 el.afterFx(o);
10453             };
10454
10455             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10456                 this.clearOpacity();
10457                 (function(){
10458                     this.fxanim({
10459                         height:{to:1},
10460                         points:{by:[0, this.getHeight() * .5]}
10461                     }, o, 'motion', 0.3, 'easeIn', after);
10462                 }).defer(100, this);
10463             });
10464         });
10465         return this;
10466     },
10467
10468     /**
10469      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10470      * changed using the "attr" config option) and then fading back to the original color. If no original
10471      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10472      * Usage:
10473 <pre><code>
10474 // default: highlight background to yellow
10475 el.highlight();
10476
10477 // custom: highlight foreground text to blue for 2 seconds
10478 el.highlight("0000ff", { attr: 'color', duration: 2 });
10479
10480 // common config options shown with default values
10481 el.highlight("ffff9c", {
10482     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10483     endColor: (current color) or "ffffff",
10484     easing: 'easeIn',
10485     duration: 1
10486 });
10487 </code></pre>
10488      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10489      * @param {Object} options (optional) Object literal with any of the Fx config options
10490      * @return {Roo.Element} The Element
10491      */ 
10492     highlight : function(color, o){
10493         var el = this.getFxEl();
10494         o = o || {};
10495
10496         el.queueFx(o, function(){
10497             color = color || "ffff9c";
10498             attr = o.attr || "backgroundColor";
10499
10500             this.clearOpacity();
10501             this.show();
10502
10503             var origColor = this.getColor(attr);
10504             var restoreColor = this.dom.style[attr];
10505             endColor = (o.endColor || origColor) || "ffffff";
10506
10507             var after = function(){
10508                 el.dom.style[attr] = restoreColor;
10509                 el.afterFx(o);
10510             };
10511
10512             var a = {};
10513             a[attr] = {from: color, to: endColor};
10514             arguments.callee.anim = this.fxanim(a,
10515                 o,
10516                 'color',
10517                 1,
10518                 'easeIn', after);
10519         });
10520         return this;
10521     },
10522
10523    /**
10524     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10525     * Usage:
10526 <pre><code>
10527 // default: a single light blue ripple
10528 el.frame();
10529
10530 // custom: 3 red ripples lasting 3 seconds total
10531 el.frame("ff0000", 3, { duration: 3 });
10532
10533 // common config options shown with default values
10534 el.frame("C3DAF9", 1, {
10535     duration: 1 //duration of entire animation (not each individual ripple)
10536     // Note: Easing is not configurable and will be ignored if included
10537 });
10538 </code></pre>
10539     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10540     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10541     * @param {Object} options (optional) Object literal with any of the Fx config options
10542     * @return {Roo.Element} The Element
10543     */
10544     frame : function(color, count, o){
10545         var el = this.getFxEl();
10546         o = o || {};
10547
10548         el.queueFx(o, function(){
10549             color = color || "#C3DAF9";
10550             if(color.length == 6){
10551                 color = "#" + color;
10552             }
10553             count = count || 1;
10554             duration = o.duration || 1;
10555             this.show();
10556
10557             var b = this.getBox();
10558             var animFn = function(){
10559                 var proxy = this.createProxy({
10560
10561                      style:{
10562                         visbility:"hidden",
10563                         position:"absolute",
10564                         "z-index":"35000", // yee haw
10565                         border:"0px solid " + color
10566                      }
10567                   });
10568                 var scale = Roo.isBorderBox ? 2 : 1;
10569                 proxy.animate({
10570                     top:{from:b.y, to:b.y - 20},
10571                     left:{from:b.x, to:b.x - 20},
10572                     borderWidth:{from:0, to:10},
10573                     opacity:{from:1, to:0},
10574                     height:{from:b.height, to:(b.height + (20*scale))},
10575                     width:{from:b.width, to:(b.width + (20*scale))}
10576                 }, duration, function(){
10577                     proxy.remove();
10578                 });
10579                 if(--count > 0){
10580                      animFn.defer((duration/2)*1000, this);
10581                 }else{
10582                     el.afterFx(o);
10583                 }
10584             };
10585             animFn.call(this);
10586         });
10587         return this;
10588     },
10589
10590    /**
10591     * Creates a pause before any subsequent queued effects begin.  If there are
10592     * no effects queued after the pause it will have no effect.
10593     * Usage:
10594 <pre><code>
10595 el.pause(1);
10596 </code></pre>
10597     * @param {Number} seconds The length of time to pause (in seconds)
10598     * @return {Roo.Element} The Element
10599     */
10600     pause : function(seconds){
10601         var el = this.getFxEl();
10602         var o = {};
10603
10604         el.queueFx(o, function(){
10605             setTimeout(function(){
10606                 el.afterFx(o);
10607             }, seconds * 1000);
10608         });
10609         return this;
10610     },
10611
10612    /**
10613     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10614     * using the "endOpacity" config option.
10615     * Usage:
10616 <pre><code>
10617 // default: fade in from opacity 0 to 100%
10618 el.fadeIn();
10619
10620 // custom: fade in from opacity 0 to 75% over 2 seconds
10621 el.fadeIn({ endOpacity: .75, duration: 2});
10622
10623 // common config options shown with default values
10624 el.fadeIn({
10625     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10626     easing: 'easeOut',
10627     duration: .5
10628 });
10629 </code></pre>
10630     * @param {Object} options (optional) Object literal with any of the Fx config options
10631     * @return {Roo.Element} The Element
10632     */
10633     fadeIn : function(o){
10634         var el = this.getFxEl();
10635         o = o || {};
10636         el.queueFx(o, function(){
10637             this.setOpacity(0);
10638             this.fixDisplay();
10639             this.dom.style.visibility = 'visible';
10640             var to = o.endOpacity || 1;
10641             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10642                 o, null, .5, "easeOut", function(){
10643                 if(to == 1){
10644                     this.clearOpacity();
10645                 }
10646                 el.afterFx(o);
10647             });
10648         });
10649         return this;
10650     },
10651
10652    /**
10653     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10654     * using the "endOpacity" config option.
10655     * Usage:
10656 <pre><code>
10657 // default: fade out from the element's current opacity to 0
10658 el.fadeOut();
10659
10660 // custom: fade out from the element's current opacity to 25% over 2 seconds
10661 el.fadeOut({ endOpacity: .25, duration: 2});
10662
10663 // common config options shown with default values
10664 el.fadeOut({
10665     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10666     easing: 'easeOut',
10667     duration: .5
10668     remove: false,
10669     useDisplay: false
10670 });
10671 </code></pre>
10672     * @param {Object} options (optional) Object literal with any of the Fx config options
10673     * @return {Roo.Element} The Element
10674     */
10675     fadeOut : function(o){
10676         var el = this.getFxEl();
10677         o = o || {};
10678         el.queueFx(o, function(){
10679             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10680                 o, null, .5, "easeOut", function(){
10681                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10682                      this.dom.style.display = "none";
10683                 }else{
10684                      this.dom.style.visibility = "hidden";
10685                 }
10686                 this.clearOpacity();
10687                 el.afterFx(o);
10688             });
10689         });
10690         return this;
10691     },
10692
10693    /**
10694     * Animates the transition of an element's dimensions from a starting height/width
10695     * to an ending height/width.
10696     * Usage:
10697 <pre><code>
10698 // change height and width to 100x100 pixels
10699 el.scale(100, 100);
10700
10701 // common config options shown with default values.  The height and width will default to
10702 // the element's existing values if passed as null.
10703 el.scale(
10704     [element's width],
10705     [element's height], {
10706     easing: 'easeOut',
10707     duration: .35
10708 });
10709 </code></pre>
10710     * @param {Number} width  The new width (pass undefined to keep the original width)
10711     * @param {Number} height  The new height (pass undefined to keep the original height)
10712     * @param {Object} options (optional) Object literal with any of the Fx config options
10713     * @return {Roo.Element} The Element
10714     */
10715     scale : function(w, h, o){
10716         this.shift(Roo.apply({}, o, {
10717             width: w,
10718             height: h
10719         }));
10720         return this;
10721     },
10722
10723    /**
10724     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10725     * Any of these properties not specified in the config object will not be changed.  This effect 
10726     * requires that at least one new dimension, position or opacity setting must be passed in on
10727     * the config object in order for the function to have any effect.
10728     * Usage:
10729 <pre><code>
10730 // slide the element horizontally to x position 200 while changing the height and opacity
10731 el.shift({ x: 200, height: 50, opacity: .8 });
10732
10733 // common config options shown with default values.
10734 el.shift({
10735     width: [element's width],
10736     height: [element's height],
10737     x: [element's x position],
10738     y: [element's y position],
10739     opacity: [element's opacity],
10740     easing: 'easeOut',
10741     duration: .35
10742 });
10743 </code></pre>
10744     * @param {Object} options  Object literal with any of the Fx config options
10745     * @return {Roo.Element} The Element
10746     */
10747     shift : function(o){
10748         var el = this.getFxEl();
10749         o = o || {};
10750         el.queueFx(o, function(){
10751             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10752             if(w !== undefined){
10753                 a.width = {to: this.adjustWidth(w)};
10754             }
10755             if(h !== undefined){
10756                 a.height = {to: this.adjustHeight(h)};
10757             }
10758             if(x !== undefined || y !== undefined){
10759                 a.points = {to: [
10760                     x !== undefined ? x : this.getX(),
10761                     y !== undefined ? y : this.getY()
10762                 ]};
10763             }
10764             if(op !== undefined){
10765                 a.opacity = {to: op};
10766             }
10767             if(o.xy !== undefined){
10768                 a.points = {to: o.xy};
10769             }
10770             arguments.callee.anim = this.fxanim(a,
10771                 o, 'motion', .35, "easeOut", function(){
10772                 el.afterFx(o);
10773             });
10774         });
10775         return this;
10776     },
10777
10778         /**
10779          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10780          * ending point of the effect.
10781          * Usage:
10782          *<pre><code>
10783 // default: slide the element downward while fading out
10784 el.ghost();
10785
10786 // custom: slide the element out to the right with a 2-second duration
10787 el.ghost('r', { duration: 2 });
10788
10789 // common config options shown with default values
10790 el.ghost('b', {
10791     easing: 'easeOut',
10792     duration: .5
10793     remove: false,
10794     useDisplay: false
10795 });
10796 </code></pre>
10797          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10798          * @param {Object} options (optional) Object literal with any of the Fx config options
10799          * @return {Roo.Element} The Element
10800          */
10801     ghost : function(anchor, o){
10802         var el = this.getFxEl();
10803         o = o || {};
10804
10805         el.queueFx(o, function(){
10806             anchor = anchor || "b";
10807
10808             // restore values after effect
10809             var r = this.getFxRestore();
10810             var w = this.getWidth(),
10811                 h = this.getHeight();
10812
10813             var st = this.dom.style;
10814
10815             var after = function(){
10816                 if(o.useDisplay){
10817                     el.setDisplayed(false);
10818                 }else{
10819                     el.hide();
10820                 }
10821
10822                 el.clearOpacity();
10823                 el.setPositioning(r.pos);
10824                 st.width = r.width;
10825                 st.height = r.height;
10826
10827                 el.afterFx(o);
10828             };
10829
10830             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10831             switch(anchor.toLowerCase()){
10832                 case "t":
10833                     pt.by = [0, -h];
10834                 break;
10835                 case "l":
10836                     pt.by = [-w, 0];
10837                 break;
10838                 case "r":
10839                     pt.by = [w, 0];
10840                 break;
10841                 case "b":
10842                     pt.by = [0, h];
10843                 break;
10844                 case "tl":
10845                     pt.by = [-w, -h];
10846                 break;
10847                 case "bl":
10848                     pt.by = [-w, h];
10849                 break;
10850                 case "br":
10851                     pt.by = [w, h];
10852                 break;
10853                 case "tr":
10854                     pt.by = [w, -h];
10855                 break;
10856             }
10857
10858             arguments.callee.anim = this.fxanim(a,
10859                 o,
10860                 'motion',
10861                 .5,
10862                 "easeOut", after);
10863         });
10864         return this;
10865     },
10866
10867         /**
10868          * Ensures that all effects queued after syncFx is called on the element are
10869          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10870          * @return {Roo.Element} The Element
10871          */
10872     syncFx : function(){
10873         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10874             block : false,
10875             concurrent : true,
10876             stopFx : false
10877         });
10878         return this;
10879     },
10880
10881         /**
10882          * Ensures that all effects queued after sequenceFx is called on the element are
10883          * run in sequence.  This is the opposite of {@link #syncFx}.
10884          * @return {Roo.Element} The Element
10885          */
10886     sequenceFx : function(){
10887         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10888             block : false,
10889             concurrent : false,
10890             stopFx : false
10891         });
10892         return this;
10893     },
10894
10895         /* @private */
10896     nextFx : function(){
10897         var ef = this.fxQueue[0];
10898         if(ef){
10899             ef.call(this);
10900         }
10901     },
10902
10903         /**
10904          * Returns true if the element has any effects actively running or queued, else returns false.
10905          * @return {Boolean} True if element has active effects, else false
10906          */
10907     hasActiveFx : function(){
10908         return this.fxQueue && this.fxQueue[0];
10909     },
10910
10911         /**
10912          * Stops any running effects and clears the element's internal effects queue if it contains
10913          * any additional effects that haven't started yet.
10914          * @return {Roo.Element} The Element
10915          */
10916     stopFx : function(){
10917         if(this.hasActiveFx()){
10918             var cur = this.fxQueue[0];
10919             if(cur && cur.anim && cur.anim.isAnimated()){
10920                 this.fxQueue = [cur]; // clear out others
10921                 cur.anim.stop(true);
10922             }
10923         }
10924         return this;
10925     },
10926
10927         /* @private */
10928     beforeFx : function(o){
10929         if(this.hasActiveFx() && !o.concurrent){
10930            if(o.stopFx){
10931                this.stopFx();
10932                return true;
10933            }
10934            return false;
10935         }
10936         return true;
10937     },
10938
10939         /**
10940          * Returns true if the element is currently blocking so that no other effect can be queued
10941          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10942          * used to ensure that an effect initiated by a user action runs to completion prior to the
10943          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10944          * @return {Boolean} True if blocking, else false
10945          */
10946     hasFxBlock : function(){
10947         var q = this.fxQueue;
10948         return q && q[0] && q[0].block;
10949     },
10950
10951         /* @private */
10952     queueFx : function(o, fn){
10953         if(!this.fxQueue){
10954             this.fxQueue = [];
10955         }
10956         if(!this.hasFxBlock()){
10957             Roo.applyIf(o, this.fxDefaults);
10958             if(!o.concurrent){
10959                 var run = this.beforeFx(o);
10960                 fn.block = o.block;
10961                 this.fxQueue.push(fn);
10962                 if(run){
10963                     this.nextFx();
10964                 }
10965             }else{
10966                 fn.call(this);
10967             }
10968         }
10969         return this;
10970     },
10971
10972         /* @private */
10973     fxWrap : function(pos, o, vis){
10974         var wrap;
10975         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10976             var wrapXY;
10977             if(o.fixPosition){
10978                 wrapXY = this.getXY();
10979             }
10980             var div = document.createElement("div");
10981             div.style.visibility = vis;
10982             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10983             wrap.setPositioning(pos);
10984             if(wrap.getStyle("position") == "static"){
10985                 wrap.position("relative");
10986             }
10987             this.clearPositioning('auto');
10988             wrap.clip();
10989             wrap.dom.appendChild(this.dom);
10990             if(wrapXY){
10991                 wrap.setXY(wrapXY);
10992             }
10993         }
10994         return wrap;
10995     },
10996
10997         /* @private */
10998     fxUnwrap : function(wrap, pos, o){
10999         this.clearPositioning();
11000         this.setPositioning(pos);
11001         if(!o.wrap){
11002             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11003             wrap.remove();
11004         }
11005     },
11006
11007         /* @private */
11008     getFxRestore : function(){
11009         var st = this.dom.style;
11010         return {pos: this.getPositioning(), width: st.width, height : st.height};
11011     },
11012
11013         /* @private */
11014     afterFx : function(o){
11015         if(o.afterStyle){
11016             this.applyStyles(o.afterStyle);
11017         }
11018         if(o.afterCls){
11019             this.addClass(o.afterCls);
11020         }
11021         if(o.remove === true){
11022             this.remove();
11023         }
11024         Roo.callback(o.callback, o.scope, [this]);
11025         if(!o.concurrent){
11026             this.fxQueue.shift();
11027             this.nextFx();
11028         }
11029     },
11030
11031         /* @private */
11032     getFxEl : function(){ // support for composite element fx
11033         return Roo.get(this.dom);
11034     },
11035
11036         /* @private */
11037     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11038         animType = animType || 'run';
11039         opt = opt || {};
11040         var anim = Roo.lib.Anim[animType](
11041             this.dom, args,
11042             (opt.duration || defaultDur) || .35,
11043             (opt.easing || defaultEase) || 'easeOut',
11044             function(){
11045                 Roo.callback(cb, this);
11046             },
11047             this
11048         );
11049         opt.anim = anim;
11050         return anim;
11051     }
11052 };
11053
11054 // backwords compat
11055 Roo.Fx.resize = Roo.Fx.scale;
11056
11057 //When included, Roo.Fx is automatically applied to Element so that all basic
11058 //effects are available directly via the Element API
11059 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11060  * Based on:
11061  * Ext JS Library 1.1.1
11062  * Copyright(c) 2006-2007, Ext JS, LLC.
11063  *
11064  * Originally Released Under LGPL - original licence link has changed is not relivant.
11065  *
11066  * Fork - LGPL
11067  * <script type="text/javascript">
11068  */
11069
11070
11071 /**
11072  * @class Roo.CompositeElement
11073  * Standard composite class. Creates a Roo.Element for every element in the collection.
11074  * <br><br>
11075  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11076  * actions will be performed on all the elements in this collection.</b>
11077  * <br><br>
11078  * All methods return <i>this</i> and can be chained.
11079  <pre><code>
11080  var els = Roo.select("#some-el div.some-class", true);
11081  // or select directly from an existing element
11082  var el = Roo.get('some-el');
11083  el.select('div.some-class', true);
11084
11085  els.setWidth(100); // all elements become 100 width
11086  els.hide(true); // all elements fade out and hide
11087  // or
11088  els.setWidth(100).hide(true);
11089  </code></pre>
11090  */
11091 Roo.CompositeElement = function(els){
11092     this.elements = [];
11093     this.addElements(els);
11094 };
11095 Roo.CompositeElement.prototype = {
11096     isComposite: true,
11097     addElements : function(els){
11098         if(!els) {
11099             return this;
11100         }
11101         if(typeof els == "string"){
11102             els = Roo.Element.selectorFunction(els);
11103         }
11104         var yels = this.elements;
11105         var index = yels.length-1;
11106         for(var i = 0, len = els.length; i < len; i++) {
11107                 yels[++index] = Roo.get(els[i]);
11108         }
11109         return this;
11110     },
11111
11112     /**
11113     * Clears this composite and adds the elements returned by the passed selector.
11114     * @param {String/Array} els A string CSS selector, an array of elements or an element
11115     * @return {CompositeElement} this
11116     */
11117     fill : function(els){
11118         this.elements = [];
11119         this.add(els);
11120         return this;
11121     },
11122
11123     /**
11124     * Filters this composite to only elements that match the passed selector.
11125     * @param {String} selector A string CSS selector
11126     * @param {Boolean} inverse return inverse filter (not matches)
11127     * @return {CompositeElement} this
11128     */
11129     filter : function(selector, inverse){
11130         var els = [];
11131         inverse = inverse || false;
11132         this.each(function(el){
11133             var match = inverse ? !el.is(selector) : el.is(selector);
11134             if(match){
11135                 els[els.length] = el.dom;
11136             }
11137         });
11138         this.fill(els);
11139         return this;
11140     },
11141
11142     invoke : function(fn, args){
11143         var els = this.elements;
11144         for(var i = 0, len = els.length; i < len; i++) {
11145                 Roo.Element.prototype[fn].apply(els[i], args);
11146         }
11147         return this;
11148     },
11149     /**
11150     * Adds elements to this composite.
11151     * @param {String/Array} els A string CSS selector, an array of elements or an element
11152     * @return {CompositeElement} this
11153     */
11154     add : function(els){
11155         if(typeof els == "string"){
11156             this.addElements(Roo.Element.selectorFunction(els));
11157         }else if(els.length !== undefined){
11158             this.addElements(els);
11159         }else{
11160             this.addElements([els]);
11161         }
11162         return this;
11163     },
11164     /**
11165     * Calls the passed function passing (el, this, index) for each element in this composite.
11166     * @param {Function} fn The function to call
11167     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11168     * @return {CompositeElement} this
11169     */
11170     each : function(fn, scope){
11171         var els = this.elements;
11172         for(var i = 0, len = els.length; i < len; i++){
11173             if(fn.call(scope || els[i], els[i], this, i) === false) {
11174                 break;
11175             }
11176         }
11177         return this;
11178     },
11179
11180     /**
11181      * Returns the Element object at the specified index
11182      * @param {Number} index
11183      * @return {Roo.Element}
11184      */
11185     item : function(index){
11186         return this.elements[index] || null;
11187     },
11188
11189     /**
11190      * Returns the first Element
11191      * @return {Roo.Element}
11192      */
11193     first : function(){
11194         return this.item(0);
11195     },
11196
11197     /**
11198      * Returns the last Element
11199      * @return {Roo.Element}
11200      */
11201     last : function(){
11202         return this.item(this.elements.length-1);
11203     },
11204
11205     /**
11206      * Returns the number of elements in this composite
11207      * @return Number
11208      */
11209     getCount : function(){
11210         return this.elements.length;
11211     },
11212
11213     /**
11214      * Returns true if this composite contains the passed element
11215      * @return Boolean
11216      */
11217     contains : function(el){
11218         return this.indexOf(el) !== -1;
11219     },
11220
11221     /**
11222      * Returns true if this composite contains the passed element
11223      * @return Boolean
11224      */
11225     indexOf : function(el){
11226         return this.elements.indexOf(Roo.get(el));
11227     },
11228
11229
11230     /**
11231     * Removes the specified element(s).
11232     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11233     * or an array of any of those.
11234     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11235     * @return {CompositeElement} this
11236     */
11237     removeElement : function(el, removeDom){
11238         if(el instanceof Array){
11239             for(var i = 0, len = el.length; i < len; i++){
11240                 this.removeElement(el[i]);
11241             }
11242             return this;
11243         }
11244         var index = typeof el == 'number' ? el : this.indexOf(el);
11245         if(index !== -1){
11246             if(removeDom){
11247                 var d = this.elements[index];
11248                 if(d.dom){
11249                     d.remove();
11250                 }else{
11251                     d.parentNode.removeChild(d);
11252                 }
11253             }
11254             this.elements.splice(index, 1);
11255         }
11256         return this;
11257     },
11258
11259     /**
11260     * Replaces the specified element with the passed element.
11261     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11262     * to replace.
11263     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11264     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11265     * @return {CompositeElement} this
11266     */
11267     replaceElement : function(el, replacement, domReplace){
11268         var index = typeof el == 'number' ? el : this.indexOf(el);
11269         if(index !== -1){
11270             if(domReplace){
11271                 this.elements[index].replaceWith(replacement);
11272             }else{
11273                 this.elements.splice(index, 1, Roo.get(replacement))
11274             }
11275         }
11276         return this;
11277     },
11278
11279     /**
11280      * Removes all elements.
11281      */
11282     clear : function(){
11283         this.elements = [];
11284     }
11285 };
11286 (function(){
11287     Roo.CompositeElement.createCall = function(proto, fnName){
11288         if(!proto[fnName]){
11289             proto[fnName] = function(){
11290                 return this.invoke(fnName, arguments);
11291             };
11292         }
11293     };
11294     for(var fnName in Roo.Element.prototype){
11295         if(typeof Roo.Element.prototype[fnName] == "function"){
11296             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11297         }
11298     };
11299 })();
11300 /*
11301  * Based on:
11302  * Ext JS Library 1.1.1
11303  * Copyright(c) 2006-2007, Ext JS, LLC.
11304  *
11305  * Originally Released Under LGPL - original licence link has changed is not relivant.
11306  *
11307  * Fork - LGPL
11308  * <script type="text/javascript">
11309  */
11310
11311 /**
11312  * @class Roo.CompositeElementLite
11313  * @extends Roo.CompositeElement
11314  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11315  <pre><code>
11316  var els = Roo.select("#some-el div.some-class");
11317  // or select directly from an existing element
11318  var el = Roo.get('some-el');
11319  el.select('div.some-class');
11320
11321  els.setWidth(100); // all elements become 100 width
11322  els.hide(true); // all elements fade out and hide
11323  // or
11324  els.setWidth(100).hide(true);
11325  </code></pre><br><br>
11326  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11327  * actions will be performed on all the elements in this collection.</b>
11328  */
11329 Roo.CompositeElementLite = function(els){
11330     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11331     this.el = new Roo.Element.Flyweight();
11332 };
11333 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11334     addElements : function(els){
11335         if(els){
11336             if(els instanceof Array){
11337                 this.elements = this.elements.concat(els);
11338             }else{
11339                 var yels = this.elements;
11340                 var index = yels.length-1;
11341                 for(var i = 0, len = els.length; i < len; i++) {
11342                     yels[++index] = els[i];
11343                 }
11344             }
11345         }
11346         return this;
11347     },
11348     invoke : function(fn, args){
11349         var els = this.elements;
11350         var el = this.el;
11351         for(var i = 0, len = els.length; i < len; i++) {
11352             el.dom = els[i];
11353                 Roo.Element.prototype[fn].apply(el, args);
11354         }
11355         return this;
11356     },
11357     /**
11358      * Returns a flyweight Element of the dom element object at the specified index
11359      * @param {Number} index
11360      * @return {Roo.Element}
11361      */
11362     item : function(index){
11363         if(!this.elements[index]){
11364             return null;
11365         }
11366         this.el.dom = this.elements[index];
11367         return this.el;
11368     },
11369
11370     // fixes scope with flyweight
11371     addListener : function(eventName, handler, scope, opt){
11372         var els = this.elements;
11373         for(var i = 0, len = els.length; i < len; i++) {
11374             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11375         }
11376         return this;
11377     },
11378
11379     /**
11380     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11381     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11382     * a reference to the dom node, use el.dom.</b>
11383     * @param {Function} fn The function to call
11384     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11385     * @return {CompositeElement} this
11386     */
11387     each : function(fn, scope){
11388         var els = this.elements;
11389         var el = this.el;
11390         for(var i = 0, len = els.length; i < len; i++){
11391             el.dom = els[i];
11392                 if(fn.call(scope || el, el, this, i) === false){
11393                 break;
11394             }
11395         }
11396         return this;
11397     },
11398
11399     indexOf : function(el){
11400         return this.elements.indexOf(Roo.getDom(el));
11401     },
11402
11403     replaceElement : function(el, replacement, domReplace){
11404         var index = typeof el == 'number' ? el : this.indexOf(el);
11405         if(index !== -1){
11406             replacement = Roo.getDom(replacement);
11407             if(domReplace){
11408                 var d = this.elements[index];
11409                 d.parentNode.insertBefore(replacement, d);
11410                 d.parentNode.removeChild(d);
11411             }
11412             this.elements.splice(index, 1, replacement);
11413         }
11414         return this;
11415     }
11416 });
11417 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11418
11419 /*
11420  * Based on:
11421  * Ext JS Library 1.1.1
11422  * Copyright(c) 2006-2007, Ext JS, LLC.
11423  *
11424  * Originally Released Under LGPL - original licence link has changed is not relivant.
11425  *
11426  * Fork - LGPL
11427  * <script type="text/javascript">
11428  */
11429
11430  
11431
11432 /**
11433  * @class Roo.data.Connection
11434  * @extends Roo.util.Observable
11435  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11436  * either to a configured URL, or to a URL specified at request time.<br><br>
11437  * <p>
11438  * Requests made by this class are asynchronous, and will return immediately. No data from
11439  * the server will be available to the statement immediately following the {@link #request} call.
11440  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11441  * <p>
11442  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11443  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11444  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11445  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11446  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11447  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11448  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11449  * standard DOM methods.
11450  * @constructor
11451  * @param {Object} config a configuration object.
11452  */
11453 Roo.data.Connection = function(config){
11454     Roo.apply(this, config);
11455     this.addEvents({
11456         /**
11457          * @event beforerequest
11458          * Fires before a network request is made to retrieve a data object.
11459          * @param {Connection} conn This Connection object.
11460          * @param {Object} options The options config object passed to the {@link #request} method.
11461          */
11462         "beforerequest" : true,
11463         /**
11464          * @event requestcomplete
11465          * Fires if the request was successfully completed.
11466          * @param {Connection} conn This Connection object.
11467          * @param {Object} response The XHR object containing the response data.
11468          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11469          * @param {Object} options The options config object passed to the {@link #request} method.
11470          */
11471         "requestcomplete" : true,
11472         /**
11473          * @event requestexception
11474          * Fires if an error HTTP status was returned from the server.
11475          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11476          * @param {Connection} conn This Connection object.
11477          * @param {Object} response The XHR object containing the response data.
11478          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11479          * @param {Object} options The options config object passed to the {@link #request} method.
11480          */
11481         "requestexception" : true
11482     });
11483     Roo.data.Connection.superclass.constructor.call(this);
11484 };
11485
11486 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11487     /**
11488      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11489      */
11490     /**
11491      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11492      * extra parameters to each request made by this object. (defaults to undefined)
11493      */
11494     /**
11495      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11496      *  to each request made by this object. (defaults to undefined)
11497      */
11498     /**
11499      * @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)
11500      */
11501     /**
11502      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11503      */
11504     timeout : 30000,
11505     /**
11506      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11507      * @type Boolean
11508      */
11509     autoAbort:false,
11510
11511     /**
11512      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11513      * @type Boolean
11514      */
11515     disableCaching: true,
11516
11517     /**
11518      * Sends an HTTP request to a remote server.
11519      * @param {Object} options An object which may contain the following properties:<ul>
11520      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11521      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11522      * request, a url encoded string or a function to call to get either.</li>
11523      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11524      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11525      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11526      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11527      * <li>options {Object} The parameter to the request call.</li>
11528      * <li>success {Boolean} True if the request succeeded.</li>
11529      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11530      * </ul></li>
11531      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11532      * The callback is passed the following parameters:<ul>
11533      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11534      * <li>options {Object} The parameter to the request call.</li>
11535      * </ul></li>
11536      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11537      * The callback is passed the following parameters:<ul>
11538      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11539      * <li>options {Object} The parameter to the request call.</li>
11540      * </ul></li>
11541      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11542      * for the callback function. Defaults to the browser window.</li>
11543      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11544      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11545      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11546      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11547      * params for the post data. Any params will be appended to the URL.</li>
11548      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11549      * </ul>
11550      * @return {Number} transactionId
11551      */
11552     request : function(o){
11553         if(this.fireEvent("beforerequest", this, o) !== false){
11554             var p = o.params;
11555
11556             if(typeof p == "function"){
11557                 p = p.call(o.scope||window, o);
11558             }
11559             if(typeof p == "object"){
11560                 p = Roo.urlEncode(o.params);
11561             }
11562             if(this.extraParams){
11563                 var extras = Roo.urlEncode(this.extraParams);
11564                 p = p ? (p + '&' + extras) : extras;
11565             }
11566
11567             var url = o.url || this.url;
11568             if(typeof url == 'function'){
11569                 url = url.call(o.scope||window, o);
11570             }
11571
11572             if(o.form){
11573                 var form = Roo.getDom(o.form);
11574                 url = url || form.action;
11575
11576                 var enctype = form.getAttribute("enctype");
11577                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11578                     return this.doFormUpload(o, p, url);
11579                 }
11580                 var f = Roo.lib.Ajax.serializeForm(form);
11581                 p = p ? (p + '&' + f) : f;
11582             }
11583
11584             var hs = o.headers;
11585             if(this.defaultHeaders){
11586                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11587                 if(!o.headers){
11588                     o.headers = hs;
11589                 }
11590             }
11591
11592             var cb = {
11593                 success: this.handleResponse,
11594                 failure: this.handleFailure,
11595                 scope: this,
11596                 argument: {options: o},
11597                 timeout : o.timeout || this.timeout
11598             };
11599
11600             var method = o.method||this.method||(p ? "POST" : "GET");
11601
11602             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11603                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11604             }
11605
11606             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11607                 if(o.autoAbort){
11608                     this.abort();
11609                 }
11610             }else if(this.autoAbort !== false){
11611                 this.abort();
11612             }
11613
11614             if((method == 'GET' && p) || o.xmlData){
11615                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11616                 p = '';
11617             }
11618             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11619             return this.transId;
11620         }else{
11621             Roo.callback(o.callback, o.scope, [o, null, null]);
11622             return null;
11623         }
11624     },
11625
11626     /**
11627      * Determine whether this object has a request outstanding.
11628      * @param {Number} transactionId (Optional) defaults to the last transaction
11629      * @return {Boolean} True if there is an outstanding request.
11630      */
11631     isLoading : function(transId){
11632         if(transId){
11633             return Roo.lib.Ajax.isCallInProgress(transId);
11634         }else{
11635             return this.transId ? true : false;
11636         }
11637     },
11638
11639     /**
11640      * Aborts any outstanding request.
11641      * @param {Number} transactionId (Optional) defaults to the last transaction
11642      */
11643     abort : function(transId){
11644         if(transId || this.isLoading()){
11645             Roo.lib.Ajax.abort(transId || this.transId);
11646         }
11647     },
11648
11649     // private
11650     handleResponse : function(response){
11651         this.transId = false;
11652         var options = response.argument.options;
11653         response.argument = options ? options.argument : null;
11654         this.fireEvent("requestcomplete", this, response, options);
11655         Roo.callback(options.success, options.scope, [response, options]);
11656         Roo.callback(options.callback, options.scope, [options, true, response]);
11657     },
11658
11659     // private
11660     handleFailure : function(response, e){
11661         this.transId = false;
11662         var options = response.argument.options;
11663         response.argument = options ? options.argument : null;
11664         this.fireEvent("requestexception", this, response, options, e);
11665         Roo.callback(options.failure, options.scope, [response, options]);
11666         Roo.callback(options.callback, options.scope, [options, false, response]);
11667     },
11668
11669     // private
11670     doFormUpload : function(o, ps, url){
11671         var id = Roo.id();
11672         var frame = document.createElement('iframe');
11673         frame.id = id;
11674         frame.name = id;
11675         frame.className = 'x-hidden';
11676         if(Roo.isIE){
11677             frame.src = Roo.SSL_SECURE_URL;
11678         }
11679         document.body.appendChild(frame);
11680
11681         if(Roo.isIE){
11682            document.frames[id].name = id;
11683         }
11684
11685         var form = Roo.getDom(o.form);
11686         form.target = id;
11687         form.method = 'POST';
11688         form.enctype = form.encoding = 'multipart/form-data';
11689         if(url){
11690             form.action = url;
11691         }
11692
11693         var hiddens, hd;
11694         if(ps){ // add dynamic params
11695             hiddens = [];
11696             ps = Roo.urlDecode(ps, false);
11697             for(var k in ps){
11698                 if(ps.hasOwnProperty(k)){
11699                     hd = document.createElement('input');
11700                     hd.type = 'hidden';
11701                     hd.name = k;
11702                     hd.value = ps[k];
11703                     form.appendChild(hd);
11704                     hiddens.push(hd);
11705                 }
11706             }
11707         }
11708
11709         function cb(){
11710             var r = {  // bogus response object
11711                 responseText : '',
11712                 responseXML : null
11713             };
11714
11715             r.argument = o ? o.argument : null;
11716
11717             try { //
11718                 var doc;
11719                 if(Roo.isIE){
11720                     doc = frame.contentWindow.document;
11721                 }else {
11722                     doc = (frame.contentDocument || window.frames[id].document);
11723                 }
11724                 if(doc && doc.body){
11725                     r.responseText = doc.body.innerHTML;
11726                 }
11727                 if(doc && doc.XMLDocument){
11728                     r.responseXML = doc.XMLDocument;
11729                 }else {
11730                     r.responseXML = doc;
11731                 }
11732             }
11733             catch(e) {
11734                 // ignore
11735             }
11736
11737             Roo.EventManager.removeListener(frame, 'load', cb, this);
11738
11739             this.fireEvent("requestcomplete", this, r, o);
11740             Roo.callback(o.success, o.scope, [r, o]);
11741             Roo.callback(o.callback, o.scope, [o, true, r]);
11742
11743             setTimeout(function(){document.body.removeChild(frame);}, 100);
11744         }
11745
11746         Roo.EventManager.on(frame, 'load', cb, this);
11747         form.submit();
11748
11749         if(hiddens){ // remove dynamic params
11750             for(var i = 0, len = hiddens.length; i < len; i++){
11751                 form.removeChild(hiddens[i]);
11752             }
11753         }
11754     }
11755 });
11756 /*
11757  * Based on:
11758  * Ext JS Library 1.1.1
11759  * Copyright(c) 2006-2007, Ext JS, LLC.
11760  *
11761  * Originally Released Under LGPL - original licence link has changed is not relivant.
11762  *
11763  * Fork - LGPL
11764  * <script type="text/javascript">
11765  */
11766  
11767 /**
11768  * Global Ajax request class.
11769  * 
11770  * @class Roo.Ajax
11771  * @extends Roo.data.Connection
11772  * @static
11773  * 
11774  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11775  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11776  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11777  * @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)
11778  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11779  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11780  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11781  */
11782 Roo.Ajax = new Roo.data.Connection({
11783     // fix up the docs
11784     /**
11785      * @scope Roo.Ajax
11786      * @type {Boolear} 
11787      */
11788     autoAbort : false,
11789
11790     /**
11791      * Serialize the passed form into a url encoded string
11792      * @scope Roo.Ajax
11793      * @param {String/HTMLElement} form
11794      * @return {String}
11795      */
11796     serializeForm : function(form){
11797         return Roo.lib.Ajax.serializeForm(form);
11798     }
11799 });/*
11800  * Based on:
11801  * Ext JS Library 1.1.1
11802  * Copyright(c) 2006-2007, Ext JS, LLC.
11803  *
11804  * Originally Released Under LGPL - original licence link has changed is not relivant.
11805  *
11806  * Fork - LGPL
11807  * <script type="text/javascript">
11808  */
11809
11810  
11811 /**
11812  * @class Roo.UpdateManager
11813  * @extends Roo.util.Observable
11814  * Provides AJAX-style update for Element object.<br><br>
11815  * Usage:<br>
11816  * <pre><code>
11817  * // Get it from a Roo.Element object
11818  * var el = Roo.get("foo");
11819  * var mgr = el.getUpdateManager();
11820  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11821  * ...
11822  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11823  * <br>
11824  * // or directly (returns the same UpdateManager instance)
11825  * var mgr = new Roo.UpdateManager("myElementId");
11826  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11827  * mgr.on("update", myFcnNeedsToKnow);
11828  * <br>
11829    // short handed call directly from the element object
11830    Roo.get("foo").load({
11831         url: "bar.php",
11832         scripts:true,
11833         params: "for=bar",
11834         text: "Loading Foo..."
11835    });
11836  * </code></pre>
11837  * @constructor
11838  * Create new UpdateManager directly.
11839  * @param {String/HTMLElement/Roo.Element} el The element to update
11840  * @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).
11841  */
11842 Roo.UpdateManager = function(el, forceNew){
11843     el = Roo.get(el);
11844     if(!forceNew && el.updateManager){
11845         return el.updateManager;
11846     }
11847     /**
11848      * The Element object
11849      * @type Roo.Element
11850      */
11851     this.el = el;
11852     /**
11853      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11854      * @type String
11855      */
11856     this.defaultUrl = null;
11857
11858     this.addEvents({
11859         /**
11860          * @event beforeupdate
11861          * Fired before an update is made, return false from your handler and the update is cancelled.
11862          * @param {Roo.Element} el
11863          * @param {String/Object/Function} url
11864          * @param {String/Object} params
11865          */
11866         "beforeupdate": true,
11867         /**
11868          * @event update
11869          * Fired after successful update is made.
11870          * @param {Roo.Element} el
11871          * @param {Object} oResponseObject The response Object
11872          */
11873         "update": true,
11874         /**
11875          * @event failure
11876          * Fired on update failure.
11877          * @param {Roo.Element} el
11878          * @param {Object} oResponseObject The response Object
11879          */
11880         "failure": true
11881     });
11882     var d = Roo.UpdateManager.defaults;
11883     /**
11884      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11885      * @type String
11886      */
11887     this.sslBlankUrl = d.sslBlankUrl;
11888     /**
11889      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11890      * @type Boolean
11891      */
11892     this.disableCaching = d.disableCaching;
11893     /**
11894      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11895      * @type String
11896      */
11897     this.indicatorText = d.indicatorText;
11898     /**
11899      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11900      * @type String
11901      */
11902     this.showLoadIndicator = d.showLoadIndicator;
11903     /**
11904      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11905      * @type Number
11906      */
11907     this.timeout = d.timeout;
11908
11909     /**
11910      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11911      * @type Boolean
11912      */
11913     this.loadScripts = d.loadScripts;
11914
11915     /**
11916      * Transaction object of current executing transaction
11917      */
11918     this.transaction = null;
11919
11920     /**
11921      * @private
11922      */
11923     this.autoRefreshProcId = null;
11924     /**
11925      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11926      * @type Function
11927      */
11928     this.refreshDelegate = this.refresh.createDelegate(this);
11929     /**
11930      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11931      * @type Function
11932      */
11933     this.updateDelegate = this.update.createDelegate(this);
11934     /**
11935      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11936      * @type Function
11937      */
11938     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11939     /**
11940      * @private
11941      */
11942     this.successDelegate = this.processSuccess.createDelegate(this);
11943     /**
11944      * @private
11945      */
11946     this.failureDelegate = this.processFailure.createDelegate(this);
11947
11948     if(!this.renderer){
11949      /**
11950       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11951       */
11952     this.renderer = new Roo.UpdateManager.BasicRenderer();
11953     }
11954     
11955     Roo.UpdateManager.superclass.constructor.call(this);
11956 };
11957
11958 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11959     /**
11960      * Get the Element this UpdateManager is bound to
11961      * @return {Roo.Element} The element
11962      */
11963     getEl : function(){
11964         return this.el;
11965     },
11966     /**
11967      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11968      * @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:
11969 <pre><code>
11970 um.update({<br/>
11971     url: "your-url.php",<br/>
11972     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11973     callback: yourFunction,<br/>
11974     scope: yourObject, //(optional scope)  <br/>
11975     discardUrl: false, <br/>
11976     nocache: false,<br/>
11977     text: "Loading...",<br/>
11978     timeout: 30,<br/>
11979     scripts: false<br/>
11980 });
11981 </code></pre>
11982      * The only required property is url. The optional properties nocache, text and scripts
11983      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11984      * @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}
11985      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11986      * @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.
11987      */
11988     update : function(url, params, callback, discardUrl){
11989         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11990             var method = this.method,
11991                 cfg;
11992             if(typeof url == "object"){ // must be config object
11993                 cfg = url;
11994                 url = cfg.url;
11995                 params = params || cfg.params;
11996                 callback = callback || cfg.callback;
11997                 discardUrl = discardUrl || cfg.discardUrl;
11998                 if(callback && cfg.scope){
11999                     callback = callback.createDelegate(cfg.scope);
12000                 }
12001                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12002                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12003                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12004                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12005                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12006             }
12007             this.showLoading();
12008             if(!discardUrl){
12009                 this.defaultUrl = url;
12010             }
12011             if(typeof url == "function"){
12012                 url = url.call(this);
12013             }
12014
12015             method = method || (params ? "POST" : "GET");
12016             if(method == "GET"){
12017                 url = this.prepareUrl(url);
12018             }
12019
12020             var o = Roo.apply(cfg ||{}, {
12021                 url : url,
12022                 params: params,
12023                 success: this.successDelegate,
12024                 failure: this.failureDelegate,
12025                 callback: undefined,
12026                 timeout: (this.timeout*1000),
12027                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12028             });
12029             Roo.log("updated manager called with timeout of " + o.timeout);
12030             this.transaction = Roo.Ajax.request(o);
12031         }
12032     },
12033
12034     /**
12035      * 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.
12036      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12037      * @param {String/HTMLElement} form The form Id or form element
12038      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12039      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12040      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12041      */
12042     formUpdate : function(form, url, reset, callback){
12043         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12044             if(typeof url == "function"){
12045                 url = url.call(this);
12046             }
12047             form = Roo.getDom(form);
12048             this.transaction = Roo.Ajax.request({
12049                 form: form,
12050                 url:url,
12051                 success: this.successDelegate,
12052                 failure: this.failureDelegate,
12053                 timeout: (this.timeout*1000),
12054                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12055             });
12056             this.showLoading.defer(1, this);
12057         }
12058     },
12059
12060     /**
12061      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12062      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12063      */
12064     refresh : function(callback){
12065         if(this.defaultUrl == null){
12066             return;
12067         }
12068         this.update(this.defaultUrl, null, callback, true);
12069     },
12070
12071     /**
12072      * Set this element to auto refresh.
12073      * @param {Number} interval How often to update (in seconds).
12074      * @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)
12075      * @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}
12076      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12077      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12078      */
12079     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12080         if(refreshNow){
12081             this.update(url || this.defaultUrl, params, callback, true);
12082         }
12083         if(this.autoRefreshProcId){
12084             clearInterval(this.autoRefreshProcId);
12085         }
12086         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12087     },
12088
12089     /**
12090      * Stop auto refresh on this element.
12091      */
12092      stopAutoRefresh : function(){
12093         if(this.autoRefreshProcId){
12094             clearInterval(this.autoRefreshProcId);
12095             delete this.autoRefreshProcId;
12096         }
12097     },
12098
12099     isAutoRefreshing : function(){
12100        return this.autoRefreshProcId ? true : false;
12101     },
12102     /**
12103      * Called to update the element to "Loading" state. Override to perform custom action.
12104      */
12105     showLoading : function(){
12106         if(this.showLoadIndicator){
12107             this.el.update(this.indicatorText);
12108         }
12109     },
12110
12111     /**
12112      * Adds unique parameter to query string if disableCaching = true
12113      * @private
12114      */
12115     prepareUrl : function(url){
12116         if(this.disableCaching){
12117             var append = "_dc=" + (new Date().getTime());
12118             if(url.indexOf("?") !== -1){
12119                 url += "&" + append;
12120             }else{
12121                 url += "?" + append;
12122             }
12123         }
12124         return url;
12125     },
12126
12127     /**
12128      * @private
12129      */
12130     processSuccess : function(response){
12131         this.transaction = null;
12132         if(response.argument.form && response.argument.reset){
12133             try{ // put in try/catch since some older FF releases had problems with this
12134                 response.argument.form.reset();
12135             }catch(e){}
12136         }
12137         if(this.loadScripts){
12138             this.renderer.render(this.el, response, this,
12139                 this.updateComplete.createDelegate(this, [response]));
12140         }else{
12141             this.renderer.render(this.el, response, this);
12142             this.updateComplete(response);
12143         }
12144     },
12145
12146     updateComplete : function(response){
12147         this.fireEvent("update", this.el, response);
12148         if(typeof response.argument.callback == "function"){
12149             response.argument.callback(this.el, true, response);
12150         }
12151     },
12152
12153     /**
12154      * @private
12155      */
12156     processFailure : function(response){
12157         this.transaction = null;
12158         this.fireEvent("failure", this.el, response);
12159         if(typeof response.argument.callback == "function"){
12160             response.argument.callback(this.el, false, response);
12161         }
12162     },
12163
12164     /**
12165      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12166      * @param {Object} renderer The object implementing the render() method
12167      */
12168     setRenderer : function(renderer){
12169         this.renderer = renderer;
12170     },
12171
12172     getRenderer : function(){
12173        return this.renderer;
12174     },
12175
12176     /**
12177      * Set the defaultUrl used for updates
12178      * @param {String/Function} defaultUrl The url or a function to call to get the url
12179      */
12180     setDefaultUrl : function(defaultUrl){
12181         this.defaultUrl = defaultUrl;
12182     },
12183
12184     /**
12185      * Aborts the executing transaction
12186      */
12187     abort : function(){
12188         if(this.transaction){
12189             Roo.Ajax.abort(this.transaction);
12190         }
12191     },
12192
12193     /**
12194      * Returns true if an update is in progress
12195      * @return {Boolean}
12196      */
12197     isUpdating : function(){
12198         if(this.transaction){
12199             return Roo.Ajax.isLoading(this.transaction);
12200         }
12201         return false;
12202     }
12203 });
12204
12205 /**
12206  * @class Roo.UpdateManager.defaults
12207  * @static (not really - but it helps the doc tool)
12208  * The defaults collection enables customizing the default properties of UpdateManager
12209  */
12210    Roo.UpdateManager.defaults = {
12211        /**
12212          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12213          * @type Number
12214          */
12215          timeout : 30,
12216
12217          /**
12218          * True to process scripts by default (Defaults to false).
12219          * @type Boolean
12220          */
12221         loadScripts : false,
12222
12223         /**
12224         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12225         * @type String
12226         */
12227         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12228         /**
12229          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12230          * @type Boolean
12231          */
12232         disableCaching : false,
12233         /**
12234          * Whether to show indicatorText when loading (Defaults to true).
12235          * @type Boolean
12236          */
12237         showLoadIndicator : true,
12238         /**
12239          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12240          * @type String
12241          */
12242         indicatorText : '<div class="loading-indicator">Loading...</div>'
12243    };
12244
12245 /**
12246  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12247  *Usage:
12248  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12249  * @param {String/HTMLElement/Roo.Element} el The element to update
12250  * @param {String} url The url
12251  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12252  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12253  * @static
12254  * @deprecated
12255  * @member Roo.UpdateManager
12256  */
12257 Roo.UpdateManager.updateElement = function(el, url, params, options){
12258     var um = Roo.get(el, true).getUpdateManager();
12259     Roo.apply(um, options);
12260     um.update(url, params, options ? options.callback : null);
12261 };
12262 // alias for backwards compat
12263 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12264 /**
12265  * @class Roo.UpdateManager.BasicRenderer
12266  * Default Content renderer. Updates the elements innerHTML with the responseText.
12267  */
12268 Roo.UpdateManager.BasicRenderer = function(){};
12269
12270 Roo.UpdateManager.BasicRenderer.prototype = {
12271     /**
12272      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12273      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12274      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12275      * @param {Roo.Element} el The element being rendered
12276      * @param {Object} response The YUI Connect response object
12277      * @param {UpdateManager} updateManager The calling update manager
12278      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12279      */
12280      render : function(el, response, updateManager, callback){
12281         el.update(response.responseText, updateManager.loadScripts, callback);
12282     }
12283 };
12284 /*
12285  * Based on:
12286  * Roo JS
12287  * (c)) Alan Knowles
12288  * Licence : LGPL
12289  */
12290
12291
12292 /**
12293  * @class Roo.DomTemplate
12294  * @extends Roo.Template
12295  * An effort at a dom based template engine..
12296  *
12297  * Similar to XTemplate, except it uses dom parsing to create the template..
12298  *
12299  * Supported features:
12300  *
12301  *  Tags:
12302
12303 <pre><code>
12304       {a_variable} - output encoded.
12305       {a_variable.format:("Y-m-d")} - call a method on the variable
12306       {a_variable:raw} - unencoded output
12307       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12308       {a_variable:this.method_on_template(...)} - call a method on the template object.
12309  
12310 </code></pre>
12311  *  The tpl tag:
12312 <pre><code>
12313         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12314         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12315         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12316         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12317   
12318 </code></pre>
12319  *      
12320  */
12321 Roo.DomTemplate = function()
12322 {
12323      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12324      if (this.html) {
12325         this.compile();
12326      }
12327 };
12328
12329
12330 Roo.extend(Roo.DomTemplate, Roo.Template, {
12331     /**
12332      * id counter for sub templates.
12333      */
12334     id : 0,
12335     /**
12336      * flag to indicate if dom parser is inside a pre,
12337      * it will strip whitespace if not.
12338      */
12339     inPre : false,
12340     
12341     /**
12342      * The various sub templates
12343      */
12344     tpls : false,
12345     
12346     
12347     
12348     /**
12349      *
12350      * basic tag replacing syntax
12351      * WORD:WORD()
12352      *
12353      * // you can fake an object call by doing this
12354      *  x.t:(test,tesT) 
12355      * 
12356      */
12357     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12358     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12359     
12360     iterChild : function (node, method) {
12361         
12362         var oldPre = this.inPre;
12363         if (node.tagName == 'PRE') {
12364             this.inPre = true;
12365         }
12366         for( var i = 0; i < node.childNodes.length; i++) {
12367             method.call(this, node.childNodes[i]);
12368         }
12369         this.inPre = oldPre;
12370     },
12371     
12372     
12373     
12374     /**
12375      * compile the template
12376      *
12377      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12378      *
12379      */
12380     compile: function()
12381     {
12382         var s = this.html;
12383         
12384         // covert the html into DOM...
12385         var doc = false;
12386         var div =false;
12387         try {
12388             doc = document.implementation.createHTMLDocument("");
12389             doc.documentElement.innerHTML =   this.html  ;
12390             div = doc.documentElement;
12391         } catch (e) {
12392             // old IE... - nasty -- it causes all sorts of issues.. with
12393             // images getting pulled from server..
12394             div = document.createElement('div');
12395             div.innerHTML = this.html;
12396         }
12397         //doc.documentElement.innerHTML = htmlBody
12398          
12399         
12400         
12401         this.tpls = [];
12402         var _t = this;
12403         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12404         
12405         var tpls = this.tpls;
12406         
12407         // create a top level template from the snippet..
12408         
12409         //Roo.log(div.innerHTML);
12410         
12411         var tpl = {
12412             uid : 'master',
12413             id : this.id++,
12414             attr : false,
12415             value : false,
12416             body : div.innerHTML,
12417             
12418             forCall : false,
12419             execCall : false,
12420             dom : div,
12421             isTop : true
12422             
12423         };
12424         tpls.unshift(tpl);
12425         
12426         
12427         // compile them...
12428         this.tpls = [];
12429         Roo.each(tpls, function(tp){
12430             this.compileTpl(tp);
12431             this.tpls[tp.id] = tp;
12432         }, this);
12433         
12434         this.master = tpls[0];
12435         return this;
12436         
12437         
12438     },
12439     
12440     compileNode : function(node, istop) {
12441         // test for
12442         //Roo.log(node);
12443         
12444         
12445         // skip anything not a tag..
12446         if (node.nodeType != 1) {
12447             if (node.nodeType == 3 && !this.inPre) {
12448                 // reduce white space..
12449                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12450                 
12451             }
12452             return;
12453         }
12454         
12455         var tpl = {
12456             uid : false,
12457             id : false,
12458             attr : false,
12459             value : false,
12460             body : '',
12461             
12462             forCall : false,
12463             execCall : false,
12464             dom : false,
12465             isTop : istop
12466             
12467             
12468         };
12469         
12470         
12471         switch(true) {
12472             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12473             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12474             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12475             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12476             // no default..
12477         }
12478         
12479         
12480         if (!tpl.attr) {
12481             // just itterate children..
12482             this.iterChild(node,this.compileNode);
12483             return;
12484         }
12485         tpl.uid = this.id++;
12486         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12487         node.removeAttribute('roo-'+ tpl.attr);
12488         if (tpl.attr != 'name') {
12489             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12490             node.parentNode.replaceChild(placeholder,  node);
12491         } else {
12492             
12493             var placeholder =  document.createElement('span');
12494             placeholder.className = 'roo-tpl-' + tpl.value;
12495             node.parentNode.replaceChild(placeholder,  node);
12496         }
12497         
12498         // parent now sees '{domtplXXXX}
12499         this.iterChild(node,this.compileNode);
12500         
12501         // we should now have node body...
12502         var div = document.createElement('div');
12503         div.appendChild(node);
12504         tpl.dom = node;
12505         // this has the unfortunate side effect of converting tagged attributes
12506         // eg. href="{...}" into %7C...%7D
12507         // this has been fixed by searching for those combo's although it's a bit hacky..
12508         
12509         
12510         tpl.body = div.innerHTML;
12511         
12512         
12513          
12514         tpl.id = tpl.uid;
12515         switch(tpl.attr) {
12516             case 'for' :
12517                 switch (tpl.value) {
12518                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12519                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12520                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12521                 }
12522                 break;
12523             
12524             case 'exec':
12525                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12526                 break;
12527             
12528             case 'if':     
12529                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12530                 break;
12531             
12532             case 'name':
12533                 tpl.id  = tpl.value; // replace non characters???
12534                 break;
12535             
12536         }
12537         
12538         
12539         this.tpls.push(tpl);
12540         
12541         
12542         
12543     },
12544     
12545     
12546     
12547     
12548     /**
12549      * Compile a segment of the template into a 'sub-template'
12550      *
12551      * 
12552      * 
12553      *
12554      */
12555     compileTpl : function(tpl)
12556     {
12557         var fm = Roo.util.Format;
12558         var useF = this.disableFormats !== true;
12559         
12560         var sep = Roo.isGecko ? "+\n" : ",\n";
12561         
12562         var undef = function(str) {
12563             Roo.debug && Roo.log("Property not found :"  + str);
12564             return '';
12565         };
12566           
12567         //Roo.log(tpl.body);
12568         
12569         
12570         
12571         var fn = function(m, lbrace, name, format, args)
12572         {
12573             //Roo.log("ARGS");
12574             //Roo.log(arguments);
12575             args = args ? args.replace(/\\'/g,"'") : args;
12576             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12577             if (typeof(format) == 'undefined') {
12578                 format =  'htmlEncode'; 
12579             }
12580             if (format == 'raw' ) {
12581                 format = false;
12582             }
12583             
12584             if(name.substr(0, 6) == 'domtpl'){
12585                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12586             }
12587             
12588             // build an array of options to determine if value is undefined..
12589             
12590             // basically get 'xxxx.yyyy' then do
12591             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12592             //    (function () { Roo.log("Property not found"); return ''; })() :
12593             //    ......
12594             
12595             var udef_ar = [];
12596             var lookfor = '';
12597             Roo.each(name.split('.'), function(st) {
12598                 lookfor += (lookfor.length ? '.': '') + st;
12599                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12600             });
12601             
12602             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12603             
12604             
12605             if(format && useF){
12606                 
12607                 args = args ? ',' + args : "";
12608                  
12609                 if(format.substr(0, 5) != "this."){
12610                     format = "fm." + format + '(';
12611                 }else{
12612                     format = 'this.call("'+ format.substr(5) + '", ';
12613                     args = ", values";
12614                 }
12615                 
12616                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12617             }
12618              
12619             if (args && args.length) {
12620                 // called with xxyx.yuu:(test,test)
12621                 // change to ()
12622                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12623             }
12624             // raw.. - :raw modifier..
12625             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12626             
12627         };
12628         var body;
12629         // branched to use + in gecko and [].join() in others
12630         if(Roo.isGecko){
12631             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12632                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12633                     "';};};";
12634         }else{
12635             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12636             body.push(tpl.body.replace(/(\r\n|\n)/g,
12637                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12638             body.push("'].join('');};};");
12639             body = body.join('');
12640         }
12641         
12642         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12643        
12644         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12645         eval(body);
12646         
12647         return this;
12648     },
12649      
12650     /**
12651      * same as applyTemplate, except it's done to one of the subTemplates
12652      * when using named templates, you can do:
12653      *
12654      * var str = pl.applySubTemplate('your-name', values);
12655      *
12656      * 
12657      * @param {Number} id of the template
12658      * @param {Object} values to apply to template
12659      * @param {Object} parent (normaly the instance of this object)
12660      */
12661     applySubTemplate : function(id, values, parent)
12662     {
12663         
12664         
12665         var t = this.tpls[id];
12666         
12667         
12668         try { 
12669             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12670                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12671                 return '';
12672             }
12673         } catch(e) {
12674             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12675             Roo.log(values);
12676           
12677             return '';
12678         }
12679         try { 
12680             
12681             if(t.execCall && t.execCall.call(this, values, parent)){
12682                 return '';
12683             }
12684         } catch(e) {
12685             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12686             Roo.log(values);
12687             return '';
12688         }
12689         
12690         try {
12691             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12692             parent = t.target ? values : parent;
12693             if(t.forCall && vs instanceof Array){
12694                 var buf = [];
12695                 for(var i = 0, len = vs.length; i < len; i++){
12696                     try {
12697                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12698                     } catch (e) {
12699                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12700                         Roo.log(e.body);
12701                         //Roo.log(t.compiled);
12702                         Roo.log(vs[i]);
12703                     }   
12704                 }
12705                 return buf.join('');
12706             }
12707         } catch (e) {
12708             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12709             Roo.log(values);
12710             return '';
12711         }
12712         try {
12713             return t.compiled.call(this, vs, parent);
12714         } catch (e) {
12715             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12716             Roo.log(e.body);
12717             //Roo.log(t.compiled);
12718             Roo.log(values);
12719             return '';
12720         }
12721     },
12722
12723    
12724
12725     applyTemplate : function(values){
12726         return this.master.compiled.call(this, values, {});
12727         //var s = this.subs;
12728     },
12729
12730     apply : function(){
12731         return this.applyTemplate.apply(this, arguments);
12732     }
12733
12734  });
12735
12736 Roo.DomTemplate.from = function(el){
12737     el = Roo.getDom(el);
12738     return new Roo.Domtemplate(el.value || el.innerHTML);
12739 };/*
12740  * Based on:
12741  * Ext JS Library 1.1.1
12742  * Copyright(c) 2006-2007, Ext JS, LLC.
12743  *
12744  * Originally Released Under LGPL - original licence link has changed is not relivant.
12745  *
12746  * Fork - LGPL
12747  * <script type="text/javascript">
12748  */
12749
12750 /**
12751  * @class Roo.util.DelayedTask
12752  * Provides a convenient method of performing setTimeout where a new
12753  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12754  * You can use this class to buffer
12755  * the keypress events for a certain number of milliseconds, and perform only if they stop
12756  * for that amount of time.
12757  * @constructor The parameters to this constructor serve as defaults and are not required.
12758  * @param {Function} fn (optional) The default function to timeout
12759  * @param {Object} scope (optional) The default scope of that timeout
12760  * @param {Array} args (optional) The default Array of arguments
12761  */
12762 Roo.util.DelayedTask = function(fn, scope, args){
12763     var id = null, d, t;
12764
12765     var call = function(){
12766         var now = new Date().getTime();
12767         if(now - t >= d){
12768             clearInterval(id);
12769             id = null;
12770             fn.apply(scope, args || []);
12771         }
12772     };
12773     /**
12774      * Cancels any pending timeout and queues a new one
12775      * @param {Number} delay The milliseconds to delay
12776      * @param {Function} newFn (optional) Overrides function passed to constructor
12777      * @param {Object} newScope (optional) Overrides scope passed to constructor
12778      * @param {Array} newArgs (optional) Overrides args passed to constructor
12779      */
12780     this.delay = function(delay, newFn, newScope, newArgs){
12781         if(id && delay != d){
12782             this.cancel();
12783         }
12784         d = delay;
12785         t = new Date().getTime();
12786         fn = newFn || fn;
12787         scope = newScope || scope;
12788         args = newArgs || args;
12789         if(!id){
12790             id = setInterval(call, d);
12791         }
12792     };
12793
12794     /**
12795      * Cancel the last queued timeout
12796      */
12797     this.cancel = function(){
12798         if(id){
12799             clearInterval(id);
12800             id = null;
12801         }
12802     };
12803 };/*
12804  * Based on:
12805  * Ext JS Library 1.1.1
12806  * Copyright(c) 2006-2007, Ext JS, LLC.
12807  *
12808  * Originally Released Under LGPL - original licence link has changed is not relivant.
12809  *
12810  * Fork - LGPL
12811  * <script type="text/javascript">
12812  */
12813  
12814  
12815 Roo.util.TaskRunner = function(interval){
12816     interval = interval || 10;
12817     var tasks = [], removeQueue = [];
12818     var id = 0;
12819     var running = false;
12820
12821     var stopThread = function(){
12822         running = false;
12823         clearInterval(id);
12824         id = 0;
12825     };
12826
12827     var startThread = function(){
12828         if(!running){
12829             running = true;
12830             id = setInterval(runTasks, interval);
12831         }
12832     };
12833
12834     var removeTask = function(task){
12835         removeQueue.push(task);
12836         if(task.onStop){
12837             task.onStop();
12838         }
12839     };
12840
12841     var runTasks = function(){
12842         if(removeQueue.length > 0){
12843             for(var i = 0, len = removeQueue.length; i < len; i++){
12844                 tasks.remove(removeQueue[i]);
12845             }
12846             removeQueue = [];
12847             if(tasks.length < 1){
12848                 stopThread();
12849                 return;
12850             }
12851         }
12852         var now = new Date().getTime();
12853         for(var i = 0, len = tasks.length; i < len; ++i){
12854             var t = tasks[i];
12855             var itime = now - t.taskRunTime;
12856             if(t.interval <= itime){
12857                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12858                 t.taskRunTime = now;
12859                 if(rt === false || t.taskRunCount === t.repeat){
12860                     removeTask(t);
12861                     return;
12862                 }
12863             }
12864             if(t.duration && t.duration <= (now - t.taskStartTime)){
12865                 removeTask(t);
12866             }
12867         }
12868     };
12869
12870     /**
12871      * Queues a new task.
12872      * @param {Object} task
12873      */
12874     this.start = function(task){
12875         tasks.push(task);
12876         task.taskStartTime = new Date().getTime();
12877         task.taskRunTime = 0;
12878         task.taskRunCount = 0;
12879         startThread();
12880         return task;
12881     };
12882
12883     this.stop = function(task){
12884         removeTask(task);
12885         return task;
12886     };
12887
12888     this.stopAll = function(){
12889         stopThread();
12890         for(var i = 0, len = tasks.length; i < len; i++){
12891             if(tasks[i].onStop){
12892                 tasks[i].onStop();
12893             }
12894         }
12895         tasks = [];
12896         removeQueue = [];
12897     };
12898 };
12899
12900 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12901  * Based on:
12902  * Ext JS Library 1.1.1
12903  * Copyright(c) 2006-2007, Ext JS, LLC.
12904  *
12905  * Originally Released Under LGPL - original licence link has changed is not relivant.
12906  *
12907  * Fork - LGPL
12908  * <script type="text/javascript">
12909  */
12910
12911  
12912 /**
12913  * @class Roo.util.MixedCollection
12914  * @extends Roo.util.Observable
12915  * A Collection class that maintains both numeric indexes and keys and exposes events.
12916  * @constructor
12917  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12918  * collection (defaults to false)
12919  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12920  * and return the key value for that item.  This is used when available to look up the key on items that
12921  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12922  * equivalent to providing an implementation for the {@link #getKey} method.
12923  */
12924 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12925     this.items = [];
12926     this.map = {};
12927     this.keys = [];
12928     this.length = 0;
12929     this.addEvents({
12930         /**
12931          * @event clear
12932          * Fires when the collection is cleared.
12933          */
12934         "clear" : true,
12935         /**
12936          * @event add
12937          * Fires when an item is added to the collection.
12938          * @param {Number} index The index at which the item was added.
12939          * @param {Object} o The item added.
12940          * @param {String} key The key associated with the added item.
12941          */
12942         "add" : true,
12943         /**
12944          * @event replace
12945          * Fires when an item is replaced in the collection.
12946          * @param {String} key he key associated with the new added.
12947          * @param {Object} old The item being replaced.
12948          * @param {Object} new The new item.
12949          */
12950         "replace" : true,
12951         /**
12952          * @event remove
12953          * Fires when an item is removed from the collection.
12954          * @param {Object} o The item being removed.
12955          * @param {String} key (optional) The key associated with the removed item.
12956          */
12957         "remove" : true,
12958         "sort" : true
12959     });
12960     this.allowFunctions = allowFunctions === true;
12961     if(keyFn){
12962         this.getKey = keyFn;
12963     }
12964     Roo.util.MixedCollection.superclass.constructor.call(this);
12965 };
12966
12967 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12968     allowFunctions : false,
12969     
12970 /**
12971  * Adds an item to the collection.
12972  * @param {String} key The key to associate with the item
12973  * @param {Object} o The item to add.
12974  * @return {Object} The item added.
12975  */
12976     add : function(key, o){
12977         if(arguments.length == 1){
12978             o = arguments[0];
12979             key = this.getKey(o);
12980         }
12981         if(typeof key == "undefined" || key === null){
12982             this.length++;
12983             this.items.push(o);
12984             this.keys.push(null);
12985         }else{
12986             var old = this.map[key];
12987             if(old){
12988                 return this.replace(key, o);
12989             }
12990             this.length++;
12991             this.items.push(o);
12992             this.map[key] = o;
12993             this.keys.push(key);
12994         }
12995         this.fireEvent("add", this.length-1, o, key);
12996         return o;
12997     },
12998        
12999 /**
13000   * MixedCollection has a generic way to fetch keys if you implement getKey.
13001 <pre><code>
13002 // normal way
13003 var mc = new Roo.util.MixedCollection();
13004 mc.add(someEl.dom.id, someEl);
13005 mc.add(otherEl.dom.id, otherEl);
13006 //and so on
13007
13008 // using getKey
13009 var mc = new Roo.util.MixedCollection();
13010 mc.getKey = function(el){
13011    return el.dom.id;
13012 };
13013 mc.add(someEl);
13014 mc.add(otherEl);
13015
13016 // or via the constructor
13017 var mc = new Roo.util.MixedCollection(false, function(el){
13018    return el.dom.id;
13019 });
13020 mc.add(someEl);
13021 mc.add(otherEl);
13022 </code></pre>
13023  * @param o {Object} The item for which to find the key.
13024  * @return {Object} The key for the passed item.
13025  */
13026     getKey : function(o){
13027          return o.id; 
13028     },
13029    
13030 /**
13031  * Replaces an item in the collection.
13032  * @param {String} key The key associated with the item to replace, or the item to replace.
13033  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13034  * @return {Object}  The new item.
13035  */
13036     replace : function(key, o){
13037         if(arguments.length == 1){
13038             o = arguments[0];
13039             key = this.getKey(o);
13040         }
13041         var old = this.item(key);
13042         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13043              return this.add(key, o);
13044         }
13045         var index = this.indexOfKey(key);
13046         this.items[index] = o;
13047         this.map[key] = o;
13048         this.fireEvent("replace", key, old, o);
13049         return o;
13050     },
13051    
13052 /**
13053  * Adds all elements of an Array or an Object to the collection.
13054  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13055  * an Array of values, each of which are added to the collection.
13056  */
13057     addAll : function(objs){
13058         if(arguments.length > 1 || objs instanceof Array){
13059             var args = arguments.length > 1 ? arguments : objs;
13060             for(var i = 0, len = args.length; i < len; i++){
13061                 this.add(args[i]);
13062             }
13063         }else{
13064             for(var key in objs){
13065                 if(this.allowFunctions || typeof objs[key] != "function"){
13066                     this.add(key, objs[key]);
13067                 }
13068             }
13069         }
13070     },
13071    
13072 /**
13073  * Executes the specified function once for every item in the collection, passing each
13074  * item as the first and only parameter. returning false from the function will stop the iteration.
13075  * @param {Function} fn The function to execute for each item.
13076  * @param {Object} scope (optional) The scope in which to execute the function.
13077  */
13078     each : function(fn, scope){
13079         var items = [].concat(this.items); // each safe for removal
13080         for(var i = 0, len = items.length; i < len; i++){
13081             if(fn.call(scope || items[i], items[i], i, len) === false){
13082                 break;
13083             }
13084         }
13085     },
13086    
13087 /**
13088  * Executes the specified function once for every key in the collection, passing each
13089  * key, and its associated item as the first two parameters.
13090  * @param {Function} fn The function to execute for each item.
13091  * @param {Object} scope (optional) The scope in which to execute the function.
13092  */
13093     eachKey : function(fn, scope){
13094         for(var i = 0, len = this.keys.length; i < len; i++){
13095             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13096         }
13097     },
13098    
13099 /**
13100  * Returns the first item in the collection which elicits a true return value from the
13101  * passed selection function.
13102  * @param {Function} fn The selection function to execute for each item.
13103  * @param {Object} scope (optional) The scope in which to execute the function.
13104  * @return {Object} The first item in the collection which returned true from the selection function.
13105  */
13106     find : function(fn, scope){
13107         for(var i = 0, len = this.items.length; i < len; i++){
13108             if(fn.call(scope || window, this.items[i], this.keys[i])){
13109                 return this.items[i];
13110             }
13111         }
13112         return null;
13113     },
13114    
13115 /**
13116  * Inserts an item at the specified index in the collection.
13117  * @param {Number} index The index to insert the item at.
13118  * @param {String} key The key to associate with the new item, or the item itself.
13119  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13120  * @return {Object} The item inserted.
13121  */
13122     insert : function(index, key, o){
13123         if(arguments.length == 2){
13124             o = arguments[1];
13125             key = this.getKey(o);
13126         }
13127         if(index >= this.length){
13128             return this.add(key, o);
13129         }
13130         this.length++;
13131         this.items.splice(index, 0, o);
13132         if(typeof key != "undefined" && key != null){
13133             this.map[key] = o;
13134         }
13135         this.keys.splice(index, 0, key);
13136         this.fireEvent("add", index, o, key);
13137         return o;
13138     },
13139    
13140 /**
13141  * Removed an item from the collection.
13142  * @param {Object} o The item to remove.
13143  * @return {Object} The item removed.
13144  */
13145     remove : function(o){
13146         return this.removeAt(this.indexOf(o));
13147     },
13148    
13149 /**
13150  * Remove an item from a specified index in the collection.
13151  * @param {Number} index The index within the collection of the item to remove.
13152  */
13153     removeAt : function(index){
13154         if(index < this.length && index >= 0){
13155             this.length--;
13156             var o = this.items[index];
13157             this.items.splice(index, 1);
13158             var key = this.keys[index];
13159             if(typeof key != "undefined"){
13160                 delete this.map[key];
13161             }
13162             this.keys.splice(index, 1);
13163             this.fireEvent("remove", o, key);
13164         }
13165     },
13166    
13167 /**
13168  * Removed an item associated with the passed key fom the collection.
13169  * @param {String} key The key of the item to remove.
13170  */
13171     removeKey : function(key){
13172         return this.removeAt(this.indexOfKey(key));
13173     },
13174    
13175 /**
13176  * Returns the number of items in the collection.
13177  * @return {Number} the number of items in the collection.
13178  */
13179     getCount : function(){
13180         return this.length; 
13181     },
13182    
13183 /**
13184  * Returns index within the collection of the passed Object.
13185  * @param {Object} o The item to find the index of.
13186  * @return {Number} index of the item.
13187  */
13188     indexOf : function(o){
13189         if(!this.items.indexOf){
13190             for(var i = 0, len = this.items.length; i < len; i++){
13191                 if(this.items[i] == o) {
13192                     return i;
13193                 }
13194             }
13195             return -1;
13196         }else{
13197             return this.items.indexOf(o);
13198         }
13199     },
13200    
13201 /**
13202  * Returns index within the collection of the passed key.
13203  * @param {String} key The key to find the index of.
13204  * @return {Number} index of the key.
13205  */
13206     indexOfKey : function(key){
13207         if(!this.keys.indexOf){
13208             for(var i = 0, len = this.keys.length; i < len; i++){
13209                 if(this.keys[i] == key) {
13210                     return i;
13211                 }
13212             }
13213             return -1;
13214         }else{
13215             return this.keys.indexOf(key);
13216         }
13217     },
13218    
13219 /**
13220  * Returns the item associated with the passed key OR index. Key has priority over index.
13221  * @param {String/Number} key The key or index of the item.
13222  * @return {Object} The item associated with the passed key.
13223  */
13224     item : function(key){
13225         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13226         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13227     },
13228     
13229 /**
13230  * Returns the item at the specified index.
13231  * @param {Number} index The index of the item.
13232  * @return {Object}
13233  */
13234     itemAt : function(index){
13235         return this.items[index];
13236     },
13237     
13238 /**
13239  * Returns the item associated with the passed key.
13240  * @param {String/Number} key The key of the item.
13241  * @return {Object} The item associated with the passed key.
13242  */
13243     key : function(key){
13244         return this.map[key];
13245     },
13246    
13247 /**
13248  * Returns true if the collection contains the passed Object as an item.
13249  * @param {Object} o  The Object to look for in the collection.
13250  * @return {Boolean} True if the collection contains the Object as an item.
13251  */
13252     contains : function(o){
13253         return this.indexOf(o) != -1;
13254     },
13255    
13256 /**
13257  * Returns true if the collection contains the passed Object as a key.
13258  * @param {String} key The key to look for in the collection.
13259  * @return {Boolean} True if the collection contains the Object as a key.
13260  */
13261     containsKey : function(key){
13262         return typeof this.map[key] != "undefined";
13263     },
13264    
13265 /**
13266  * Removes all items from the collection.
13267  */
13268     clear : function(){
13269         this.length = 0;
13270         this.items = [];
13271         this.keys = [];
13272         this.map = {};
13273         this.fireEvent("clear");
13274     },
13275    
13276 /**
13277  * Returns the first item in the collection.
13278  * @return {Object} the first item in the collection..
13279  */
13280     first : function(){
13281         return this.items[0]; 
13282     },
13283    
13284 /**
13285  * Returns the last item in the collection.
13286  * @return {Object} the last item in the collection..
13287  */
13288     last : function(){
13289         return this.items[this.length-1];   
13290     },
13291     
13292     _sort : function(property, dir, fn){
13293         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13294         fn = fn || function(a, b){
13295             return a-b;
13296         };
13297         var c = [], k = this.keys, items = this.items;
13298         for(var i = 0, len = items.length; i < len; i++){
13299             c[c.length] = {key: k[i], value: items[i], index: i};
13300         }
13301         c.sort(function(a, b){
13302             var v = fn(a[property], b[property]) * dsc;
13303             if(v == 0){
13304                 v = (a.index < b.index ? -1 : 1);
13305             }
13306             return v;
13307         });
13308         for(var i = 0, len = c.length; i < len; i++){
13309             items[i] = c[i].value;
13310             k[i] = c[i].key;
13311         }
13312         this.fireEvent("sort", this);
13313     },
13314     
13315     /**
13316      * Sorts this collection with the passed comparison function
13317      * @param {String} direction (optional) "ASC" or "DESC"
13318      * @param {Function} fn (optional) comparison function
13319      */
13320     sort : function(dir, fn){
13321         this._sort("value", dir, fn);
13322     },
13323     
13324     /**
13325      * Sorts this collection by keys
13326      * @param {String} direction (optional) "ASC" or "DESC"
13327      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13328      */
13329     keySort : function(dir, fn){
13330         this._sort("key", dir, fn || function(a, b){
13331             return String(a).toUpperCase()-String(b).toUpperCase();
13332         });
13333     },
13334     
13335     /**
13336      * Returns a range of items in this collection
13337      * @param {Number} startIndex (optional) defaults to 0
13338      * @param {Number} endIndex (optional) default to the last item
13339      * @return {Array} An array of items
13340      */
13341     getRange : function(start, end){
13342         var items = this.items;
13343         if(items.length < 1){
13344             return [];
13345         }
13346         start = start || 0;
13347         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13348         var r = [];
13349         if(start <= end){
13350             for(var i = start; i <= end; i++) {
13351                     r[r.length] = items[i];
13352             }
13353         }else{
13354             for(var i = start; i >= end; i--) {
13355                     r[r.length] = items[i];
13356             }
13357         }
13358         return r;
13359     },
13360         
13361     /**
13362      * Filter the <i>objects</i> in this collection by a specific property. 
13363      * Returns a new collection that has been filtered.
13364      * @param {String} property A property on your objects
13365      * @param {String/RegExp} value Either string that the property values 
13366      * should start with or a RegExp to test against the property
13367      * @return {MixedCollection} The new filtered collection
13368      */
13369     filter : function(property, value){
13370         if(!value.exec){ // not a regex
13371             value = String(value);
13372             if(value.length == 0){
13373                 return this.clone();
13374             }
13375             value = new RegExp("^" + Roo.escapeRe(value), "i");
13376         }
13377         return this.filterBy(function(o){
13378             return o && value.test(o[property]);
13379         });
13380         },
13381     
13382     /**
13383      * Filter by a function. * Returns a new collection that has been filtered.
13384      * The passed function will be called with each 
13385      * object in the collection. If the function returns true, the value is included 
13386      * otherwise it is filtered.
13387      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13388      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13389      * @return {MixedCollection} The new filtered collection
13390      */
13391     filterBy : function(fn, scope){
13392         var r = new Roo.util.MixedCollection();
13393         r.getKey = this.getKey;
13394         var k = this.keys, it = this.items;
13395         for(var i = 0, len = it.length; i < len; i++){
13396             if(fn.call(scope||this, it[i], k[i])){
13397                                 r.add(k[i], it[i]);
13398                         }
13399         }
13400         return r;
13401     },
13402     
13403     /**
13404      * Creates a duplicate of this collection
13405      * @return {MixedCollection}
13406      */
13407     clone : function(){
13408         var r = new Roo.util.MixedCollection();
13409         var k = this.keys, it = this.items;
13410         for(var i = 0, len = it.length; i < len; i++){
13411             r.add(k[i], it[i]);
13412         }
13413         r.getKey = this.getKey;
13414         return r;
13415     }
13416 });
13417 /**
13418  * Returns the item associated with the passed key or index.
13419  * @method
13420  * @param {String/Number} key The key or index of the item.
13421  * @return {Object} The item associated with the passed key.
13422  */
13423 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13424  * Based on:
13425  * Ext JS Library 1.1.1
13426  * Copyright(c) 2006-2007, Ext JS, LLC.
13427  *
13428  * Originally Released Under LGPL - original licence link has changed is not relivant.
13429  *
13430  * Fork - LGPL
13431  * <script type="text/javascript">
13432  */
13433 /**
13434  * @class Roo.util.JSON
13435  * Modified version of Douglas Crockford"s json.js that doesn"t
13436  * mess with the Object prototype 
13437  * http://www.json.org/js.html
13438  * @singleton
13439  */
13440 Roo.util.JSON = new (function(){
13441     var useHasOwn = {}.hasOwnProperty ? true : false;
13442     
13443     // crashes Safari in some instances
13444     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13445     
13446     var pad = function(n) {
13447         return n < 10 ? "0" + n : n;
13448     };
13449     
13450     var m = {
13451         "\b": '\\b',
13452         "\t": '\\t',
13453         "\n": '\\n',
13454         "\f": '\\f',
13455         "\r": '\\r',
13456         '"' : '\\"',
13457         "\\": '\\\\'
13458     };
13459
13460     var encodeString = function(s){
13461         if (/["\\\x00-\x1f]/.test(s)) {
13462             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13463                 var c = m[b];
13464                 if(c){
13465                     return c;
13466                 }
13467                 c = b.charCodeAt();
13468                 return "\\u00" +
13469                     Math.floor(c / 16).toString(16) +
13470                     (c % 16).toString(16);
13471             }) + '"';
13472         }
13473         return '"' + s + '"';
13474     };
13475     
13476     var encodeArray = function(o){
13477         var a = ["["], b, i, l = o.length, v;
13478             for (i = 0; i < l; i += 1) {
13479                 v = o[i];
13480                 switch (typeof v) {
13481                     case "undefined":
13482                     case "function":
13483                     case "unknown":
13484                         break;
13485                     default:
13486                         if (b) {
13487                             a.push(',');
13488                         }
13489                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13490                         b = true;
13491                 }
13492             }
13493             a.push("]");
13494             return a.join("");
13495     };
13496     
13497     var encodeDate = function(o){
13498         return '"' + o.getFullYear() + "-" +
13499                 pad(o.getMonth() + 1) + "-" +
13500                 pad(o.getDate()) + "T" +
13501                 pad(o.getHours()) + ":" +
13502                 pad(o.getMinutes()) + ":" +
13503                 pad(o.getSeconds()) + '"';
13504     };
13505     
13506     /**
13507      * Encodes an Object, Array or other value
13508      * @param {Mixed} o The variable to encode
13509      * @return {String} The JSON string
13510      */
13511     this.encode = function(o)
13512     {
13513         // should this be extended to fully wrap stringify..
13514         
13515         if(typeof o == "undefined" || o === null){
13516             return "null";
13517         }else if(o instanceof Array){
13518             return encodeArray(o);
13519         }else if(o instanceof Date){
13520             return encodeDate(o);
13521         }else if(typeof o == "string"){
13522             return encodeString(o);
13523         }else if(typeof o == "number"){
13524             return isFinite(o) ? String(o) : "null";
13525         }else if(typeof o == "boolean"){
13526             return String(o);
13527         }else {
13528             var a = ["{"], b, i, v;
13529             for (i in o) {
13530                 if(!useHasOwn || o.hasOwnProperty(i)) {
13531                     v = o[i];
13532                     switch (typeof v) {
13533                     case "undefined":
13534                     case "function":
13535                     case "unknown":
13536                         break;
13537                     default:
13538                         if(b){
13539                             a.push(',');
13540                         }
13541                         a.push(this.encode(i), ":",
13542                                 v === null ? "null" : this.encode(v));
13543                         b = true;
13544                     }
13545                 }
13546             }
13547             a.push("}");
13548             return a.join("");
13549         }
13550     };
13551     
13552     /**
13553      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13554      * @param {String} json The JSON string
13555      * @return {Object} The resulting object
13556      */
13557     this.decode = function(json){
13558         
13559         return  /** eval:var:json */ eval("(" + json + ')');
13560     };
13561 })();
13562 /** 
13563  * Shorthand for {@link Roo.util.JSON#encode}
13564  * @member Roo encode 
13565  * @method */
13566 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13567 /** 
13568  * Shorthand for {@link Roo.util.JSON#decode}
13569  * @member Roo decode 
13570  * @method */
13571 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13572 /*
13573  * Based on:
13574  * Ext JS Library 1.1.1
13575  * Copyright(c) 2006-2007, Ext JS, LLC.
13576  *
13577  * Originally Released Under LGPL - original licence link has changed is not relivant.
13578  *
13579  * Fork - LGPL
13580  * <script type="text/javascript">
13581  */
13582  
13583 /**
13584  * @class Roo.util.Format
13585  * Reusable data formatting functions
13586  * @singleton
13587  */
13588 Roo.util.Format = function(){
13589     var trimRe = /^\s+|\s+$/g;
13590     return {
13591         /**
13592          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13593          * @param {String} value The string to truncate
13594          * @param {Number} length The maximum length to allow before truncating
13595          * @return {String} The converted text
13596          */
13597         ellipsis : function(value, len){
13598             if(value && value.length > len){
13599                 return value.substr(0, len-3)+"...";
13600             }
13601             return value;
13602         },
13603
13604         /**
13605          * Checks a reference and converts it to empty string if it is undefined
13606          * @param {Mixed} value Reference to check
13607          * @return {Mixed} Empty string if converted, otherwise the original value
13608          */
13609         undef : function(value){
13610             return typeof value != "undefined" ? value : "";
13611         },
13612
13613         /**
13614          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13615          * @param {String} value The string to encode
13616          * @return {String} The encoded text
13617          */
13618         htmlEncode : function(value){
13619             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13620         },
13621
13622         /**
13623          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13624          * @param {String} value The string to decode
13625          * @return {String} The decoded text
13626          */
13627         htmlDecode : function(value){
13628             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13629         },
13630
13631         /**
13632          * Trims any whitespace from either side of a string
13633          * @param {String} value The text to trim
13634          * @return {String} The trimmed text
13635          */
13636         trim : function(value){
13637             return String(value).replace(trimRe, "");
13638         },
13639
13640         /**
13641          * Returns a substring from within an original string
13642          * @param {String} value The original text
13643          * @param {Number} start The start index of the substring
13644          * @param {Number} length The length of the substring
13645          * @return {String} The substring
13646          */
13647         substr : function(value, start, length){
13648             return String(value).substr(start, length);
13649         },
13650
13651         /**
13652          * Converts a string to all lower case letters
13653          * @param {String} value The text to convert
13654          * @return {String} The converted text
13655          */
13656         lowercase : function(value){
13657             return String(value).toLowerCase();
13658         },
13659
13660         /**
13661          * Converts a string to all upper case letters
13662          * @param {String} value The text to convert
13663          * @return {String} The converted text
13664          */
13665         uppercase : function(value){
13666             return String(value).toUpperCase();
13667         },
13668
13669         /**
13670          * Converts the first character only of a string to upper case
13671          * @param {String} value The text to convert
13672          * @return {String} The converted text
13673          */
13674         capitalize : function(value){
13675             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13676         },
13677
13678         // private
13679         call : function(value, fn){
13680             if(arguments.length > 2){
13681                 var args = Array.prototype.slice.call(arguments, 2);
13682                 args.unshift(value);
13683                  
13684                 return /** eval:var:value */  eval(fn).apply(window, args);
13685             }else{
13686                 /** eval:var:value */
13687                 return /** eval:var:value */ eval(fn).call(window, value);
13688             }
13689         },
13690
13691        
13692         /**
13693          * safer version of Math.toFixed..??/
13694          * @param {Number/String} value The numeric value to format
13695          * @param {Number/String} value Decimal places 
13696          * @return {String} The formatted currency string
13697          */
13698         toFixed : function(v, n)
13699         {
13700             // why not use to fixed - precision is buggered???
13701             if (!n) {
13702                 return Math.round(v-0);
13703             }
13704             var fact = Math.pow(10,n+1);
13705             v = (Math.round((v-0)*fact))/fact;
13706             var z = (''+fact).substring(2);
13707             if (v == Math.floor(v)) {
13708                 return Math.floor(v) + '.' + z;
13709             }
13710             
13711             // now just padd decimals..
13712             var ps = String(v).split('.');
13713             var fd = (ps[1] + z);
13714             var r = fd.substring(0,n); 
13715             var rm = fd.substring(n); 
13716             if (rm < 5) {
13717                 return ps[0] + '.' + r;
13718             }
13719             r*=1; // turn it into a number;
13720             r++;
13721             if (String(r).length != n) {
13722                 ps[0]*=1;
13723                 ps[0]++;
13724                 r = String(r).substring(1); // chop the end off.
13725             }
13726             
13727             return ps[0] + '.' + r;
13728              
13729         },
13730         
13731         /**
13732          * Format a number as US currency
13733          * @param {Number/String} value The numeric value to format
13734          * @return {String} The formatted currency string
13735          */
13736         usMoney : function(v){
13737             return '$' + Roo.util.Format.number(v);
13738         },
13739         
13740         /**
13741          * Format a number
13742          * eventually this should probably emulate php's number_format
13743          * @param {Number/String} value The numeric value to format
13744          * @param {Number} decimals number of decimal places
13745          * @return {String} The formatted currency string
13746          */
13747         number : function(v,decimals)
13748         {
13749             // multiply and round.
13750             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13751             var mul = Math.pow(10, decimals);
13752             var zero = String(mul).substring(1);
13753             v = (Math.round((v-0)*mul))/mul;
13754             
13755             // if it's '0' number.. then
13756             
13757             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13758             v = String(v);
13759             var ps = v.split('.');
13760             var whole = ps[0];
13761             
13762             
13763             var r = /(\d+)(\d{3})/;
13764             // add comma's
13765             while (r.test(whole)) {
13766                 whole = whole.replace(r, '$1' + ',' + '$2');
13767             }
13768             
13769             
13770             var sub = ps[1] ?
13771                     // has decimals..
13772                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13773                     // does not have decimals
13774                     (decimals ? ('.' + zero) : '');
13775             
13776             
13777             return whole + sub ;
13778         },
13779         
13780         /**
13781          * Parse a value into a formatted date using the specified format pattern.
13782          * @param {Mixed} value The value to format
13783          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13784          * @return {String} The formatted date string
13785          */
13786         date : function(v, format){
13787             if(!v){
13788                 return "";
13789             }
13790             if(!(v instanceof Date)){
13791                 v = new Date(Date.parse(v));
13792             }
13793             return v.dateFormat(format || Roo.util.Format.defaults.date);
13794         },
13795
13796         /**
13797          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13798          * @param {String} format Any valid date format string
13799          * @return {Function} The date formatting function
13800          */
13801         dateRenderer : function(format){
13802             return function(v){
13803                 return Roo.util.Format.date(v, format);  
13804             };
13805         },
13806
13807         // private
13808         stripTagsRE : /<\/?[^>]+>/gi,
13809         
13810         /**
13811          * Strips all HTML tags
13812          * @param {Mixed} value The text from which to strip tags
13813          * @return {String} The stripped text
13814          */
13815         stripTags : function(v){
13816             return !v ? v : String(v).replace(this.stripTagsRE, "");
13817         }
13818     };
13819 }();
13820 Roo.util.Format.defaults = {
13821     date : 'd/M/Y'
13822 };/*
13823  * Based on:
13824  * Ext JS Library 1.1.1
13825  * Copyright(c) 2006-2007, Ext JS, LLC.
13826  *
13827  * Originally Released Under LGPL - original licence link has changed is not relivant.
13828  *
13829  * Fork - LGPL
13830  * <script type="text/javascript">
13831  */
13832
13833
13834  
13835
13836 /**
13837  * @class Roo.MasterTemplate
13838  * @extends Roo.Template
13839  * Provides a template that can have child templates. The syntax is:
13840 <pre><code>
13841 var t = new Roo.MasterTemplate(
13842         '&lt;select name="{name}"&gt;',
13843                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13844         '&lt;/select&gt;'
13845 );
13846 t.add('options', {value: 'foo', text: 'bar'});
13847 // or you can add multiple child elements in one shot
13848 t.addAll('options', [
13849     {value: 'foo', text: 'bar'},
13850     {value: 'foo2', text: 'bar2'},
13851     {value: 'foo3', text: 'bar3'}
13852 ]);
13853 // then append, applying the master template values
13854 t.append('my-form', {name: 'my-select'});
13855 </code></pre>
13856 * A name attribute for the child template is not required if you have only one child
13857 * template or you want to refer to them by index.
13858  */
13859 Roo.MasterTemplate = function(){
13860     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13861     this.originalHtml = this.html;
13862     var st = {};
13863     var m, re = this.subTemplateRe;
13864     re.lastIndex = 0;
13865     var subIndex = 0;
13866     while(m = re.exec(this.html)){
13867         var name = m[1], content = m[2];
13868         st[subIndex] = {
13869             name: name,
13870             index: subIndex,
13871             buffer: [],
13872             tpl : new Roo.Template(content)
13873         };
13874         if(name){
13875             st[name] = st[subIndex];
13876         }
13877         st[subIndex].tpl.compile();
13878         st[subIndex].tpl.call = this.call.createDelegate(this);
13879         subIndex++;
13880     }
13881     this.subCount = subIndex;
13882     this.subs = st;
13883 };
13884 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13885     /**
13886     * The regular expression used to match sub templates
13887     * @type RegExp
13888     * @property
13889     */
13890     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13891
13892     /**
13893      * Applies the passed values to a child template.
13894      * @param {String/Number} name (optional) The name or index of the child template
13895      * @param {Array/Object} values The values to be applied to the template
13896      * @return {MasterTemplate} this
13897      */
13898      add : function(name, values){
13899         if(arguments.length == 1){
13900             values = arguments[0];
13901             name = 0;
13902         }
13903         var s = this.subs[name];
13904         s.buffer[s.buffer.length] = s.tpl.apply(values);
13905         return this;
13906     },
13907
13908     /**
13909      * Applies all the passed values to a child template.
13910      * @param {String/Number} name (optional) The name or index of the child template
13911      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13912      * @param {Boolean} reset (optional) True to reset the template first
13913      * @return {MasterTemplate} this
13914      */
13915     fill : function(name, values, reset){
13916         var a = arguments;
13917         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13918             values = a[0];
13919             name = 0;
13920             reset = a[1];
13921         }
13922         if(reset){
13923             this.reset();
13924         }
13925         for(var i = 0, len = values.length; i < len; i++){
13926             this.add(name, values[i]);
13927         }
13928         return this;
13929     },
13930
13931     /**
13932      * Resets the template for reuse
13933      * @return {MasterTemplate} this
13934      */
13935      reset : function(){
13936         var s = this.subs;
13937         for(var i = 0; i < this.subCount; i++){
13938             s[i].buffer = [];
13939         }
13940         return this;
13941     },
13942
13943     applyTemplate : function(values){
13944         var s = this.subs;
13945         var replaceIndex = -1;
13946         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13947             return s[++replaceIndex].buffer.join("");
13948         });
13949         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13950     },
13951
13952     apply : function(){
13953         return this.applyTemplate.apply(this, arguments);
13954     },
13955
13956     compile : function(){return this;}
13957 });
13958
13959 /**
13960  * Alias for fill().
13961  * @method
13962  */
13963 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13964  /**
13965  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13966  * var tpl = Roo.MasterTemplate.from('element-id');
13967  * @param {String/HTMLElement} el
13968  * @param {Object} config
13969  * @static
13970  */
13971 Roo.MasterTemplate.from = function(el, config){
13972     el = Roo.getDom(el);
13973     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13974 };/*
13975  * Based on:
13976  * Ext JS Library 1.1.1
13977  * Copyright(c) 2006-2007, Ext JS, LLC.
13978  *
13979  * Originally Released Under LGPL - original licence link has changed is not relivant.
13980  *
13981  * Fork - LGPL
13982  * <script type="text/javascript">
13983  */
13984
13985  
13986 /**
13987  * @class Roo.util.CSS
13988  * Utility class for manipulating CSS rules
13989  * @singleton
13990  */
13991 Roo.util.CSS = function(){
13992         var rules = null;
13993         var doc = document;
13994
13995     var camelRe = /(-[a-z])/gi;
13996     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13997
13998    return {
13999    /**
14000     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14001     * tag and appended to the HEAD of the document.
14002     * @param {String|Object} cssText The text containing the css rules
14003     * @param {String} id An id to add to the stylesheet for later removal
14004     * @return {StyleSheet}
14005     */
14006     createStyleSheet : function(cssText, id){
14007         var ss;
14008         var head = doc.getElementsByTagName("head")[0];
14009         var nrules = doc.createElement("style");
14010         nrules.setAttribute("type", "text/css");
14011         if(id){
14012             nrules.setAttribute("id", id);
14013         }
14014         if (typeof(cssText) != 'string') {
14015             // support object maps..
14016             // not sure if this a good idea.. 
14017             // perhaps it should be merged with the general css handling
14018             // and handle js style props.
14019             var cssTextNew = [];
14020             for(var n in cssText) {
14021                 var citems = [];
14022                 for(var k in cssText[n]) {
14023                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14024                 }
14025                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14026                 
14027             }
14028             cssText = cssTextNew.join("\n");
14029             
14030         }
14031        
14032        
14033        if(Roo.isIE){
14034            head.appendChild(nrules);
14035            ss = nrules.styleSheet;
14036            ss.cssText = cssText;
14037        }else{
14038            try{
14039                 nrules.appendChild(doc.createTextNode(cssText));
14040            }catch(e){
14041                nrules.cssText = cssText; 
14042            }
14043            head.appendChild(nrules);
14044            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14045        }
14046        this.cacheStyleSheet(ss);
14047        return ss;
14048    },
14049
14050    /**
14051     * Removes a style or link tag by id
14052     * @param {String} id The id of the tag
14053     */
14054    removeStyleSheet : function(id){
14055        var existing = doc.getElementById(id);
14056        if(existing){
14057            existing.parentNode.removeChild(existing);
14058        }
14059    },
14060
14061    /**
14062     * Dynamically swaps an existing stylesheet reference for a new one
14063     * @param {String} id The id of an existing link tag to remove
14064     * @param {String} url The href of the new stylesheet to include
14065     */
14066    swapStyleSheet : function(id, url){
14067        this.removeStyleSheet(id);
14068        var ss = doc.createElement("link");
14069        ss.setAttribute("rel", "stylesheet");
14070        ss.setAttribute("type", "text/css");
14071        ss.setAttribute("id", id);
14072        ss.setAttribute("href", url);
14073        doc.getElementsByTagName("head")[0].appendChild(ss);
14074    },
14075    
14076    /**
14077     * Refresh the rule cache if you have dynamically added stylesheets
14078     * @return {Object} An object (hash) of rules indexed by selector
14079     */
14080    refreshCache : function(){
14081        return this.getRules(true);
14082    },
14083
14084    // private
14085    cacheStyleSheet : function(stylesheet){
14086        if(!rules){
14087            rules = {};
14088        }
14089        try{// try catch for cross domain access issue
14090            var ssRules = stylesheet.cssRules || stylesheet.rules;
14091            for(var j = ssRules.length-1; j >= 0; --j){
14092                rules[ssRules[j].selectorText] = ssRules[j];
14093            }
14094        }catch(e){}
14095    },
14096    
14097    /**
14098     * Gets all css rules for the document
14099     * @param {Boolean} refreshCache true to refresh the internal cache
14100     * @return {Object} An object (hash) of rules indexed by selector
14101     */
14102    getRules : function(refreshCache){
14103                 if(rules == null || refreshCache){
14104                         rules = {};
14105                         var ds = doc.styleSheets;
14106                         for(var i =0, len = ds.length; i < len; i++){
14107                             try{
14108                         this.cacheStyleSheet(ds[i]);
14109                     }catch(e){} 
14110                 }
14111                 }
14112                 return rules;
14113         },
14114         
14115         /**
14116     * Gets an an individual CSS rule by selector(s)
14117     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14118     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14119     * @return {CSSRule} The CSS rule or null if one is not found
14120     */
14121    getRule : function(selector, refreshCache){
14122                 var rs = this.getRules(refreshCache);
14123                 if(!(selector instanceof Array)){
14124                     return rs[selector];
14125                 }
14126                 for(var i = 0; i < selector.length; i++){
14127                         if(rs[selector[i]]){
14128                                 return rs[selector[i]];
14129                         }
14130                 }
14131                 return null;
14132         },
14133         
14134         
14135         /**
14136     * Updates a rule property
14137     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14138     * @param {String} property The css property
14139     * @param {String} value The new value for the property
14140     * @return {Boolean} true If a rule was found and updated
14141     */
14142    updateRule : function(selector, property, value){
14143                 if(!(selector instanceof Array)){
14144                         var rule = this.getRule(selector);
14145                         if(rule){
14146                                 rule.style[property.replace(camelRe, camelFn)] = value;
14147                                 return true;
14148                         }
14149                 }else{
14150                         for(var i = 0; i < selector.length; i++){
14151                                 if(this.updateRule(selector[i], property, value)){
14152                                         return true;
14153                                 }
14154                         }
14155                 }
14156                 return false;
14157         }
14158    };   
14159 }();/*
14160  * Based on:
14161  * Ext JS Library 1.1.1
14162  * Copyright(c) 2006-2007, Ext JS, LLC.
14163  *
14164  * Originally Released Under LGPL - original licence link has changed is not relivant.
14165  *
14166  * Fork - LGPL
14167  * <script type="text/javascript">
14168  */
14169
14170  
14171
14172 /**
14173  * @class Roo.util.ClickRepeater
14174  * @extends Roo.util.Observable
14175  * 
14176  * A wrapper class which can be applied to any element. Fires a "click" event while the
14177  * mouse is pressed. The interval between firings may be specified in the config but
14178  * defaults to 10 milliseconds.
14179  * 
14180  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14181  * 
14182  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14183  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14184  * Similar to an autorepeat key delay.
14185  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14186  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14187  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14188  *           "interval" and "delay" are ignored. "immediate" is honored.
14189  * @cfg {Boolean} preventDefault True to prevent the default click event
14190  * @cfg {Boolean} stopDefault True to stop the default click event
14191  * 
14192  * @history
14193  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14194  *     2007-02-02 jvs Renamed to ClickRepeater
14195  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14196  *
14197  *  @constructor
14198  * @param {String/HTMLElement/Element} el The element to listen on
14199  * @param {Object} config
14200  **/
14201 Roo.util.ClickRepeater = function(el, config)
14202 {
14203     this.el = Roo.get(el);
14204     this.el.unselectable();
14205
14206     Roo.apply(this, config);
14207
14208     this.addEvents({
14209     /**
14210      * @event mousedown
14211      * Fires when the mouse button is depressed.
14212      * @param {Roo.util.ClickRepeater} this
14213      */
14214         "mousedown" : true,
14215     /**
14216      * @event click
14217      * Fires on a specified interval during the time the element is pressed.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "click" : true,
14221     /**
14222      * @event mouseup
14223      * Fires when the mouse key is released.
14224      * @param {Roo.util.ClickRepeater} this
14225      */
14226         "mouseup" : true
14227     });
14228
14229     this.el.on("mousedown", this.handleMouseDown, this);
14230     if(this.preventDefault || this.stopDefault){
14231         this.el.on("click", function(e){
14232             if(this.preventDefault){
14233                 e.preventDefault();
14234             }
14235             if(this.stopDefault){
14236                 e.stopEvent();
14237             }
14238         }, this);
14239     }
14240
14241     // allow inline handler
14242     if(this.handler){
14243         this.on("click", this.handler,  this.scope || this);
14244     }
14245
14246     Roo.util.ClickRepeater.superclass.constructor.call(this);
14247 };
14248
14249 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14250     interval : 20,
14251     delay: 250,
14252     preventDefault : true,
14253     stopDefault : false,
14254     timer : 0,
14255
14256     // private
14257     handleMouseDown : function(){
14258         clearTimeout(this.timer);
14259         this.el.blur();
14260         if(this.pressClass){
14261             this.el.addClass(this.pressClass);
14262         }
14263         this.mousedownTime = new Date();
14264
14265         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14266         this.el.on("mouseout", this.handleMouseOut, this);
14267
14268         this.fireEvent("mousedown", this);
14269         this.fireEvent("click", this);
14270         
14271         this.timer = this.click.defer(this.delay || this.interval, this);
14272     },
14273
14274     // private
14275     click : function(){
14276         this.fireEvent("click", this);
14277         this.timer = this.click.defer(this.getInterval(), this);
14278     },
14279
14280     // private
14281     getInterval: function(){
14282         if(!this.accelerate){
14283             return this.interval;
14284         }
14285         var pressTime = this.mousedownTime.getElapsed();
14286         if(pressTime < 500){
14287             return 400;
14288         }else if(pressTime < 1700){
14289             return 320;
14290         }else if(pressTime < 2600){
14291             return 250;
14292         }else if(pressTime < 3500){
14293             return 180;
14294         }else if(pressTime < 4400){
14295             return 140;
14296         }else if(pressTime < 5300){
14297             return 80;
14298         }else if(pressTime < 6200){
14299             return 50;
14300         }else{
14301             return 10;
14302         }
14303     },
14304
14305     // private
14306     handleMouseOut : function(){
14307         clearTimeout(this.timer);
14308         if(this.pressClass){
14309             this.el.removeClass(this.pressClass);
14310         }
14311         this.el.on("mouseover", this.handleMouseReturn, this);
14312     },
14313
14314     // private
14315     handleMouseReturn : function(){
14316         this.el.un("mouseover", this.handleMouseReturn);
14317         if(this.pressClass){
14318             this.el.addClass(this.pressClass);
14319         }
14320         this.click();
14321     },
14322
14323     // private
14324     handleMouseUp : function(){
14325         clearTimeout(this.timer);
14326         this.el.un("mouseover", this.handleMouseReturn);
14327         this.el.un("mouseout", this.handleMouseOut);
14328         Roo.get(document).un("mouseup", this.handleMouseUp);
14329         this.el.removeClass(this.pressClass);
14330         this.fireEvent("mouseup", this);
14331     }
14332 });/*
14333  * Based on:
14334  * Ext JS Library 1.1.1
14335  * Copyright(c) 2006-2007, Ext JS, LLC.
14336  *
14337  * Originally Released Under LGPL - original licence link has changed is not relivant.
14338  *
14339  * Fork - LGPL
14340  * <script type="text/javascript">
14341  */
14342
14343  
14344 /**
14345  * @class Roo.KeyNav
14346  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14347  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14348  * way to implement custom navigation schemes for any UI component.</p>
14349  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14350  * pageUp, pageDown, del, home, end.  Usage:</p>
14351  <pre><code>
14352 var nav = new Roo.KeyNav("my-element", {
14353     "left" : function(e){
14354         this.moveLeft(e.ctrlKey);
14355     },
14356     "right" : function(e){
14357         this.moveRight(e.ctrlKey);
14358     },
14359     "enter" : function(e){
14360         this.save();
14361     },
14362     scope : this
14363 });
14364 </code></pre>
14365  * @constructor
14366  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14367  * @param {Object} config The config
14368  */
14369 Roo.KeyNav = function(el, config){
14370     this.el = Roo.get(el);
14371     Roo.apply(this, config);
14372     if(!this.disabled){
14373         this.disabled = true;
14374         this.enable();
14375     }
14376 };
14377
14378 Roo.KeyNav.prototype = {
14379     /**
14380      * @cfg {Boolean} disabled
14381      * True to disable this KeyNav instance (defaults to false)
14382      */
14383     disabled : false,
14384     /**
14385      * @cfg {String} defaultEventAction
14386      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14387      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14388      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14389      */
14390     defaultEventAction: "stopEvent",
14391     /**
14392      * @cfg {Boolean} forceKeyDown
14393      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14394      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14395      * handle keydown instead of keypress.
14396      */
14397     forceKeyDown : false,
14398
14399     // private
14400     prepareEvent : function(e){
14401         var k = e.getKey();
14402         var h = this.keyToHandler[k];
14403         //if(h && this[h]){
14404         //    e.stopPropagation();
14405         //}
14406         if(Roo.isSafari && h && k >= 37 && k <= 40){
14407             e.stopEvent();
14408         }
14409     },
14410
14411     // private
14412     relay : function(e){
14413         var k = e.getKey();
14414         var h = this.keyToHandler[k];
14415         if(h && this[h]){
14416             if(this.doRelay(e, this[h], h) !== true){
14417                 e[this.defaultEventAction]();
14418             }
14419         }
14420     },
14421
14422     // private
14423     doRelay : function(e, h, hname){
14424         return h.call(this.scope || this, e);
14425     },
14426
14427     // possible handlers
14428     enter : false,
14429     left : false,
14430     right : false,
14431     up : false,
14432     down : false,
14433     tab : false,
14434     esc : false,
14435     pageUp : false,
14436     pageDown : false,
14437     del : false,
14438     home : false,
14439     end : false,
14440
14441     // quick lookup hash
14442     keyToHandler : {
14443         37 : "left",
14444         39 : "right",
14445         38 : "up",
14446         40 : "down",
14447         33 : "pageUp",
14448         34 : "pageDown",
14449         46 : "del",
14450         36 : "home",
14451         35 : "end",
14452         13 : "enter",
14453         27 : "esc",
14454         9  : "tab"
14455     },
14456
14457         /**
14458          * Enable this KeyNav
14459          */
14460         enable: function(){
14461                 if(this.disabled){
14462             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14463             // the EventObject will normalize Safari automatically
14464             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14465                 this.el.on("keydown", this.relay,  this);
14466             }else{
14467                 this.el.on("keydown", this.prepareEvent,  this);
14468                 this.el.on("keypress", this.relay,  this);
14469             }
14470                     this.disabled = false;
14471                 }
14472         },
14473
14474         /**
14475          * Disable this KeyNav
14476          */
14477         disable: function(){
14478                 if(!this.disabled){
14479                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14480                 this.el.un("keydown", this.relay);
14481             }else{
14482                 this.el.un("keydown", this.prepareEvent);
14483                 this.el.un("keypress", this.relay);
14484             }
14485                     this.disabled = true;
14486                 }
14487         }
14488 };/*
14489  * Based on:
14490  * Ext JS Library 1.1.1
14491  * Copyright(c) 2006-2007, Ext JS, LLC.
14492  *
14493  * Originally Released Under LGPL - original licence link has changed is not relivant.
14494  *
14495  * Fork - LGPL
14496  * <script type="text/javascript">
14497  */
14498
14499  
14500 /**
14501  * @class Roo.KeyMap
14502  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14503  * The constructor accepts the same config object as defined by {@link #addBinding}.
14504  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14505  * combination it will call the function with this signature (if the match is a multi-key
14506  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14507  * A KeyMap can also handle a string representation of keys.<br />
14508  * Usage:
14509  <pre><code>
14510 // map one key by key code
14511 var map = new Roo.KeyMap("my-element", {
14512     key: 13, // or Roo.EventObject.ENTER
14513     fn: myHandler,
14514     scope: myObject
14515 });
14516
14517 // map multiple keys to one action by string
14518 var map = new Roo.KeyMap("my-element", {
14519     key: "a\r\n\t",
14520     fn: myHandler,
14521     scope: myObject
14522 });
14523
14524 // map multiple keys to multiple actions by strings and array of codes
14525 var map = new Roo.KeyMap("my-element", [
14526     {
14527         key: [10,13],
14528         fn: function(){ alert("Return was pressed"); }
14529     }, {
14530         key: "abc",
14531         fn: function(){ alert('a, b or c was pressed'); }
14532     }, {
14533         key: "\t",
14534         ctrl:true,
14535         shift:true,
14536         fn: function(){ alert('Control + shift + tab was pressed.'); }
14537     }
14538 ]);
14539 </code></pre>
14540  * <b>Note: A KeyMap starts enabled</b>
14541  * @constructor
14542  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14543  * @param {Object} config The config (see {@link #addBinding})
14544  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14545  */
14546 Roo.KeyMap = function(el, config, eventName){
14547     this.el  = Roo.get(el);
14548     this.eventName = eventName || "keydown";
14549     this.bindings = [];
14550     if(config){
14551         this.addBinding(config);
14552     }
14553     this.enable();
14554 };
14555
14556 Roo.KeyMap.prototype = {
14557     /**
14558      * True to stop the event from bubbling and prevent the default browser action if the
14559      * key was handled by the KeyMap (defaults to false)
14560      * @type Boolean
14561      */
14562     stopEvent : false,
14563
14564     /**
14565      * Add a new binding to this KeyMap. The following config object properties are supported:
14566      * <pre>
14567 Property    Type             Description
14568 ----------  ---------------  ----------------------------------------------------------------------
14569 key         String/Array     A single keycode or an array of keycodes to handle
14570 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14571 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14572 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14573 fn          Function         The function to call when KeyMap finds the expected key combination
14574 scope       Object           The scope of the callback function
14575 </pre>
14576      *
14577      * Usage:
14578      * <pre><code>
14579 // Create a KeyMap
14580 var map = new Roo.KeyMap(document, {
14581     key: Roo.EventObject.ENTER,
14582     fn: handleKey,
14583     scope: this
14584 });
14585
14586 //Add a new binding to the existing KeyMap later
14587 map.addBinding({
14588     key: 'abc',
14589     shift: true,
14590     fn: handleKey,
14591     scope: this
14592 });
14593 </code></pre>
14594      * @param {Object/Array} config A single KeyMap config or an array of configs
14595      */
14596         addBinding : function(config){
14597         if(config instanceof Array){
14598             for(var i = 0, len = config.length; i < len; i++){
14599                 this.addBinding(config[i]);
14600             }
14601             return;
14602         }
14603         var keyCode = config.key,
14604             shift = config.shift, 
14605             ctrl = config.ctrl, 
14606             alt = config.alt,
14607             fn = config.fn,
14608             scope = config.scope;
14609         if(typeof keyCode == "string"){
14610             var ks = [];
14611             var keyString = keyCode.toUpperCase();
14612             for(var j = 0, len = keyString.length; j < len; j++){
14613                 ks.push(keyString.charCodeAt(j));
14614             }
14615             keyCode = ks;
14616         }
14617         var keyArray = keyCode instanceof Array;
14618         var handler = function(e){
14619             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14620                 var k = e.getKey();
14621                 if(keyArray){
14622                     for(var i = 0, len = keyCode.length; i < len; i++){
14623                         if(keyCode[i] == k){
14624                           if(this.stopEvent){
14625                               e.stopEvent();
14626                           }
14627                           fn.call(scope || window, k, e);
14628                           return;
14629                         }
14630                     }
14631                 }else{
14632                     if(k == keyCode){
14633                         if(this.stopEvent){
14634                            e.stopEvent();
14635                         }
14636                         fn.call(scope || window, k, e);
14637                     }
14638                 }
14639             }
14640         };
14641         this.bindings.push(handler);  
14642         },
14643
14644     /**
14645      * Shorthand for adding a single key listener
14646      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14647      * following options:
14648      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14649      * @param {Function} fn The function to call
14650      * @param {Object} scope (optional) The scope of the function
14651      */
14652     on : function(key, fn, scope){
14653         var keyCode, shift, ctrl, alt;
14654         if(typeof key == "object" && !(key instanceof Array)){
14655             keyCode = key.key;
14656             shift = key.shift;
14657             ctrl = key.ctrl;
14658             alt = key.alt;
14659         }else{
14660             keyCode = key;
14661         }
14662         this.addBinding({
14663             key: keyCode,
14664             shift: shift,
14665             ctrl: ctrl,
14666             alt: alt,
14667             fn: fn,
14668             scope: scope
14669         })
14670     },
14671
14672     // private
14673     handleKeyDown : function(e){
14674             if(this.enabled){ //just in case
14675             var b = this.bindings;
14676             for(var i = 0, len = b.length; i < len; i++){
14677                 b[i].call(this, e);
14678             }
14679             }
14680         },
14681         
14682         /**
14683          * Returns true if this KeyMap is enabled
14684          * @return {Boolean} 
14685          */
14686         isEnabled : function(){
14687             return this.enabled;  
14688         },
14689         
14690         /**
14691          * Enables this KeyMap
14692          */
14693         enable: function(){
14694                 if(!this.enabled){
14695                     this.el.on(this.eventName, this.handleKeyDown, this);
14696                     this.enabled = true;
14697                 }
14698         },
14699
14700         /**
14701          * Disable this KeyMap
14702          */
14703         disable: function(){
14704                 if(this.enabled){
14705                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14706                     this.enabled = false;
14707                 }
14708         }
14709 };/*
14710  * Based on:
14711  * Ext JS Library 1.1.1
14712  * Copyright(c) 2006-2007, Ext JS, LLC.
14713  *
14714  * Originally Released Under LGPL - original licence link has changed is not relivant.
14715  *
14716  * Fork - LGPL
14717  * <script type="text/javascript">
14718  */
14719
14720  
14721 /**
14722  * @class Roo.util.TextMetrics
14723  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14724  * wide, in pixels, a given block of text will be.
14725  * @singleton
14726  */
14727 Roo.util.TextMetrics = function(){
14728     var shared;
14729     return {
14730         /**
14731          * Measures the size of the specified text
14732          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14733          * that can affect the size of the rendered text
14734          * @param {String} text The text to measure
14735          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14736          * in order to accurately measure the text height
14737          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14738          */
14739         measure : function(el, text, fixedWidth){
14740             if(!shared){
14741                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14742             }
14743             shared.bind(el);
14744             shared.setFixedWidth(fixedWidth || 'auto');
14745             return shared.getSize(text);
14746         },
14747
14748         /**
14749          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14750          * the overhead of multiple calls to initialize the style properties on each measurement.
14751          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14752          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14753          * in order to accurately measure the text height
14754          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14755          */
14756         createInstance : function(el, fixedWidth){
14757             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14758         }
14759     };
14760 }();
14761
14762  
14763
14764 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14765     var ml = new Roo.Element(document.createElement('div'));
14766     document.body.appendChild(ml.dom);
14767     ml.position('absolute');
14768     ml.setLeftTop(-1000, -1000);
14769     ml.hide();
14770
14771     if(fixedWidth){
14772         ml.setWidth(fixedWidth);
14773     }
14774      
14775     var instance = {
14776         /**
14777          * Returns the size of the specified text based on the internal element's style and width properties
14778          * @memberOf Roo.util.TextMetrics.Instance#
14779          * @param {String} text The text to measure
14780          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14781          */
14782         getSize : function(text){
14783             ml.update(text);
14784             var s = ml.getSize();
14785             ml.update('');
14786             return s;
14787         },
14788
14789         /**
14790          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14791          * that can affect the size of the rendered text
14792          * @memberOf Roo.util.TextMetrics.Instance#
14793          * @param {String/HTMLElement} el The element, dom node or id
14794          */
14795         bind : function(el){
14796             ml.setStyle(
14797                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14798             );
14799         },
14800
14801         /**
14802          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14803          * to set a fixed width in order to accurately measure the text height.
14804          * @memberOf Roo.util.TextMetrics.Instance#
14805          * @param {Number} width The width to set on the element
14806          */
14807         setFixedWidth : function(width){
14808             ml.setWidth(width);
14809         },
14810
14811         /**
14812          * Returns the measured width of the specified text
14813          * @memberOf Roo.util.TextMetrics.Instance#
14814          * @param {String} text The text to measure
14815          * @return {Number} width The width in pixels
14816          */
14817         getWidth : function(text){
14818             ml.dom.style.width = 'auto';
14819             return this.getSize(text).width;
14820         },
14821
14822         /**
14823          * Returns the measured height of the specified text.  For multiline text, be sure to call
14824          * {@link #setFixedWidth} if necessary.
14825          * @memberOf Roo.util.TextMetrics.Instance#
14826          * @param {String} text The text to measure
14827          * @return {Number} height The height in pixels
14828          */
14829         getHeight : function(text){
14830             return this.getSize(text).height;
14831         }
14832     };
14833
14834     instance.bind(bindTo);
14835
14836     return instance;
14837 };
14838
14839 // backwards compat
14840 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14841  * Based on:
14842  * Ext JS Library 1.1.1
14843  * Copyright(c) 2006-2007, Ext JS, LLC.
14844  *
14845  * Originally Released Under LGPL - original licence link has changed is not relivant.
14846  *
14847  * Fork - LGPL
14848  * <script type="text/javascript">
14849  */
14850
14851 /**
14852  * @class Roo.state.Provider
14853  * Abstract base class for state provider implementations. This class provides methods
14854  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14855  * Provider interface.
14856  */
14857 Roo.state.Provider = function(){
14858     /**
14859      * @event statechange
14860      * Fires when a state change occurs.
14861      * @param {Provider} this This state provider
14862      * @param {String} key The state key which was changed
14863      * @param {String} value The encoded value for the state
14864      */
14865     this.addEvents({
14866         "statechange": true
14867     });
14868     this.state = {};
14869     Roo.state.Provider.superclass.constructor.call(this);
14870 };
14871 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14872     /**
14873      * Returns the current value for a key
14874      * @param {String} name The key name
14875      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14876      * @return {Mixed} The state data
14877      */
14878     get : function(name, defaultValue){
14879         return typeof this.state[name] == "undefined" ?
14880             defaultValue : this.state[name];
14881     },
14882     
14883     /**
14884      * Clears a value from the state
14885      * @param {String} name The key name
14886      */
14887     clear : function(name){
14888         delete this.state[name];
14889         this.fireEvent("statechange", this, name, null);
14890     },
14891     
14892     /**
14893      * Sets the value for a key
14894      * @param {String} name The key name
14895      * @param {Mixed} value The value to set
14896      */
14897     set : function(name, value){
14898         this.state[name] = value;
14899         this.fireEvent("statechange", this, name, value);
14900     },
14901     
14902     /**
14903      * Decodes a string previously encoded with {@link #encodeValue}.
14904      * @param {String} value The value to decode
14905      * @return {Mixed} The decoded value
14906      */
14907     decodeValue : function(cookie){
14908         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14909         var matches = re.exec(unescape(cookie));
14910         if(!matches || !matches[1]) {
14911             return; // non state cookie
14912         }
14913         var type = matches[1];
14914         var v = matches[2];
14915         switch(type){
14916             case "n":
14917                 return parseFloat(v);
14918             case "d":
14919                 return new Date(Date.parse(v));
14920             case "b":
14921                 return (v == "1");
14922             case "a":
14923                 var all = [];
14924                 var values = v.split("^");
14925                 for(var i = 0, len = values.length; i < len; i++){
14926                     all.push(this.decodeValue(values[i]));
14927                 }
14928                 return all;
14929            case "o":
14930                 var all = {};
14931                 var values = v.split("^");
14932                 for(var i = 0, len = values.length; i < len; i++){
14933                     var kv = values[i].split("=");
14934                     all[kv[0]] = this.decodeValue(kv[1]);
14935                 }
14936                 return all;
14937            default:
14938                 return v;
14939         }
14940     },
14941     
14942     /**
14943      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14944      * @param {Mixed} value The value to encode
14945      * @return {String} The encoded value
14946      */
14947     encodeValue : function(v){
14948         var enc;
14949         if(typeof v == "number"){
14950             enc = "n:" + v;
14951         }else if(typeof v == "boolean"){
14952             enc = "b:" + (v ? "1" : "0");
14953         }else if(v instanceof Date){
14954             enc = "d:" + v.toGMTString();
14955         }else if(v instanceof Array){
14956             var flat = "";
14957             for(var i = 0, len = v.length; i < len; i++){
14958                 flat += this.encodeValue(v[i]);
14959                 if(i != len-1) {
14960                     flat += "^";
14961                 }
14962             }
14963             enc = "a:" + flat;
14964         }else if(typeof v == "object"){
14965             var flat = "";
14966             for(var key in v){
14967                 if(typeof v[key] != "function"){
14968                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14969                 }
14970             }
14971             enc = "o:" + flat.substring(0, flat.length-1);
14972         }else{
14973             enc = "s:" + v;
14974         }
14975         return escape(enc);        
14976     }
14977 });
14978
14979 /*
14980  * Based on:
14981  * Ext JS Library 1.1.1
14982  * Copyright(c) 2006-2007, Ext JS, LLC.
14983  *
14984  * Originally Released Under LGPL - original licence link has changed is not relivant.
14985  *
14986  * Fork - LGPL
14987  * <script type="text/javascript">
14988  */
14989 /**
14990  * @class Roo.state.Manager
14991  * This is the global state manager. By default all components that are "state aware" check this class
14992  * for state information if you don't pass them a custom state provider. In order for this class
14993  * to be useful, it must be initialized with a provider when your application initializes.
14994  <pre><code>
14995 // in your initialization function
14996 init : function(){
14997    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14998    ...
14999    // supposed you have a {@link Roo.BorderLayout}
15000    var layout = new Roo.BorderLayout(...);
15001    layout.restoreState();
15002    // or a {Roo.BasicDialog}
15003    var dialog = new Roo.BasicDialog(...);
15004    dialog.restoreState();
15005  </code></pre>
15006  * @singleton
15007  */
15008 Roo.state.Manager = function(){
15009     var provider = new Roo.state.Provider();
15010     
15011     return {
15012         /**
15013          * Configures the default state provider for your application
15014          * @param {Provider} stateProvider The state provider to set
15015          */
15016         setProvider : function(stateProvider){
15017             provider = stateProvider;
15018         },
15019         
15020         /**
15021          * Returns the current value for a key
15022          * @param {String} name The key name
15023          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15024          * @return {Mixed} The state data
15025          */
15026         get : function(key, defaultValue){
15027             return provider.get(key, defaultValue);
15028         },
15029         
15030         /**
15031          * Sets the value for a key
15032          * @param {String} name The key name
15033          * @param {Mixed} value The state data
15034          */
15035          set : function(key, value){
15036             provider.set(key, value);
15037         },
15038         
15039         /**
15040          * Clears a value from the state
15041          * @param {String} name The key name
15042          */
15043         clear : function(key){
15044             provider.clear(key);
15045         },
15046         
15047         /**
15048          * Gets the currently configured state provider
15049          * @return {Provider} The state provider
15050          */
15051         getProvider : function(){
15052             return provider;
15053         }
15054     };
15055 }();
15056 /*
15057  * Based on:
15058  * Ext JS Library 1.1.1
15059  * Copyright(c) 2006-2007, Ext JS, LLC.
15060  *
15061  * Originally Released Under LGPL - original licence link has changed is not relivant.
15062  *
15063  * Fork - LGPL
15064  * <script type="text/javascript">
15065  */
15066 /**
15067  * @class Roo.state.CookieProvider
15068  * @extends Roo.state.Provider
15069  * The default Provider implementation which saves state via cookies.
15070  * <br />Usage:
15071  <pre><code>
15072    var cp = new Roo.state.CookieProvider({
15073        path: "/cgi-bin/",
15074        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15075        domain: "roojs.com"
15076    })
15077    Roo.state.Manager.setProvider(cp);
15078  </code></pre>
15079  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15080  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15081  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15082  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15083  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15084  * domain the page is running on including the 'www' like 'www.roojs.com')
15085  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15086  * @constructor
15087  * Create a new CookieProvider
15088  * @param {Object} config The configuration object
15089  */
15090 Roo.state.CookieProvider = function(config){
15091     Roo.state.CookieProvider.superclass.constructor.call(this);
15092     this.path = "/";
15093     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15094     this.domain = null;
15095     this.secure = false;
15096     Roo.apply(this, config);
15097     this.state = this.readCookies();
15098 };
15099
15100 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15101     // private
15102     set : function(name, value){
15103         if(typeof value == "undefined" || value === null){
15104             this.clear(name);
15105             return;
15106         }
15107         this.setCookie(name, value);
15108         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15109     },
15110
15111     // private
15112     clear : function(name){
15113         this.clearCookie(name);
15114         Roo.state.CookieProvider.superclass.clear.call(this, name);
15115     },
15116
15117     // private
15118     readCookies : function(){
15119         var cookies = {};
15120         var c = document.cookie + ";";
15121         var re = /\s?(.*?)=(.*?);/g;
15122         var matches;
15123         while((matches = re.exec(c)) != null){
15124             var name = matches[1];
15125             var value = matches[2];
15126             if(name && name.substring(0,3) == "ys-"){
15127                 cookies[name.substr(3)] = this.decodeValue(value);
15128             }
15129         }
15130         return cookies;
15131     },
15132
15133     // private
15134     setCookie : function(name, value){
15135         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15136            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15137            ((this.path == null) ? "" : ("; path=" + this.path)) +
15138            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15139            ((this.secure == true) ? "; secure" : "");
15140     },
15141
15142     // private
15143     clearCookie : function(name){
15144         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15145            ((this.path == null) ? "" : ("; path=" + this.path)) +
15146            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15147            ((this.secure == true) ? "; secure" : "");
15148     }
15149 });/*
15150  * Based on:
15151  * Ext JS Library 1.1.1
15152  * Copyright(c) 2006-2007, Ext JS, LLC.
15153  *
15154  * Originally Released Under LGPL - original licence link has changed is not relivant.
15155  *
15156  * Fork - LGPL
15157  * <script type="text/javascript">
15158  */
15159  
15160
15161 /**
15162  * @class Roo.ComponentMgr
15163  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15164  * @singleton
15165  */
15166 Roo.ComponentMgr = function(){
15167     var all = new Roo.util.MixedCollection();
15168
15169     return {
15170         /**
15171          * Registers a component.
15172          * @param {Roo.Component} c The component
15173          */
15174         register : function(c){
15175             all.add(c);
15176         },
15177
15178         /**
15179          * Unregisters a component.
15180          * @param {Roo.Component} c The component
15181          */
15182         unregister : function(c){
15183             all.remove(c);
15184         },
15185
15186         /**
15187          * Returns a component by id
15188          * @param {String} id The component id
15189          */
15190         get : function(id){
15191             return all.get(id);
15192         },
15193
15194         /**
15195          * Registers a function that will be called when a specified component is added to ComponentMgr
15196          * @param {String} id The component id
15197          * @param {Funtction} fn The callback function
15198          * @param {Object} scope The scope of the callback
15199          */
15200         onAvailable : function(id, fn, scope){
15201             all.on("add", function(index, o){
15202                 if(o.id == id){
15203                     fn.call(scope || o, o);
15204                     all.un("add", fn, scope);
15205                 }
15206             });
15207         }
15208     };
15209 }();/*
15210  * Based on:
15211  * Ext JS Library 1.1.1
15212  * Copyright(c) 2006-2007, Ext JS, LLC.
15213  *
15214  * Originally Released Under LGPL - original licence link has changed is not relivant.
15215  *
15216  * Fork - LGPL
15217  * <script type="text/javascript">
15218  */
15219  
15220 /**
15221  * @class Roo.Component
15222  * @extends Roo.util.Observable
15223  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15224  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15225  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15226  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15227  * All visual components (widgets) that require rendering into a layout should subclass Component.
15228  * @constructor
15229  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15230  * 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
15231  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15232  */
15233 Roo.Component = function(config){
15234     config = config || {};
15235     if(config.tagName || config.dom || typeof config == "string"){ // element object
15236         config = {el: config, id: config.id || config};
15237     }
15238     this.initialConfig = config;
15239
15240     Roo.apply(this, config);
15241     this.addEvents({
15242         /**
15243          * @event disable
15244          * Fires after the component is disabled.
15245              * @param {Roo.Component} this
15246              */
15247         disable : true,
15248         /**
15249          * @event enable
15250          * Fires after the component is enabled.
15251              * @param {Roo.Component} this
15252              */
15253         enable : true,
15254         /**
15255          * @event beforeshow
15256          * Fires before the component is shown.  Return false to stop the show.
15257              * @param {Roo.Component} this
15258              */
15259         beforeshow : true,
15260         /**
15261          * @event show
15262          * Fires after the component is shown.
15263              * @param {Roo.Component} this
15264              */
15265         show : true,
15266         /**
15267          * @event beforehide
15268          * Fires before the component is hidden. Return false to stop the hide.
15269              * @param {Roo.Component} this
15270              */
15271         beforehide : true,
15272         /**
15273          * @event hide
15274          * Fires after the component is hidden.
15275              * @param {Roo.Component} this
15276              */
15277         hide : true,
15278         /**
15279          * @event beforerender
15280          * Fires before the component is rendered. Return false to stop the render.
15281              * @param {Roo.Component} this
15282              */
15283         beforerender : true,
15284         /**
15285          * @event render
15286          * Fires after the component is rendered.
15287              * @param {Roo.Component} this
15288              */
15289         render : true,
15290         /**
15291          * @event beforedestroy
15292          * Fires before the component is destroyed. Return false to stop the destroy.
15293              * @param {Roo.Component} this
15294              */
15295         beforedestroy : true,
15296         /**
15297          * @event destroy
15298          * Fires after the component is destroyed.
15299              * @param {Roo.Component} this
15300              */
15301         destroy : true
15302     });
15303     if(!this.id){
15304         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15305     }
15306     Roo.ComponentMgr.register(this);
15307     Roo.Component.superclass.constructor.call(this);
15308     this.initComponent();
15309     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15310         this.render(this.renderTo);
15311         delete this.renderTo;
15312     }
15313 };
15314
15315 /** @private */
15316 Roo.Component.AUTO_ID = 1000;
15317
15318 Roo.extend(Roo.Component, Roo.util.Observable, {
15319     /**
15320      * @scope Roo.Component.prototype
15321      * @type {Boolean}
15322      * true if this component is hidden. Read-only.
15323      */
15324     hidden : false,
15325     /**
15326      * @type {Boolean}
15327      * true if this component is disabled. Read-only.
15328      */
15329     disabled : false,
15330     /**
15331      * @type {Boolean}
15332      * true if this component has been rendered. Read-only.
15333      */
15334     rendered : false,
15335     
15336     /** @cfg {String} disableClass
15337      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15338      */
15339     disabledClass : "x-item-disabled",
15340         /** @cfg {Boolean} allowDomMove
15341          * Whether the component can move the Dom node when rendering (defaults to true).
15342          */
15343     allowDomMove : true,
15344     /** @cfg {String} hideMode (display|visibility)
15345      * How this component should hidden. Supported values are
15346      * "visibility" (css visibility), "offsets" (negative offset position) and
15347      * "display" (css display) - defaults to "display".
15348      */
15349     hideMode: 'display',
15350
15351     /** @private */
15352     ctype : "Roo.Component",
15353
15354     /**
15355      * @cfg {String} actionMode 
15356      * which property holds the element that used for  hide() / show() / disable() / enable()
15357      * default is 'el' 
15358      */
15359     actionMode : "el",
15360
15361     /** @private */
15362     getActionEl : function(){
15363         return this[this.actionMode];
15364     },
15365
15366     initComponent : Roo.emptyFn,
15367     /**
15368      * If this is a lazy rendering component, render it to its container element.
15369      * @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.
15370      */
15371     render : function(container, position){
15372         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15373             if(!container && this.el){
15374                 this.el = Roo.get(this.el);
15375                 container = this.el.dom.parentNode;
15376                 this.allowDomMove = false;
15377             }
15378             this.container = Roo.get(container);
15379             this.rendered = true;
15380             if(position !== undefined){
15381                 if(typeof position == 'number'){
15382                     position = this.container.dom.childNodes[position];
15383                 }else{
15384                     position = Roo.getDom(position);
15385                 }
15386             }
15387             this.onRender(this.container, position || null);
15388             if(this.cls){
15389                 this.el.addClass(this.cls);
15390                 delete this.cls;
15391             }
15392             if(this.style){
15393                 this.el.applyStyles(this.style);
15394                 delete this.style;
15395             }
15396             this.fireEvent("render", this);
15397             this.afterRender(this.container);
15398             if(this.hidden){
15399                 this.hide();
15400             }
15401             if(this.disabled){
15402                 this.disable();
15403             }
15404         }
15405         return this;
15406     },
15407
15408     /** @private */
15409     // default function is not really useful
15410     onRender : function(ct, position){
15411         if(this.el){
15412             this.el = Roo.get(this.el);
15413             if(this.allowDomMove !== false){
15414                 ct.dom.insertBefore(this.el.dom, position);
15415             }
15416         }
15417     },
15418
15419     /** @private */
15420     getAutoCreate : function(){
15421         var cfg = typeof this.autoCreate == "object" ?
15422                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15423         if(this.id && !cfg.id){
15424             cfg.id = this.id;
15425         }
15426         return cfg;
15427     },
15428
15429     /** @private */
15430     afterRender : Roo.emptyFn,
15431
15432     /**
15433      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15434      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15435      */
15436     destroy : function(){
15437         if(this.fireEvent("beforedestroy", this) !== false){
15438             this.purgeListeners();
15439             this.beforeDestroy();
15440             if(this.rendered){
15441                 this.el.removeAllListeners();
15442                 this.el.remove();
15443                 if(this.actionMode == "container"){
15444                     this.container.remove();
15445                 }
15446             }
15447             this.onDestroy();
15448             Roo.ComponentMgr.unregister(this);
15449             this.fireEvent("destroy", this);
15450         }
15451     },
15452
15453         /** @private */
15454     beforeDestroy : function(){
15455
15456     },
15457
15458         /** @private */
15459         onDestroy : function(){
15460
15461     },
15462
15463     /**
15464      * Returns the underlying {@link Roo.Element}.
15465      * @return {Roo.Element} The element
15466      */
15467     getEl : function(){
15468         return this.el;
15469     },
15470
15471     /**
15472      * Returns the id of this component.
15473      * @return {String}
15474      */
15475     getId : function(){
15476         return this.id;
15477     },
15478
15479     /**
15480      * Try to focus this component.
15481      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15482      * @return {Roo.Component} this
15483      */
15484     focus : function(selectText){
15485         if(this.rendered){
15486             this.el.focus();
15487             if(selectText === true){
15488                 this.el.dom.select();
15489             }
15490         }
15491         return this;
15492     },
15493
15494     /** @private */
15495     blur : function(){
15496         if(this.rendered){
15497             this.el.blur();
15498         }
15499         return this;
15500     },
15501
15502     /**
15503      * Disable this component.
15504      * @return {Roo.Component} this
15505      */
15506     disable : function(){
15507         if(this.rendered){
15508             this.onDisable();
15509         }
15510         this.disabled = true;
15511         this.fireEvent("disable", this);
15512         return this;
15513     },
15514
15515         // private
15516     onDisable : function(){
15517         this.getActionEl().addClass(this.disabledClass);
15518         this.el.dom.disabled = true;
15519     },
15520
15521     /**
15522      * Enable this component.
15523      * @return {Roo.Component} this
15524      */
15525     enable : function(){
15526         if(this.rendered){
15527             this.onEnable();
15528         }
15529         this.disabled = false;
15530         this.fireEvent("enable", this);
15531         return this;
15532     },
15533
15534         // private
15535     onEnable : function(){
15536         this.getActionEl().removeClass(this.disabledClass);
15537         this.el.dom.disabled = false;
15538     },
15539
15540     /**
15541      * Convenience function for setting disabled/enabled by boolean.
15542      * @param {Boolean} disabled
15543      */
15544     setDisabled : function(disabled){
15545         this[disabled ? "disable" : "enable"]();
15546     },
15547
15548     /**
15549      * Show this component.
15550      * @return {Roo.Component} this
15551      */
15552     show: function(){
15553         if(this.fireEvent("beforeshow", this) !== false){
15554             this.hidden = false;
15555             if(this.rendered){
15556                 this.onShow();
15557             }
15558             this.fireEvent("show", this);
15559         }
15560         return this;
15561     },
15562
15563     // private
15564     onShow : function(){
15565         var ae = this.getActionEl();
15566         if(this.hideMode == 'visibility'){
15567             ae.dom.style.visibility = "visible";
15568         }else if(this.hideMode == 'offsets'){
15569             ae.removeClass('x-hidden');
15570         }else{
15571             ae.dom.style.display = "";
15572         }
15573     },
15574
15575     /**
15576      * Hide this component.
15577      * @return {Roo.Component} this
15578      */
15579     hide: function(){
15580         if(this.fireEvent("beforehide", this) !== false){
15581             this.hidden = true;
15582             if(this.rendered){
15583                 this.onHide();
15584             }
15585             this.fireEvent("hide", this);
15586         }
15587         return this;
15588     },
15589
15590     // private
15591     onHide : function(){
15592         var ae = this.getActionEl();
15593         if(this.hideMode == 'visibility'){
15594             ae.dom.style.visibility = "hidden";
15595         }else if(this.hideMode == 'offsets'){
15596             ae.addClass('x-hidden');
15597         }else{
15598             ae.dom.style.display = "none";
15599         }
15600     },
15601
15602     /**
15603      * Convenience function to hide or show this component by boolean.
15604      * @param {Boolean} visible True to show, false to hide
15605      * @return {Roo.Component} this
15606      */
15607     setVisible: function(visible){
15608         if(visible) {
15609             this.show();
15610         }else{
15611             this.hide();
15612         }
15613         return this;
15614     },
15615
15616     /**
15617      * Returns true if this component is visible.
15618      */
15619     isVisible : function(){
15620         return this.getActionEl().isVisible();
15621     },
15622
15623     cloneConfig : function(overrides){
15624         overrides = overrides || {};
15625         var id = overrides.id || Roo.id();
15626         var cfg = Roo.applyIf(overrides, this.initialConfig);
15627         cfg.id = id; // prevent dup id
15628         return new this.constructor(cfg);
15629     }
15630 });/*
15631  * Based on:
15632  * Ext JS Library 1.1.1
15633  * Copyright(c) 2006-2007, Ext JS, LLC.
15634  *
15635  * Originally Released Under LGPL - original licence link has changed is not relivant.
15636  *
15637  * Fork - LGPL
15638  * <script type="text/javascript">
15639  */
15640
15641 /**
15642  * @class Roo.BoxComponent
15643  * @extends Roo.Component
15644  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15645  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15646  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15647  * layout containers.
15648  * @constructor
15649  * @param {Roo.Element/String/Object} config The configuration options.
15650  */
15651 Roo.BoxComponent = function(config){
15652     Roo.Component.call(this, config);
15653     this.addEvents({
15654         /**
15655          * @event resize
15656          * Fires after the component is resized.
15657              * @param {Roo.Component} this
15658              * @param {Number} adjWidth The box-adjusted width that was set
15659              * @param {Number} adjHeight The box-adjusted height that was set
15660              * @param {Number} rawWidth The width that was originally specified
15661              * @param {Number} rawHeight The height that was originally specified
15662              */
15663         resize : true,
15664         /**
15665          * @event move
15666          * Fires after the component is moved.
15667              * @param {Roo.Component} this
15668              * @param {Number} x The new x position
15669              * @param {Number} y The new y position
15670              */
15671         move : true
15672     });
15673 };
15674
15675 Roo.extend(Roo.BoxComponent, Roo.Component, {
15676     // private, set in afterRender to signify that the component has been rendered
15677     boxReady : false,
15678     // private, used to defer height settings to subclasses
15679     deferHeight: false,
15680     /** @cfg {Number} width
15681      * width (optional) size of component
15682      */
15683      /** @cfg {Number} height
15684      * height (optional) size of component
15685      */
15686      
15687     /**
15688      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15689      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15690      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15691      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15692      * @return {Roo.BoxComponent} this
15693      */
15694     setSize : function(w, h){
15695         // support for standard size objects
15696         if(typeof w == 'object'){
15697             h = w.height;
15698             w = w.width;
15699         }
15700         // not rendered
15701         if(!this.boxReady){
15702             this.width = w;
15703             this.height = h;
15704             return this;
15705         }
15706
15707         // prevent recalcs when not needed
15708         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15709             return this;
15710         }
15711         this.lastSize = {width: w, height: h};
15712
15713         var adj = this.adjustSize(w, h);
15714         var aw = adj.width, ah = adj.height;
15715         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15716             var rz = this.getResizeEl();
15717             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15718                 rz.setSize(aw, ah);
15719             }else if(!this.deferHeight && ah !== undefined){
15720                 rz.setHeight(ah);
15721             }else if(aw !== undefined){
15722                 rz.setWidth(aw);
15723             }
15724             this.onResize(aw, ah, w, h);
15725             this.fireEvent('resize', this, aw, ah, w, h);
15726         }
15727         return this;
15728     },
15729
15730     /**
15731      * Gets the current size of the component's underlying element.
15732      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15733      */
15734     getSize : function(){
15735         return this.el.getSize();
15736     },
15737
15738     /**
15739      * Gets the current XY position of the component's underlying element.
15740      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15741      * @return {Array} The XY position of the element (e.g., [100, 200])
15742      */
15743     getPosition : function(local){
15744         if(local === true){
15745             return [this.el.getLeft(true), this.el.getTop(true)];
15746         }
15747         return this.xy || this.el.getXY();
15748     },
15749
15750     /**
15751      * Gets the current box measurements of the component's underlying element.
15752      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15753      * @returns {Object} box An object in the format {x, y, width, height}
15754      */
15755     getBox : function(local){
15756         var s = this.el.getSize();
15757         if(local){
15758             s.x = this.el.getLeft(true);
15759             s.y = this.el.getTop(true);
15760         }else{
15761             var xy = this.xy || this.el.getXY();
15762             s.x = xy[0];
15763             s.y = xy[1];
15764         }
15765         return s;
15766     },
15767
15768     /**
15769      * Sets the current box measurements of the component's underlying element.
15770      * @param {Object} box An object in the format {x, y, width, height}
15771      * @returns {Roo.BoxComponent} this
15772      */
15773     updateBox : function(box){
15774         this.setSize(box.width, box.height);
15775         this.setPagePosition(box.x, box.y);
15776         return this;
15777     },
15778
15779     // protected
15780     getResizeEl : function(){
15781         return this.resizeEl || this.el;
15782     },
15783
15784     // protected
15785     getPositionEl : function(){
15786         return this.positionEl || this.el;
15787     },
15788
15789     /**
15790      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15791      * This method fires the move event.
15792      * @param {Number} left The new left
15793      * @param {Number} top The new top
15794      * @returns {Roo.BoxComponent} this
15795      */
15796     setPosition : function(x, y){
15797         this.x = x;
15798         this.y = y;
15799         if(!this.boxReady){
15800             return this;
15801         }
15802         var adj = this.adjustPosition(x, y);
15803         var ax = adj.x, ay = adj.y;
15804
15805         var el = this.getPositionEl();
15806         if(ax !== undefined || ay !== undefined){
15807             if(ax !== undefined && ay !== undefined){
15808                 el.setLeftTop(ax, ay);
15809             }else if(ax !== undefined){
15810                 el.setLeft(ax);
15811             }else if(ay !== undefined){
15812                 el.setTop(ay);
15813             }
15814             this.onPosition(ax, ay);
15815             this.fireEvent('move', this, ax, ay);
15816         }
15817         return this;
15818     },
15819
15820     /**
15821      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15822      * This method fires the move event.
15823      * @param {Number} x The new x position
15824      * @param {Number} y The new y position
15825      * @returns {Roo.BoxComponent} this
15826      */
15827     setPagePosition : function(x, y){
15828         this.pageX = x;
15829         this.pageY = y;
15830         if(!this.boxReady){
15831             return;
15832         }
15833         if(x === undefined || y === undefined){ // cannot translate undefined points
15834             return;
15835         }
15836         var p = this.el.translatePoints(x, y);
15837         this.setPosition(p.left, p.top);
15838         return this;
15839     },
15840
15841     // private
15842     onRender : function(ct, position){
15843         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15844         if(this.resizeEl){
15845             this.resizeEl = Roo.get(this.resizeEl);
15846         }
15847         if(this.positionEl){
15848             this.positionEl = Roo.get(this.positionEl);
15849         }
15850     },
15851
15852     // private
15853     afterRender : function(){
15854         Roo.BoxComponent.superclass.afterRender.call(this);
15855         this.boxReady = true;
15856         this.setSize(this.width, this.height);
15857         if(this.x || this.y){
15858             this.setPosition(this.x, this.y);
15859         }
15860         if(this.pageX || this.pageY){
15861             this.setPagePosition(this.pageX, this.pageY);
15862         }
15863     },
15864
15865     /**
15866      * Force the component's size to recalculate based on the underlying element's current height and width.
15867      * @returns {Roo.BoxComponent} this
15868      */
15869     syncSize : function(){
15870         delete this.lastSize;
15871         this.setSize(this.el.getWidth(), this.el.getHeight());
15872         return this;
15873     },
15874
15875     /**
15876      * Called after the component is resized, this method is empty by default but can be implemented by any
15877      * subclass that needs to perform custom logic after a resize occurs.
15878      * @param {Number} adjWidth The box-adjusted width that was set
15879      * @param {Number} adjHeight The box-adjusted height that was set
15880      * @param {Number} rawWidth The width that was originally specified
15881      * @param {Number} rawHeight The height that was originally specified
15882      */
15883     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15884
15885     },
15886
15887     /**
15888      * Called after the component is moved, this method is empty by default but can be implemented by any
15889      * subclass that needs to perform custom logic after a move occurs.
15890      * @param {Number} x The new x position
15891      * @param {Number} y The new y position
15892      */
15893     onPosition : function(x, y){
15894
15895     },
15896
15897     // private
15898     adjustSize : function(w, h){
15899         if(this.autoWidth){
15900             w = 'auto';
15901         }
15902         if(this.autoHeight){
15903             h = 'auto';
15904         }
15905         return {width : w, height: h};
15906     },
15907
15908     // private
15909     adjustPosition : function(x, y){
15910         return {x : x, y: y};
15911     }
15912 });/*
15913  * Original code for Roojs - LGPL
15914  * <script type="text/javascript">
15915  */
15916  
15917 /**
15918  * @class Roo.XComponent
15919  * A delayed Element creator...
15920  * Or a way to group chunks of interface together.
15921  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15922  *  used in conjunction with XComponent.build() it will create an instance of each element,
15923  *  then call addxtype() to build the User interface.
15924  * 
15925  * Mypart.xyx = new Roo.XComponent({
15926
15927     parent : 'Mypart.xyz', // empty == document.element.!!
15928     order : '001',
15929     name : 'xxxx'
15930     region : 'xxxx'
15931     disabled : function() {} 
15932      
15933     tree : function() { // return an tree of xtype declared components
15934         var MODULE = this;
15935         return 
15936         {
15937             xtype : 'NestedLayoutPanel',
15938             // technicall
15939         }
15940      ]
15941  *})
15942  *
15943  *
15944  * It can be used to build a big heiracy, with parent etc.
15945  * or you can just use this to render a single compoent to a dom element
15946  * MYPART.render(Roo.Element | String(id) | dom_element )
15947  *
15948  *
15949  * Usage patterns.
15950  *
15951  * Classic Roo
15952  *
15953  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15954  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15955  *
15956  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15957  *
15958  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15959  * - if mulitple topModules exist, the last one is defined as the top module.
15960  *
15961  * Embeded Roo
15962  * 
15963  * When the top level or multiple modules are to embedded into a existing HTML page,
15964  * the parent element can container '#id' of the element where the module will be drawn.
15965  *
15966  * Bootstrap Roo
15967  *
15968  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15969  * it relies more on a include mechanism, where sub modules are included into an outer page.
15970  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15971  * 
15972  * Bootstrap Roo Included elements
15973  *
15974  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15975  * hence confusing the component builder as it thinks there are multiple top level elements. 
15976  *
15977  * 
15978  * 
15979  * @extends Roo.util.Observable
15980  * @constructor
15981  * @param cfg {Object} configuration of component
15982  * 
15983  */
15984 Roo.XComponent = function(cfg) {
15985     Roo.apply(this, cfg);
15986     this.addEvents({ 
15987         /**
15988              * @event built
15989              * Fires when this the componnt is built
15990              * @param {Roo.XComponent} c the component
15991              */
15992         'built' : true
15993         
15994     });
15995     this.region = this.region || 'center'; // default..
15996     Roo.XComponent.register(this);
15997     this.modules = false;
15998     this.el = false; // where the layout goes..
15999     
16000     
16001 }
16002 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16003     /**
16004      * @property el
16005      * The created element (with Roo.factory())
16006      * @type {Roo.Layout}
16007      */
16008     el  : false,
16009     
16010     /**
16011      * @property el
16012      * for BC  - use el in new code
16013      * @type {Roo.Layout}
16014      */
16015     panel : false,
16016     
16017     /**
16018      * @property layout
16019      * for BC  - use el in new code
16020      * @type {Roo.Layout}
16021      */
16022     layout : false,
16023     
16024      /**
16025      * @cfg {Function|boolean} disabled
16026      * If this module is disabled by some rule, return true from the funtion
16027      */
16028     disabled : false,
16029     
16030     /**
16031      * @cfg {String} parent 
16032      * Name of parent element which it get xtype added to..
16033      */
16034     parent: false,
16035     
16036     /**
16037      * @cfg {String} order
16038      * Used to set the order in which elements are created (usefull for multiple tabs)
16039      */
16040     
16041     order : false,
16042     /**
16043      * @cfg {String} name
16044      * String to display while loading.
16045      */
16046     name : false,
16047     /**
16048      * @cfg {String} region
16049      * Region to render component to (defaults to center)
16050      */
16051     region : 'center',
16052     
16053     /**
16054      * @cfg {Array} items
16055      * A single item array - the first element is the root of the tree..
16056      * It's done this way to stay compatible with the Xtype system...
16057      */
16058     items : false,
16059     
16060     /**
16061      * @property _tree
16062      * The method that retuns the tree of parts that make up this compoennt 
16063      * @type {function}
16064      */
16065     _tree  : false,
16066     
16067      /**
16068      * render
16069      * render element to dom or tree
16070      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16071      */
16072     
16073     render : function(el)
16074     {
16075         
16076         el = el || false;
16077         var hp = this.parent ? 1 : 0;
16078         Roo.debug &&  Roo.log(this);
16079         
16080         var tree = this._tree ? this._tree() : this.tree();
16081
16082         
16083         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16084             // if parent is a '#.....' string, then let's use that..
16085             var ename = this.parent.substr(1);
16086             this.parent = false;
16087             Roo.debug && Roo.log(ename);
16088             switch (ename) {
16089                 case 'bootstrap-body':
16090                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16091                         // this is the BorderLayout standard?
16092                        this.parent = { el : true };
16093                        break;
16094                     }
16095                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16096                         // need to insert stuff...
16097                         this.parent =  {
16098                              el : new Roo.bootstrap.layout.Border({
16099                                  el : document.body, 
16100                      
16101                                  center: {
16102                                     titlebar: false,
16103                                     autoScroll:false,
16104                                     closeOnTab: true,
16105                                     tabPosition: 'top',
16106                                       //resizeTabs: true,
16107                                     alwaysShowTabs: true,
16108                                     hideTabs: false
16109                                      //minTabWidth: 140
16110                                  }
16111                              })
16112                         
16113                          };
16114                          break;
16115                     }
16116                          
16117                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16118                         this.parent = { el :  new  Roo.bootstrap.Body() };
16119                         Roo.debug && Roo.log("setting el to doc body");
16120                          
16121                     } else {
16122                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16123                     }
16124                     break;
16125                 case 'bootstrap':
16126                     this.parent = { el : true};
16127                     // fall through
16128                 default:
16129                     el = Roo.get(ename);
16130                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16131                         this.parent = { el : true};
16132                     }
16133                     
16134                     break;
16135             }
16136                 
16137             
16138             if (!el && !this.parent) {
16139                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16140                 return;
16141             }
16142         }
16143         
16144         Roo.debug && Roo.log("EL:");
16145         Roo.debug && Roo.log(el);
16146         Roo.debug && Roo.log("this.parent.el:");
16147         Roo.debug && Roo.log(this.parent.el);
16148         
16149
16150         // altertive root elements ??? - we need a better way to indicate these.
16151         var is_alt = Roo.XComponent.is_alt ||
16152                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16153                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16154                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16155         
16156         
16157         
16158         if (!this.parent && is_alt) {
16159             //el = Roo.get(document.body);
16160             this.parent = { el : true };
16161         }
16162             
16163             
16164         
16165         if (!this.parent) {
16166             
16167             Roo.debug && Roo.log("no parent - creating one");
16168             
16169             el = el ? Roo.get(el) : false;      
16170             
16171             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16172                 
16173                 this.parent =  {
16174                     el : new Roo.bootstrap.layout.Border({
16175                         el: el || document.body,
16176                     
16177                         center: {
16178                             titlebar: false,
16179                             autoScroll:false,
16180                             closeOnTab: true,
16181                             tabPosition: 'top',
16182                              //resizeTabs: true,
16183                             alwaysShowTabs: false,
16184                             hideTabs: true,
16185                             minTabWidth: 140,
16186                             overflow: 'visible'
16187                          }
16188                      })
16189                 };
16190             } else {
16191             
16192                 // it's a top level one..
16193                 this.parent =  {
16194                     el : new Roo.BorderLayout(el || document.body, {
16195                         center: {
16196                             titlebar: false,
16197                             autoScroll:false,
16198                             closeOnTab: true,
16199                             tabPosition: 'top',
16200                              //resizeTabs: true,
16201                             alwaysShowTabs: el && hp? false :  true,
16202                             hideTabs: el || !hp ? true :  false,
16203                             minTabWidth: 140
16204                          }
16205                     })
16206                 };
16207             }
16208         }
16209         
16210         if (!this.parent.el) {
16211                 // probably an old style ctor, which has been disabled.
16212                 return;
16213
16214         }
16215                 // The 'tree' method is  '_tree now' 
16216             
16217         tree.region = tree.region || this.region;
16218         var is_body = false;
16219         if (this.parent.el === true) {
16220             // bootstrap... - body..
16221             if (el) {
16222                 tree.el = el;
16223             }
16224             this.parent.el = Roo.factory(tree);
16225             is_body = true;
16226         }
16227         
16228         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16229         this.fireEvent('built', this);
16230         
16231         this.panel = this.el;
16232         this.layout = this.panel.layout;
16233         this.parentLayout = this.parent.layout  || false;  
16234          
16235     }
16236     
16237 });
16238
16239 Roo.apply(Roo.XComponent, {
16240     /**
16241      * @property  hideProgress
16242      * true to disable the building progress bar.. usefull on single page renders.
16243      * @type Boolean
16244      */
16245     hideProgress : false,
16246     /**
16247      * @property  buildCompleted
16248      * True when the builder has completed building the interface.
16249      * @type Boolean
16250      */
16251     buildCompleted : false,
16252      
16253     /**
16254      * @property  topModule
16255      * the upper most module - uses document.element as it's constructor.
16256      * @type Object
16257      */
16258      
16259     topModule  : false,
16260       
16261     /**
16262      * @property  modules
16263      * array of modules to be created by registration system.
16264      * @type {Array} of Roo.XComponent
16265      */
16266     
16267     modules : [],
16268     /**
16269      * @property  elmodules
16270      * array of modules to be created by which use #ID 
16271      * @type {Array} of Roo.XComponent
16272      */
16273      
16274     elmodules : [],
16275
16276      /**
16277      * @property  is_alt
16278      * Is an alternative Root - normally used by bootstrap or other systems,
16279      *    where the top element in the tree can wrap 'body' 
16280      * @type {boolean}  (default false)
16281      */
16282      
16283     is_alt : false,
16284     /**
16285      * @property  build_from_html
16286      * Build elements from html - used by bootstrap HTML stuff 
16287      *    - this is cleared after build is completed
16288      * @type {boolean}    (default false)
16289      */
16290      
16291     build_from_html : false,
16292     /**
16293      * Register components to be built later.
16294      *
16295      * This solves the following issues
16296      * - Building is not done on page load, but after an authentication process has occured.
16297      * - Interface elements are registered on page load
16298      * - Parent Interface elements may not be loaded before child, so this handles that..
16299      * 
16300      *
16301      * example:
16302      * 
16303      * MyApp.register({
16304           order : '000001',
16305           module : 'Pman.Tab.projectMgr',
16306           region : 'center',
16307           parent : 'Pman.layout',
16308           disabled : false,  // or use a function..
16309         })
16310      
16311      * * @param {Object} details about module
16312      */
16313     register : function(obj) {
16314                 
16315         Roo.XComponent.event.fireEvent('register', obj);
16316         switch(typeof(obj.disabled) ) {
16317                 
16318             case 'undefined':
16319                 break;
16320             
16321             case 'function':
16322                 if ( obj.disabled() ) {
16323                         return;
16324                 }
16325                 break;
16326             
16327             default:
16328                 if (obj.disabled) {
16329                         return;
16330                 }
16331                 break;
16332         }
16333                 
16334         this.modules.push(obj);
16335          
16336     },
16337     /**
16338      * convert a string to an object..
16339      * eg. 'AAA.BBB' -> finds AAA.BBB
16340
16341      */
16342     
16343     toObject : function(str)
16344     {
16345         if (!str || typeof(str) == 'object') {
16346             return str;
16347         }
16348         if (str.substring(0,1) == '#') {
16349             return str;
16350         }
16351
16352         var ar = str.split('.');
16353         var rt, o;
16354         rt = ar.shift();
16355             /** eval:var:o */
16356         try {
16357             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16358         } catch (e) {
16359             throw "Module not found : " + str;
16360         }
16361         
16362         if (o === false) {
16363             throw "Module not found : " + str;
16364         }
16365         Roo.each(ar, function(e) {
16366             if (typeof(o[e]) == 'undefined') {
16367                 throw "Module not found : " + str;
16368             }
16369             o = o[e];
16370         });
16371         
16372         return o;
16373         
16374     },
16375     
16376     
16377     /**
16378      * move modules into their correct place in the tree..
16379      * 
16380      */
16381     preBuild : function ()
16382     {
16383         var _t = this;
16384         Roo.each(this.modules , function (obj)
16385         {
16386             Roo.XComponent.event.fireEvent('beforebuild', obj);
16387             
16388             var opar = obj.parent;
16389             try { 
16390                 obj.parent = this.toObject(opar);
16391             } catch(e) {
16392                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16393                 return;
16394             }
16395             
16396             if (!obj.parent) {
16397                 Roo.debug && Roo.log("GOT top level module");
16398                 Roo.debug && Roo.log(obj);
16399                 obj.modules = new Roo.util.MixedCollection(false, 
16400                     function(o) { return o.order + '' }
16401                 );
16402                 this.topModule = obj;
16403                 return;
16404             }
16405                         // parent is a string (usually a dom element name..)
16406             if (typeof(obj.parent) == 'string') {
16407                 this.elmodules.push(obj);
16408                 return;
16409             }
16410             if (obj.parent.constructor != Roo.XComponent) {
16411                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16412             }
16413             if (!obj.parent.modules) {
16414                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16415                     function(o) { return o.order + '' }
16416                 );
16417             }
16418             if (obj.parent.disabled) {
16419                 obj.disabled = true;
16420             }
16421             obj.parent.modules.add(obj);
16422         }, this);
16423     },
16424     
16425      /**
16426      * make a list of modules to build.
16427      * @return {Array} list of modules. 
16428      */ 
16429     
16430     buildOrder : function()
16431     {
16432         var _this = this;
16433         var cmp = function(a,b) {   
16434             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16435         };
16436         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16437             throw "No top level modules to build";
16438         }
16439         
16440         // make a flat list in order of modules to build.
16441         var mods = this.topModule ? [ this.topModule ] : [];
16442                 
16443         
16444         // elmodules (is a list of DOM based modules )
16445         Roo.each(this.elmodules, function(e) {
16446             mods.push(e);
16447             if (!this.topModule &&
16448                 typeof(e.parent) == 'string' &&
16449                 e.parent.substring(0,1) == '#' &&
16450                 Roo.get(e.parent.substr(1))
16451                ) {
16452                 
16453                 _this.topModule = e;
16454             }
16455             
16456         });
16457
16458         
16459         // add modules to their parents..
16460         var addMod = function(m) {
16461             Roo.debug && Roo.log("build Order: add: " + m.name);
16462                 
16463             mods.push(m);
16464             if (m.modules && !m.disabled) {
16465                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16466                 m.modules.keySort('ASC',  cmp );
16467                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16468     
16469                 m.modules.each(addMod);
16470             } else {
16471                 Roo.debug && Roo.log("build Order: no child modules");
16472             }
16473             // not sure if this is used any more..
16474             if (m.finalize) {
16475                 m.finalize.name = m.name + " (clean up) ";
16476                 mods.push(m.finalize);
16477             }
16478             
16479         }
16480         if (this.topModule && this.topModule.modules) { 
16481             this.topModule.modules.keySort('ASC',  cmp );
16482             this.topModule.modules.each(addMod);
16483         } 
16484         return mods;
16485     },
16486     
16487      /**
16488      * Build the registered modules.
16489      * @param {Object} parent element.
16490      * @param {Function} optional method to call after module has been added.
16491      * 
16492      */ 
16493    
16494     build : function(opts) 
16495     {
16496         
16497         if (typeof(opts) != 'undefined') {
16498             Roo.apply(this,opts);
16499         }
16500         
16501         this.preBuild();
16502         var mods = this.buildOrder();
16503       
16504         //this.allmods = mods;
16505         //Roo.debug && Roo.log(mods);
16506         //return;
16507         if (!mods.length) { // should not happen
16508             throw "NO modules!!!";
16509         }
16510         
16511         
16512         var msg = "Building Interface...";
16513         // flash it up as modal - so we store the mask!?
16514         if (!this.hideProgress && Roo.MessageBox) {
16515             Roo.MessageBox.show({ title: 'loading' });
16516             Roo.MessageBox.show({
16517                title: "Please wait...",
16518                msg: msg,
16519                width:450,
16520                progress:true,
16521                closable:false,
16522                modal: false
16523               
16524             });
16525         }
16526         var total = mods.length;
16527         
16528         var _this = this;
16529         var progressRun = function() {
16530             if (!mods.length) {
16531                 Roo.debug && Roo.log('hide?');
16532                 if (!this.hideProgress && Roo.MessageBox) {
16533                     Roo.MessageBox.hide();
16534                 }
16535                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16536                 
16537                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16538                 
16539                 // THE END...
16540                 return false;   
16541             }
16542             
16543             var m = mods.shift();
16544             
16545             
16546             Roo.debug && Roo.log(m);
16547             // not sure if this is supported any more.. - modules that are are just function
16548             if (typeof(m) == 'function') { 
16549                 m.call(this);
16550                 return progressRun.defer(10, _this);
16551             } 
16552             
16553             
16554             msg = "Building Interface " + (total  - mods.length) + 
16555                     " of " + total + 
16556                     (m.name ? (' - ' + m.name) : '');
16557                         Roo.debug && Roo.log(msg);
16558             if (!_this.hideProgress &&  Roo.MessageBox) { 
16559                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16560             }
16561             
16562          
16563             // is the module disabled?
16564             var disabled = (typeof(m.disabled) == 'function') ?
16565                 m.disabled.call(m.module.disabled) : m.disabled;    
16566             
16567             
16568             if (disabled) {
16569                 return progressRun(); // we do not update the display!
16570             }
16571             
16572             // now build 
16573             
16574                         
16575                         
16576             m.render();
16577             // it's 10 on top level, and 1 on others??? why...
16578             return progressRun.defer(10, _this);
16579              
16580         }
16581         progressRun.defer(1, _this);
16582      
16583         
16584         
16585     },
16586         
16587         
16588         /**
16589          * Event Object.
16590          *
16591          *
16592          */
16593         event: false, 
16594     /**
16595          * wrapper for event.on - aliased later..  
16596          * Typically use to register a event handler for register:
16597          *
16598          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16599          *
16600          */
16601     on : false
16602    
16603     
16604     
16605 });
16606
16607 Roo.XComponent.event = new Roo.util.Observable({
16608                 events : { 
16609                         /**
16610                          * @event register
16611                          * Fires when an Component is registered,
16612                          * set the disable property on the Component to stop registration.
16613                          * @param {Roo.XComponent} c the component being registerd.
16614                          * 
16615                          */
16616                         'register' : true,
16617             /**
16618                          * @event beforebuild
16619                          * Fires before each Component is built
16620                          * can be used to apply permissions.
16621                          * @param {Roo.XComponent} c the component being registerd.
16622                          * 
16623                          */
16624                         'beforebuild' : true,
16625                         /**
16626                          * @event buildcomplete
16627                          * Fires on the top level element when all elements have been built
16628                          * @param {Roo.XComponent} the top level component.
16629                          */
16630                         'buildcomplete' : true
16631                         
16632                 }
16633 });
16634
16635 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16636  //
16637  /**
16638  * marked - a markdown parser
16639  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16640  * https://github.com/chjj/marked
16641  */
16642
16643
16644 /**
16645  *
16646  * Roo.Markdown - is a very crude wrapper around marked..
16647  *
16648  * usage:
16649  * 
16650  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16651  * 
16652  * Note: move the sample code to the bottom of this
16653  * file before uncommenting it.
16654  *
16655  */
16656
16657 Roo.Markdown = {};
16658 Roo.Markdown.toHtml = function(text) {
16659     
16660     var c = new Roo.Markdown.marked.setOptions({
16661             renderer: new Roo.Markdown.marked.Renderer(),
16662             gfm: true,
16663             tables: true,
16664             breaks: false,
16665             pedantic: false,
16666             sanitize: false,
16667             smartLists: true,
16668             smartypants: false
16669           });
16670     // A FEW HACKS!!?
16671     
16672     text = text.replace(/\\\n/g,' ');
16673     return Roo.Markdown.marked(text);
16674 };
16675 //
16676 // converter
16677 //
16678 // Wraps all "globals" so that the only thing
16679 // exposed is makeHtml().
16680 //
16681 (function() {
16682     
16683     /**
16684      * Block-Level Grammar
16685      */
16686     
16687     var block = {
16688       newline: /^\n+/,
16689       code: /^( {4}[^\n]+\n*)+/,
16690       fences: noop,
16691       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16692       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16693       nptable: noop,
16694       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16695       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16696       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16697       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16698       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16699       table: noop,
16700       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16701       text: /^[^\n]+/
16702     };
16703     
16704     block.bullet = /(?:[*+-]|\d+\.)/;
16705     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16706     block.item = replace(block.item, 'gm')
16707       (/bull/g, block.bullet)
16708       ();
16709     
16710     block.list = replace(block.list)
16711       (/bull/g, block.bullet)
16712       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16713       ('def', '\\n+(?=' + block.def.source + ')')
16714       ();
16715     
16716     block.blockquote = replace(block.blockquote)
16717       ('def', block.def)
16718       ();
16719     
16720     block._tag = '(?!(?:'
16721       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16722       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16723       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16724     
16725     block.html = replace(block.html)
16726       ('comment', /<!--[\s\S]*?-->/)
16727       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16728       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16729       (/tag/g, block._tag)
16730       ();
16731     
16732     block.paragraph = replace(block.paragraph)
16733       ('hr', block.hr)
16734       ('heading', block.heading)
16735       ('lheading', block.lheading)
16736       ('blockquote', block.blockquote)
16737       ('tag', '<' + block._tag)
16738       ('def', block.def)
16739       ();
16740     
16741     /**
16742      * Normal Block Grammar
16743      */
16744     
16745     block.normal = merge({}, block);
16746     
16747     /**
16748      * GFM Block Grammar
16749      */
16750     
16751     block.gfm = merge({}, block.normal, {
16752       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16753       paragraph: /^/,
16754       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16755     });
16756     
16757     block.gfm.paragraph = replace(block.paragraph)
16758       ('(?!', '(?!'
16759         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16760         + block.list.source.replace('\\1', '\\3') + '|')
16761       ();
16762     
16763     /**
16764      * GFM + Tables Block Grammar
16765      */
16766     
16767     block.tables = merge({}, block.gfm, {
16768       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16769       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16770     });
16771     
16772     /**
16773      * Block Lexer
16774      */
16775     
16776     function Lexer(options) {
16777       this.tokens = [];
16778       this.tokens.links = {};
16779       this.options = options || marked.defaults;
16780       this.rules = block.normal;
16781     
16782       if (this.options.gfm) {
16783         if (this.options.tables) {
16784           this.rules = block.tables;
16785         } else {
16786           this.rules = block.gfm;
16787         }
16788       }
16789     }
16790     
16791     /**
16792      * Expose Block Rules
16793      */
16794     
16795     Lexer.rules = block;
16796     
16797     /**
16798      * Static Lex Method
16799      */
16800     
16801     Lexer.lex = function(src, options) {
16802       var lexer = new Lexer(options);
16803       return lexer.lex(src);
16804     };
16805     
16806     /**
16807      * Preprocessing
16808      */
16809     
16810     Lexer.prototype.lex = function(src) {
16811       src = src
16812         .replace(/\r\n|\r/g, '\n')
16813         .replace(/\t/g, '    ')
16814         .replace(/\u00a0/g, ' ')
16815         .replace(/\u2424/g, '\n');
16816     
16817       return this.token(src, true);
16818     };
16819     
16820     /**
16821      * Lexing
16822      */
16823     
16824     Lexer.prototype.token = function(src, top, bq) {
16825       var src = src.replace(/^ +$/gm, '')
16826         , next
16827         , loose
16828         , cap
16829         , bull
16830         , b
16831         , item
16832         , space
16833         , i
16834         , l;
16835     
16836       while (src) {
16837         // newline
16838         if (cap = this.rules.newline.exec(src)) {
16839           src = src.substring(cap[0].length);
16840           if (cap[0].length > 1) {
16841             this.tokens.push({
16842               type: 'space'
16843             });
16844           }
16845         }
16846     
16847         // code
16848         if (cap = this.rules.code.exec(src)) {
16849           src = src.substring(cap[0].length);
16850           cap = cap[0].replace(/^ {4}/gm, '');
16851           this.tokens.push({
16852             type: 'code',
16853             text: !this.options.pedantic
16854               ? cap.replace(/\n+$/, '')
16855               : cap
16856           });
16857           continue;
16858         }
16859     
16860         // fences (gfm)
16861         if (cap = this.rules.fences.exec(src)) {
16862           src = src.substring(cap[0].length);
16863           this.tokens.push({
16864             type: 'code',
16865             lang: cap[2],
16866             text: cap[3] || ''
16867           });
16868           continue;
16869         }
16870     
16871         // heading
16872         if (cap = this.rules.heading.exec(src)) {
16873           src = src.substring(cap[0].length);
16874           this.tokens.push({
16875             type: 'heading',
16876             depth: cap[1].length,
16877             text: cap[2]
16878           });
16879           continue;
16880         }
16881     
16882         // table no leading pipe (gfm)
16883         if (top && (cap = this.rules.nptable.exec(src))) {
16884           src = src.substring(cap[0].length);
16885     
16886           item = {
16887             type: 'table',
16888             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16889             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16890             cells: cap[3].replace(/\n$/, '').split('\n')
16891           };
16892     
16893           for (i = 0; i < item.align.length; i++) {
16894             if (/^ *-+: *$/.test(item.align[i])) {
16895               item.align[i] = 'right';
16896             } else if (/^ *:-+: *$/.test(item.align[i])) {
16897               item.align[i] = 'center';
16898             } else if (/^ *:-+ *$/.test(item.align[i])) {
16899               item.align[i] = 'left';
16900             } else {
16901               item.align[i] = null;
16902             }
16903           }
16904     
16905           for (i = 0; i < item.cells.length; i++) {
16906             item.cells[i] = item.cells[i].split(/ *\| */);
16907           }
16908     
16909           this.tokens.push(item);
16910     
16911           continue;
16912         }
16913     
16914         // lheading
16915         if (cap = this.rules.lheading.exec(src)) {
16916           src = src.substring(cap[0].length);
16917           this.tokens.push({
16918             type: 'heading',
16919             depth: cap[2] === '=' ? 1 : 2,
16920             text: cap[1]
16921           });
16922           continue;
16923         }
16924     
16925         // hr
16926         if (cap = this.rules.hr.exec(src)) {
16927           src = src.substring(cap[0].length);
16928           this.tokens.push({
16929             type: 'hr'
16930           });
16931           continue;
16932         }
16933     
16934         // blockquote
16935         if (cap = this.rules.blockquote.exec(src)) {
16936           src = src.substring(cap[0].length);
16937     
16938           this.tokens.push({
16939             type: 'blockquote_start'
16940           });
16941     
16942           cap = cap[0].replace(/^ *> ?/gm, '');
16943     
16944           // Pass `top` to keep the current
16945           // "toplevel" state. This is exactly
16946           // how markdown.pl works.
16947           this.token(cap, top, true);
16948     
16949           this.tokens.push({
16950             type: 'blockquote_end'
16951           });
16952     
16953           continue;
16954         }
16955     
16956         // list
16957         if (cap = this.rules.list.exec(src)) {
16958           src = src.substring(cap[0].length);
16959           bull = cap[2];
16960     
16961           this.tokens.push({
16962             type: 'list_start',
16963             ordered: bull.length > 1
16964           });
16965     
16966           // Get each top-level item.
16967           cap = cap[0].match(this.rules.item);
16968     
16969           next = false;
16970           l = cap.length;
16971           i = 0;
16972     
16973           for (; i < l; i++) {
16974             item = cap[i];
16975     
16976             // Remove the list item's bullet
16977             // so it is seen as the next token.
16978             space = item.length;
16979             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16980     
16981             // Outdent whatever the
16982             // list item contains. Hacky.
16983             if (~item.indexOf('\n ')) {
16984               space -= item.length;
16985               item = !this.options.pedantic
16986                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16987                 : item.replace(/^ {1,4}/gm, '');
16988             }
16989     
16990             // Determine whether the next list item belongs here.
16991             // Backpedal if it does not belong in this list.
16992             if (this.options.smartLists && i !== l - 1) {
16993               b = block.bullet.exec(cap[i + 1])[0];
16994               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16995                 src = cap.slice(i + 1).join('\n') + src;
16996                 i = l - 1;
16997               }
16998             }
16999     
17000             // Determine whether item is loose or not.
17001             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17002             // for discount behavior.
17003             loose = next || /\n\n(?!\s*$)/.test(item);
17004             if (i !== l - 1) {
17005               next = item.charAt(item.length - 1) === '\n';
17006               if (!loose) { loose = next; }
17007             }
17008     
17009             this.tokens.push({
17010               type: loose
17011                 ? 'loose_item_start'
17012                 : 'list_item_start'
17013             });
17014     
17015             // Recurse.
17016             this.token(item, false, bq);
17017     
17018             this.tokens.push({
17019               type: 'list_item_end'
17020             });
17021           }
17022     
17023           this.tokens.push({
17024             type: 'list_end'
17025           });
17026     
17027           continue;
17028         }
17029     
17030         // html
17031         if (cap = this.rules.html.exec(src)) {
17032           src = src.substring(cap[0].length);
17033           this.tokens.push({
17034             type: this.options.sanitize
17035               ? 'paragraph'
17036               : 'html',
17037             pre: !this.options.sanitizer
17038               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17039             text: cap[0]
17040           });
17041           continue;
17042         }
17043     
17044         // def
17045         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17046           src = src.substring(cap[0].length);
17047           this.tokens.links[cap[1].toLowerCase()] = {
17048             href: cap[2],
17049             title: cap[3]
17050           };
17051           continue;
17052         }
17053     
17054         // table (gfm)
17055         if (top && (cap = this.rules.table.exec(src))) {
17056           src = src.substring(cap[0].length);
17057     
17058           item = {
17059             type: 'table',
17060             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17061             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17062             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17063           };
17064     
17065           for (i = 0; i < item.align.length; i++) {
17066             if (/^ *-+: *$/.test(item.align[i])) {
17067               item.align[i] = 'right';
17068             } else if (/^ *:-+: *$/.test(item.align[i])) {
17069               item.align[i] = 'center';
17070             } else if (/^ *:-+ *$/.test(item.align[i])) {
17071               item.align[i] = 'left';
17072             } else {
17073               item.align[i] = null;
17074             }
17075           }
17076     
17077           for (i = 0; i < item.cells.length; i++) {
17078             item.cells[i] = item.cells[i]
17079               .replace(/^ *\| *| *\| *$/g, '')
17080               .split(/ *\| */);
17081           }
17082     
17083           this.tokens.push(item);
17084     
17085           continue;
17086         }
17087     
17088         // top-level paragraph
17089         if (top && (cap = this.rules.paragraph.exec(src))) {
17090           src = src.substring(cap[0].length);
17091           this.tokens.push({
17092             type: 'paragraph',
17093             text: cap[1].charAt(cap[1].length - 1) === '\n'
17094               ? cap[1].slice(0, -1)
17095               : cap[1]
17096           });
17097           continue;
17098         }
17099     
17100         // text
17101         if (cap = this.rules.text.exec(src)) {
17102           // Top-level should never reach here.
17103           src = src.substring(cap[0].length);
17104           this.tokens.push({
17105             type: 'text',
17106             text: cap[0]
17107           });
17108           continue;
17109         }
17110     
17111         if (src) {
17112           throw new
17113             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17114         }
17115       }
17116     
17117       return this.tokens;
17118     };
17119     
17120     /**
17121      * Inline-Level Grammar
17122      */
17123     
17124     var inline = {
17125       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17126       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17127       url: noop,
17128       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17129       link: /^!?\[(inside)\]\(href\)/,
17130       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17131       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17132       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17133       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17134       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17135       br: /^ {2,}\n(?!\s*$)/,
17136       del: noop,
17137       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17138     };
17139     
17140     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17141     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17142     
17143     inline.link = replace(inline.link)
17144       ('inside', inline._inside)
17145       ('href', inline._href)
17146       ();
17147     
17148     inline.reflink = replace(inline.reflink)
17149       ('inside', inline._inside)
17150       ();
17151     
17152     /**
17153      * Normal Inline Grammar
17154      */
17155     
17156     inline.normal = merge({}, inline);
17157     
17158     /**
17159      * Pedantic Inline Grammar
17160      */
17161     
17162     inline.pedantic = merge({}, inline.normal, {
17163       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17164       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17165     });
17166     
17167     /**
17168      * GFM Inline Grammar
17169      */
17170     
17171     inline.gfm = merge({}, inline.normal, {
17172       escape: replace(inline.escape)('])', '~|])')(),
17173       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17174       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17175       text: replace(inline.text)
17176         (']|', '~]|')
17177         ('|', '|https?://|')
17178         ()
17179     });
17180     
17181     /**
17182      * GFM + Line Breaks Inline Grammar
17183      */
17184     
17185     inline.breaks = merge({}, inline.gfm, {
17186       br: replace(inline.br)('{2,}', '*')(),
17187       text: replace(inline.gfm.text)('{2,}', '*')()
17188     });
17189     
17190     /**
17191      * Inline Lexer & Compiler
17192      */
17193     
17194     function InlineLexer(links, options) {
17195       this.options = options || marked.defaults;
17196       this.links = links;
17197       this.rules = inline.normal;
17198       this.renderer = this.options.renderer || new Renderer;
17199       this.renderer.options = this.options;
17200     
17201       if (!this.links) {
17202         throw new
17203           Error('Tokens array requires a `links` property.');
17204       }
17205     
17206       if (this.options.gfm) {
17207         if (this.options.breaks) {
17208           this.rules = inline.breaks;
17209         } else {
17210           this.rules = inline.gfm;
17211         }
17212       } else if (this.options.pedantic) {
17213         this.rules = inline.pedantic;
17214       }
17215     }
17216     
17217     /**
17218      * Expose Inline Rules
17219      */
17220     
17221     InlineLexer.rules = inline;
17222     
17223     /**
17224      * Static Lexing/Compiling Method
17225      */
17226     
17227     InlineLexer.output = function(src, links, options) {
17228       var inline = new InlineLexer(links, options);
17229       return inline.output(src);
17230     };
17231     
17232     /**
17233      * Lexing/Compiling
17234      */
17235     
17236     InlineLexer.prototype.output = function(src) {
17237       var out = ''
17238         , link
17239         , text
17240         , href
17241         , cap;
17242     
17243       while (src) {
17244         // escape
17245         if (cap = this.rules.escape.exec(src)) {
17246           src = src.substring(cap[0].length);
17247           out += cap[1];
17248           continue;
17249         }
17250     
17251         // autolink
17252         if (cap = this.rules.autolink.exec(src)) {
17253           src = src.substring(cap[0].length);
17254           if (cap[2] === '@') {
17255             text = cap[1].charAt(6) === ':'
17256               ? this.mangle(cap[1].substring(7))
17257               : this.mangle(cap[1]);
17258             href = this.mangle('mailto:') + text;
17259           } else {
17260             text = escape(cap[1]);
17261             href = text;
17262           }
17263           out += this.renderer.link(href, null, text);
17264           continue;
17265         }
17266     
17267         // url (gfm)
17268         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17269           src = src.substring(cap[0].length);
17270           text = escape(cap[1]);
17271           href = text;
17272           out += this.renderer.link(href, null, text);
17273           continue;
17274         }
17275     
17276         // tag
17277         if (cap = this.rules.tag.exec(src)) {
17278           if (!this.inLink && /^<a /i.test(cap[0])) {
17279             this.inLink = true;
17280           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17281             this.inLink = false;
17282           }
17283           src = src.substring(cap[0].length);
17284           out += this.options.sanitize
17285             ? this.options.sanitizer
17286               ? this.options.sanitizer(cap[0])
17287               : escape(cap[0])
17288             : cap[0];
17289           continue;
17290         }
17291     
17292         // link
17293         if (cap = this.rules.link.exec(src)) {
17294           src = src.substring(cap[0].length);
17295           this.inLink = true;
17296           out += this.outputLink(cap, {
17297             href: cap[2],
17298             title: cap[3]
17299           });
17300           this.inLink = false;
17301           continue;
17302         }
17303     
17304         // reflink, nolink
17305         if ((cap = this.rules.reflink.exec(src))
17306             || (cap = this.rules.nolink.exec(src))) {
17307           src = src.substring(cap[0].length);
17308           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17309           link = this.links[link.toLowerCase()];
17310           if (!link || !link.href) {
17311             out += cap[0].charAt(0);
17312             src = cap[0].substring(1) + src;
17313             continue;
17314           }
17315           this.inLink = true;
17316           out += this.outputLink(cap, link);
17317           this.inLink = false;
17318           continue;
17319         }
17320     
17321         // strong
17322         if (cap = this.rules.strong.exec(src)) {
17323           src = src.substring(cap[0].length);
17324           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17325           continue;
17326         }
17327     
17328         // em
17329         if (cap = this.rules.em.exec(src)) {
17330           src = src.substring(cap[0].length);
17331           out += this.renderer.em(this.output(cap[2] || cap[1]));
17332           continue;
17333         }
17334     
17335         // code
17336         if (cap = this.rules.code.exec(src)) {
17337           src = src.substring(cap[0].length);
17338           out += this.renderer.codespan(escape(cap[2], true));
17339           continue;
17340         }
17341     
17342         // br
17343         if (cap = this.rules.br.exec(src)) {
17344           src = src.substring(cap[0].length);
17345           out += this.renderer.br();
17346           continue;
17347         }
17348     
17349         // del (gfm)
17350         if (cap = this.rules.del.exec(src)) {
17351           src = src.substring(cap[0].length);
17352           out += this.renderer.del(this.output(cap[1]));
17353           continue;
17354         }
17355     
17356         // text
17357         if (cap = this.rules.text.exec(src)) {
17358           src = src.substring(cap[0].length);
17359           out += this.renderer.text(escape(this.smartypants(cap[0])));
17360           continue;
17361         }
17362     
17363         if (src) {
17364           throw new
17365             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17366         }
17367       }
17368     
17369       return out;
17370     };
17371     
17372     /**
17373      * Compile Link
17374      */
17375     
17376     InlineLexer.prototype.outputLink = function(cap, link) {
17377       var href = escape(link.href)
17378         , title = link.title ? escape(link.title) : null;
17379     
17380       return cap[0].charAt(0) !== '!'
17381         ? this.renderer.link(href, title, this.output(cap[1]))
17382         : this.renderer.image(href, title, escape(cap[1]));
17383     };
17384     
17385     /**
17386      * Smartypants Transformations
17387      */
17388     
17389     InlineLexer.prototype.smartypants = function(text) {
17390       if (!this.options.smartypants)  { return text; }
17391       return text
17392         // em-dashes
17393         .replace(/---/g, '\u2014')
17394         // en-dashes
17395         .replace(/--/g, '\u2013')
17396         // opening singles
17397         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17398         // closing singles & apostrophes
17399         .replace(/'/g, '\u2019')
17400         // opening doubles
17401         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17402         // closing doubles
17403         .replace(/"/g, '\u201d')
17404         // ellipses
17405         .replace(/\.{3}/g, '\u2026');
17406     };
17407     
17408     /**
17409      * Mangle Links
17410      */
17411     
17412     InlineLexer.prototype.mangle = function(text) {
17413       if (!this.options.mangle) { return text; }
17414       var out = ''
17415         , l = text.length
17416         , i = 0
17417         , ch;
17418     
17419       for (; i < l; i++) {
17420         ch = text.charCodeAt(i);
17421         if (Math.random() > 0.5) {
17422           ch = 'x' + ch.toString(16);
17423         }
17424         out += '&#' + ch + ';';
17425       }
17426     
17427       return out;
17428     };
17429     
17430     /**
17431      * Renderer
17432      */
17433     
17434     function Renderer(options) {
17435       this.options = options || {};
17436     }
17437     
17438     Renderer.prototype.code = function(code, lang, escaped) {
17439       if (this.options.highlight) {
17440         var out = this.options.highlight(code, lang);
17441         if (out != null && out !== code) {
17442           escaped = true;
17443           code = out;
17444         }
17445       } else {
17446             // hack!!! - it's already escapeD?
17447             escaped = true;
17448       }
17449     
17450       if (!lang) {
17451         return '<pre><code>'
17452           + (escaped ? code : escape(code, true))
17453           + '\n</code></pre>';
17454       }
17455     
17456       return '<pre><code class="'
17457         + this.options.langPrefix
17458         + escape(lang, true)
17459         + '">'
17460         + (escaped ? code : escape(code, true))
17461         + '\n</code></pre>\n';
17462     };
17463     
17464     Renderer.prototype.blockquote = function(quote) {
17465       return '<blockquote>\n' + quote + '</blockquote>\n';
17466     };
17467     
17468     Renderer.prototype.html = function(html) {
17469       return html;
17470     };
17471     
17472     Renderer.prototype.heading = function(text, level, raw) {
17473       return '<h'
17474         + level
17475         + ' id="'
17476         + this.options.headerPrefix
17477         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17478         + '">'
17479         + text
17480         + '</h'
17481         + level
17482         + '>\n';
17483     };
17484     
17485     Renderer.prototype.hr = function() {
17486       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17487     };
17488     
17489     Renderer.prototype.list = function(body, ordered) {
17490       var type = ordered ? 'ol' : 'ul';
17491       return '<' + type + '>\n' + body + '</' + type + '>\n';
17492     };
17493     
17494     Renderer.prototype.listitem = function(text) {
17495       return '<li>' + text + '</li>\n';
17496     };
17497     
17498     Renderer.prototype.paragraph = function(text) {
17499       return '<p>' + text + '</p>\n';
17500     };
17501     
17502     Renderer.prototype.table = function(header, body) {
17503       return '<table class="table table-striped">\n'
17504         + '<thead>\n'
17505         + header
17506         + '</thead>\n'
17507         + '<tbody>\n'
17508         + body
17509         + '</tbody>\n'
17510         + '</table>\n';
17511     };
17512     
17513     Renderer.prototype.tablerow = function(content) {
17514       return '<tr>\n' + content + '</tr>\n';
17515     };
17516     
17517     Renderer.prototype.tablecell = function(content, flags) {
17518       var type = flags.header ? 'th' : 'td';
17519       var tag = flags.align
17520         ? '<' + type + ' style="text-align:' + flags.align + '">'
17521         : '<' + type + '>';
17522       return tag + content + '</' + type + '>\n';
17523     };
17524     
17525     // span level renderer
17526     Renderer.prototype.strong = function(text) {
17527       return '<strong>' + text + '</strong>';
17528     };
17529     
17530     Renderer.prototype.em = function(text) {
17531       return '<em>' + text + '</em>';
17532     };
17533     
17534     Renderer.prototype.codespan = function(text) {
17535       return '<code>' + text + '</code>';
17536     };
17537     
17538     Renderer.prototype.br = function() {
17539       return this.options.xhtml ? '<br/>' : '<br>';
17540     };
17541     
17542     Renderer.prototype.del = function(text) {
17543       return '<del>' + text + '</del>';
17544     };
17545     
17546     Renderer.prototype.link = function(href, title, text) {
17547       if (this.options.sanitize) {
17548         try {
17549           var prot = decodeURIComponent(unescape(href))
17550             .replace(/[^\w:]/g, '')
17551             .toLowerCase();
17552         } catch (e) {
17553           return '';
17554         }
17555         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17556           return '';
17557         }
17558       }
17559       var out = '<a href="' + href + '"';
17560       if (title) {
17561         out += ' title="' + title + '"';
17562       }
17563       out += '>' + text + '</a>';
17564       return out;
17565     };
17566     
17567     Renderer.prototype.image = function(href, title, text) {
17568       var out = '<img src="' + href + '" alt="' + text + '"';
17569       if (title) {
17570         out += ' title="' + title + '"';
17571       }
17572       out += this.options.xhtml ? '/>' : '>';
17573       return out;
17574     };
17575     
17576     Renderer.prototype.text = function(text) {
17577       return text;
17578     };
17579     
17580     /**
17581      * Parsing & Compiling
17582      */
17583     
17584     function Parser(options) {
17585       this.tokens = [];
17586       this.token = null;
17587       this.options = options || marked.defaults;
17588       this.options.renderer = this.options.renderer || new Renderer;
17589       this.renderer = this.options.renderer;
17590       this.renderer.options = this.options;
17591     }
17592     
17593     /**
17594      * Static Parse Method
17595      */
17596     
17597     Parser.parse = function(src, options, renderer) {
17598       var parser = new Parser(options, renderer);
17599       return parser.parse(src);
17600     };
17601     
17602     /**
17603      * Parse Loop
17604      */
17605     
17606     Parser.prototype.parse = function(src) {
17607       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17608       this.tokens = src.reverse();
17609     
17610       var out = '';
17611       while (this.next()) {
17612         out += this.tok();
17613       }
17614     
17615       return out;
17616     };
17617     
17618     /**
17619      * Next Token
17620      */
17621     
17622     Parser.prototype.next = function() {
17623       return this.token = this.tokens.pop();
17624     };
17625     
17626     /**
17627      * Preview Next Token
17628      */
17629     
17630     Parser.prototype.peek = function() {
17631       return this.tokens[this.tokens.length - 1] || 0;
17632     };
17633     
17634     /**
17635      * Parse Text Tokens
17636      */
17637     
17638     Parser.prototype.parseText = function() {
17639       var body = this.token.text;
17640     
17641       while (this.peek().type === 'text') {
17642         body += '\n' + this.next().text;
17643       }
17644     
17645       return this.inline.output(body);
17646     };
17647     
17648     /**
17649      * Parse Current Token
17650      */
17651     
17652     Parser.prototype.tok = function() {
17653       switch (this.token.type) {
17654         case 'space': {
17655           return '';
17656         }
17657         case 'hr': {
17658           return this.renderer.hr();
17659         }
17660         case 'heading': {
17661           return this.renderer.heading(
17662             this.inline.output(this.token.text),
17663             this.token.depth,
17664             this.token.text);
17665         }
17666         case 'code': {
17667           return this.renderer.code(this.token.text,
17668             this.token.lang,
17669             this.token.escaped);
17670         }
17671         case 'table': {
17672           var header = ''
17673             , body = ''
17674             , i
17675             , row
17676             , cell
17677             , flags
17678             , j;
17679     
17680           // header
17681           cell = '';
17682           for (i = 0; i < this.token.header.length; i++) {
17683             flags = { header: true, align: this.token.align[i] };
17684             cell += this.renderer.tablecell(
17685               this.inline.output(this.token.header[i]),
17686               { header: true, align: this.token.align[i] }
17687             );
17688           }
17689           header += this.renderer.tablerow(cell);
17690     
17691           for (i = 0; i < this.token.cells.length; i++) {
17692             row = this.token.cells[i];
17693     
17694             cell = '';
17695             for (j = 0; j < row.length; j++) {
17696               cell += this.renderer.tablecell(
17697                 this.inline.output(row[j]),
17698                 { header: false, align: this.token.align[j] }
17699               );
17700             }
17701     
17702             body += this.renderer.tablerow(cell);
17703           }
17704           return this.renderer.table(header, body);
17705         }
17706         case 'blockquote_start': {
17707           var body = '';
17708     
17709           while (this.next().type !== 'blockquote_end') {
17710             body += this.tok();
17711           }
17712     
17713           return this.renderer.blockquote(body);
17714         }
17715         case 'list_start': {
17716           var body = ''
17717             , ordered = this.token.ordered;
17718     
17719           while (this.next().type !== 'list_end') {
17720             body += this.tok();
17721           }
17722     
17723           return this.renderer.list(body, ordered);
17724         }
17725         case 'list_item_start': {
17726           var body = '';
17727     
17728           while (this.next().type !== 'list_item_end') {
17729             body += this.token.type === 'text'
17730               ? this.parseText()
17731               : this.tok();
17732           }
17733     
17734           return this.renderer.listitem(body);
17735         }
17736         case 'loose_item_start': {
17737           var body = '';
17738     
17739           while (this.next().type !== 'list_item_end') {
17740             body += this.tok();
17741           }
17742     
17743           return this.renderer.listitem(body);
17744         }
17745         case 'html': {
17746           var html = !this.token.pre && !this.options.pedantic
17747             ? this.inline.output(this.token.text)
17748             : this.token.text;
17749           return this.renderer.html(html);
17750         }
17751         case 'paragraph': {
17752           return this.renderer.paragraph(this.inline.output(this.token.text));
17753         }
17754         case 'text': {
17755           return this.renderer.paragraph(this.parseText());
17756         }
17757       }
17758     };
17759     
17760     /**
17761      * Helpers
17762      */
17763     
17764     function escape(html, encode) {
17765       return html
17766         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17767         .replace(/</g, '&lt;')
17768         .replace(/>/g, '&gt;')
17769         .replace(/"/g, '&quot;')
17770         .replace(/'/g, '&#39;');
17771     }
17772     
17773     function unescape(html) {
17774         // explicitly match decimal, hex, and named HTML entities 
17775       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17776         n = n.toLowerCase();
17777         if (n === 'colon') { return ':'; }
17778         if (n.charAt(0) === '#') {
17779           return n.charAt(1) === 'x'
17780             ? String.fromCharCode(parseInt(n.substring(2), 16))
17781             : String.fromCharCode(+n.substring(1));
17782         }
17783         return '';
17784       });
17785     }
17786     
17787     function replace(regex, opt) {
17788       regex = regex.source;
17789       opt = opt || '';
17790       return function self(name, val) {
17791         if (!name) { return new RegExp(regex, opt); }
17792         val = val.source || val;
17793         val = val.replace(/(^|[^\[])\^/g, '$1');
17794         regex = regex.replace(name, val);
17795         return self;
17796       };
17797     }
17798     
17799     function noop() {}
17800     noop.exec = noop;
17801     
17802     function merge(obj) {
17803       var i = 1
17804         , target
17805         , key;
17806     
17807       for (; i < arguments.length; i++) {
17808         target = arguments[i];
17809         for (key in target) {
17810           if (Object.prototype.hasOwnProperty.call(target, key)) {
17811             obj[key] = target[key];
17812           }
17813         }
17814       }
17815     
17816       return obj;
17817     }
17818     
17819     
17820     /**
17821      * Marked
17822      */
17823     
17824     function marked(src, opt, callback) {
17825       if (callback || typeof opt === 'function') {
17826         if (!callback) {
17827           callback = opt;
17828           opt = null;
17829         }
17830     
17831         opt = merge({}, marked.defaults, opt || {});
17832     
17833         var highlight = opt.highlight
17834           , tokens
17835           , pending
17836           , i = 0;
17837     
17838         try {
17839           tokens = Lexer.lex(src, opt)
17840         } catch (e) {
17841           return callback(e);
17842         }
17843     
17844         pending = tokens.length;
17845     
17846         var done = function(err) {
17847           if (err) {
17848             opt.highlight = highlight;
17849             return callback(err);
17850           }
17851     
17852           var out;
17853     
17854           try {
17855             out = Parser.parse(tokens, opt);
17856           } catch (e) {
17857             err = e;
17858           }
17859     
17860           opt.highlight = highlight;
17861     
17862           return err
17863             ? callback(err)
17864             : callback(null, out);
17865         };
17866     
17867         if (!highlight || highlight.length < 3) {
17868           return done();
17869         }
17870     
17871         delete opt.highlight;
17872     
17873         if (!pending) { return done(); }
17874     
17875         for (; i < tokens.length; i++) {
17876           (function(token) {
17877             if (token.type !== 'code') {
17878               return --pending || done();
17879             }
17880             return highlight(token.text, token.lang, function(err, code) {
17881               if (err) { return done(err); }
17882               if (code == null || code === token.text) {
17883                 return --pending || done();
17884               }
17885               token.text = code;
17886               token.escaped = true;
17887               --pending || done();
17888             });
17889           })(tokens[i]);
17890         }
17891     
17892         return;
17893       }
17894       try {
17895         if (opt) { opt = merge({}, marked.defaults, opt); }
17896         return Parser.parse(Lexer.lex(src, opt), opt);
17897       } catch (e) {
17898         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17899         if ((opt || marked.defaults).silent) {
17900           return '<p>An error occured:</p><pre>'
17901             + escape(e.message + '', true)
17902             + '</pre>';
17903         }
17904         throw e;
17905       }
17906     }
17907     
17908     /**
17909      * Options
17910      */
17911     
17912     marked.options =
17913     marked.setOptions = function(opt) {
17914       merge(marked.defaults, opt);
17915       return marked;
17916     };
17917     
17918     marked.defaults = {
17919       gfm: true,
17920       tables: true,
17921       breaks: false,
17922       pedantic: false,
17923       sanitize: false,
17924       sanitizer: null,
17925       mangle: true,
17926       smartLists: false,
17927       silent: false,
17928       highlight: null,
17929       langPrefix: 'lang-',
17930       smartypants: false,
17931       headerPrefix: '',
17932       renderer: new Renderer,
17933       xhtml: false
17934     };
17935     
17936     /**
17937      * Expose
17938      */
17939     
17940     marked.Parser = Parser;
17941     marked.parser = Parser.parse;
17942     
17943     marked.Renderer = Renderer;
17944     
17945     marked.Lexer = Lexer;
17946     marked.lexer = Lexer.lex;
17947     
17948     marked.InlineLexer = InlineLexer;
17949     marked.inlineLexer = InlineLexer.output;
17950     
17951     marked.parse = marked;
17952     
17953     Roo.Markdown.marked = marked;
17954
17955 })();/*
17956  * Based on:
17957  * Ext JS Library 1.1.1
17958  * Copyright(c) 2006-2007, Ext JS, LLC.
17959  *
17960  * Originally Released Under LGPL - original licence link has changed is not relivant.
17961  *
17962  * Fork - LGPL
17963  * <script type="text/javascript">
17964  */
17965
17966
17967
17968 /*
17969  * These classes are derivatives of the similarly named classes in the YUI Library.
17970  * The original license:
17971  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17972  * Code licensed under the BSD License:
17973  * http://developer.yahoo.net/yui/license.txt
17974  */
17975
17976 (function() {
17977
17978 var Event=Roo.EventManager;
17979 var Dom=Roo.lib.Dom;
17980
17981 /**
17982  * @class Roo.dd.DragDrop
17983  * @extends Roo.util.Observable
17984  * Defines the interface and base operation of items that that can be
17985  * dragged or can be drop targets.  It was designed to be extended, overriding
17986  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17987  * Up to three html elements can be associated with a DragDrop instance:
17988  * <ul>
17989  * <li>linked element: the element that is passed into the constructor.
17990  * This is the element which defines the boundaries for interaction with
17991  * other DragDrop objects.</li>
17992  * <li>handle element(s): The drag operation only occurs if the element that
17993  * was clicked matches a handle element.  By default this is the linked
17994  * element, but there are times that you will want only a portion of the
17995  * linked element to initiate the drag operation, and the setHandleElId()
17996  * method provides a way to define this.</li>
17997  * <li>drag element: this represents the element that would be moved along
17998  * with the cursor during a drag operation.  By default, this is the linked
17999  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18000  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18001  * </li>
18002  * </ul>
18003  * This class should not be instantiated until the onload event to ensure that
18004  * the associated elements are available.
18005  * The following would define a DragDrop obj that would interact with any
18006  * other DragDrop obj in the "group1" group:
18007  * <pre>
18008  *  dd = new Roo.dd.DragDrop("div1", "group1");
18009  * </pre>
18010  * Since none of the event handlers have been implemented, nothing would
18011  * actually happen if you were to run the code above.  Normally you would
18012  * override this class or one of the default implementations, but you can
18013  * also override the methods you want on an instance of the class...
18014  * <pre>
18015  *  dd.onDragDrop = function(e, id) {
18016  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18017  *  }
18018  * </pre>
18019  * @constructor
18020  * @param {String} id of the element that is linked to this instance
18021  * @param {String} sGroup the group of related DragDrop objects
18022  * @param {object} config an object containing configurable attributes
18023  *                Valid properties for DragDrop:
18024  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18025  */
18026 Roo.dd.DragDrop = function(id, sGroup, config) {
18027     if (id) {
18028         this.init(id, sGroup, config);
18029     }
18030     
18031 };
18032
18033 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18034
18035     /**
18036      * The id of the element associated with this object.  This is what we
18037      * refer to as the "linked element" because the size and position of
18038      * this element is used to determine when the drag and drop objects have
18039      * interacted.
18040      * @property id
18041      * @type String
18042      */
18043     id: null,
18044
18045     /**
18046      * Configuration attributes passed into the constructor
18047      * @property config
18048      * @type object
18049      */
18050     config: null,
18051
18052     /**
18053      * The id of the element that will be dragged.  By default this is same
18054      * as the linked element , but could be changed to another element. Ex:
18055      * Roo.dd.DDProxy
18056      * @property dragElId
18057      * @type String
18058      * @private
18059      */
18060     dragElId: null,
18061
18062     /**
18063      * the id of the element that initiates the drag operation.  By default
18064      * this is the linked element, but could be changed to be a child of this
18065      * element.  This lets us do things like only starting the drag when the
18066      * header element within the linked html element is clicked.
18067      * @property handleElId
18068      * @type String
18069      * @private
18070      */
18071     handleElId: null,
18072
18073     /**
18074      * An associative array of HTML tags that will be ignored if clicked.
18075      * @property invalidHandleTypes
18076      * @type {string: string}
18077      */
18078     invalidHandleTypes: null,
18079
18080     /**
18081      * An associative array of ids for elements that will be ignored if clicked
18082      * @property invalidHandleIds
18083      * @type {string: string}
18084      */
18085     invalidHandleIds: null,
18086
18087     /**
18088      * An indexted array of css class names for elements that will be ignored
18089      * if clicked.
18090      * @property invalidHandleClasses
18091      * @type string[]
18092      */
18093     invalidHandleClasses: null,
18094
18095     /**
18096      * The linked element's absolute X position at the time the drag was
18097      * started
18098      * @property startPageX
18099      * @type int
18100      * @private
18101      */
18102     startPageX: 0,
18103
18104     /**
18105      * The linked element's absolute X position at the time the drag was
18106      * started
18107      * @property startPageY
18108      * @type int
18109      * @private
18110      */
18111     startPageY: 0,
18112
18113     /**
18114      * The group defines a logical collection of DragDrop objects that are
18115      * related.  Instances only get events when interacting with other
18116      * DragDrop object in the same group.  This lets us define multiple
18117      * groups using a single DragDrop subclass if we want.
18118      * @property groups
18119      * @type {string: string}
18120      */
18121     groups: null,
18122
18123     /**
18124      * Individual drag/drop instances can be locked.  This will prevent
18125      * onmousedown start drag.
18126      * @property locked
18127      * @type boolean
18128      * @private
18129      */
18130     locked: false,
18131
18132     /**
18133      * Lock this instance
18134      * @method lock
18135      */
18136     lock: function() { this.locked = true; },
18137
18138     /**
18139      * Unlock this instace
18140      * @method unlock
18141      */
18142     unlock: function() { this.locked = false; },
18143
18144     /**
18145      * By default, all insances can be a drop target.  This can be disabled by
18146      * setting isTarget to false.
18147      * @method isTarget
18148      * @type boolean
18149      */
18150     isTarget: true,
18151
18152     /**
18153      * The padding configured for this drag and drop object for calculating
18154      * the drop zone intersection with this object.
18155      * @method padding
18156      * @type int[]
18157      */
18158     padding: null,
18159
18160     /**
18161      * Cached reference to the linked element
18162      * @property _domRef
18163      * @private
18164      */
18165     _domRef: null,
18166
18167     /**
18168      * Internal typeof flag
18169      * @property __ygDragDrop
18170      * @private
18171      */
18172     __ygDragDrop: true,
18173
18174     /**
18175      * Set to true when horizontal contraints are applied
18176      * @property constrainX
18177      * @type boolean
18178      * @private
18179      */
18180     constrainX: false,
18181
18182     /**
18183      * Set to true when vertical contraints are applied
18184      * @property constrainY
18185      * @type boolean
18186      * @private
18187      */
18188     constrainY: false,
18189
18190     /**
18191      * The left constraint
18192      * @property minX
18193      * @type int
18194      * @private
18195      */
18196     minX: 0,
18197
18198     /**
18199      * The right constraint
18200      * @property maxX
18201      * @type int
18202      * @private
18203      */
18204     maxX: 0,
18205
18206     /**
18207      * The up constraint
18208      * @property minY
18209      * @type int
18210      * @type int
18211      * @private
18212      */
18213     minY: 0,
18214
18215     /**
18216      * The down constraint
18217      * @property maxY
18218      * @type int
18219      * @private
18220      */
18221     maxY: 0,
18222
18223     /**
18224      * Maintain offsets when we resetconstraints.  Set to true when you want
18225      * the position of the element relative to its parent to stay the same
18226      * when the page changes
18227      *
18228      * @property maintainOffset
18229      * @type boolean
18230      */
18231     maintainOffset: false,
18232
18233     /**
18234      * Array of pixel locations the element will snap to if we specified a
18235      * horizontal graduation/interval.  This array is generated automatically
18236      * when you define a tick interval.
18237      * @property xTicks
18238      * @type int[]
18239      */
18240     xTicks: null,
18241
18242     /**
18243      * Array of pixel locations the element will snap to if we specified a
18244      * vertical graduation/interval.  This array is generated automatically
18245      * when you define a tick interval.
18246      * @property yTicks
18247      * @type int[]
18248      */
18249     yTicks: null,
18250
18251     /**
18252      * By default the drag and drop instance will only respond to the primary
18253      * button click (left button for a right-handed mouse).  Set to true to
18254      * allow drag and drop to start with any mouse click that is propogated
18255      * by the browser
18256      * @property primaryButtonOnly
18257      * @type boolean
18258      */
18259     primaryButtonOnly: true,
18260
18261     /**
18262      * The availabe property is false until the linked dom element is accessible.
18263      * @property available
18264      * @type boolean
18265      */
18266     available: false,
18267
18268     /**
18269      * By default, drags can only be initiated if the mousedown occurs in the
18270      * region the linked element is.  This is done in part to work around a
18271      * bug in some browsers that mis-report the mousedown if the previous
18272      * mouseup happened outside of the window.  This property is set to true
18273      * if outer handles are defined.
18274      *
18275      * @property hasOuterHandles
18276      * @type boolean
18277      * @default false
18278      */
18279     hasOuterHandles: false,
18280
18281     /**
18282      * Code that executes immediately before the startDrag event
18283      * @method b4StartDrag
18284      * @private
18285      */
18286     b4StartDrag: function(x, y) { },
18287
18288     /**
18289      * Abstract method called after a drag/drop object is clicked
18290      * and the drag or mousedown time thresholds have beeen met.
18291      * @method startDrag
18292      * @param {int} X click location
18293      * @param {int} Y click location
18294      */
18295     startDrag: function(x, y) { /* override this */ },
18296
18297     /**
18298      * Code that executes immediately before the onDrag event
18299      * @method b4Drag
18300      * @private
18301      */
18302     b4Drag: function(e) { },
18303
18304     /**
18305      * Abstract method called during the onMouseMove event while dragging an
18306      * object.
18307      * @method onDrag
18308      * @param {Event} e the mousemove event
18309      */
18310     onDrag: function(e) { /* override this */ },
18311
18312     /**
18313      * Abstract method called when this element fist begins hovering over
18314      * another DragDrop obj
18315      * @method onDragEnter
18316      * @param {Event} e the mousemove event
18317      * @param {String|DragDrop[]} id In POINT mode, the element
18318      * id this is hovering over.  In INTERSECT mode, an array of one or more
18319      * dragdrop items being hovered over.
18320      */
18321     onDragEnter: function(e, id) { /* override this */ },
18322
18323     /**
18324      * Code that executes immediately before the onDragOver event
18325      * @method b4DragOver
18326      * @private
18327      */
18328     b4DragOver: function(e) { },
18329
18330     /**
18331      * Abstract method called when this element is hovering over another
18332      * DragDrop obj
18333      * @method onDragOver
18334      * @param {Event} e the mousemove event
18335      * @param {String|DragDrop[]} id In POINT mode, the element
18336      * id this is hovering over.  In INTERSECT mode, an array of dd items
18337      * being hovered over.
18338      */
18339     onDragOver: function(e, id) { /* override this */ },
18340
18341     /**
18342      * Code that executes immediately before the onDragOut event
18343      * @method b4DragOut
18344      * @private
18345      */
18346     b4DragOut: function(e) { },
18347
18348     /**
18349      * Abstract method called when we are no longer hovering over an element
18350      * @method onDragOut
18351      * @param {Event} e the mousemove event
18352      * @param {String|DragDrop[]} id In POINT mode, the element
18353      * id this was hovering over.  In INTERSECT mode, an array of dd items
18354      * that the mouse is no longer over.
18355      */
18356     onDragOut: function(e, id) { /* override this */ },
18357
18358     /**
18359      * Code that executes immediately before the onDragDrop event
18360      * @method b4DragDrop
18361      * @private
18362      */
18363     b4DragDrop: function(e) { },
18364
18365     /**
18366      * Abstract method called when this item is dropped on another DragDrop
18367      * obj
18368      * @method onDragDrop
18369      * @param {Event} e the mouseup event
18370      * @param {String|DragDrop[]} id In POINT mode, the element
18371      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18372      * was dropped on.
18373      */
18374     onDragDrop: function(e, id) { /* override this */ },
18375
18376     /**
18377      * Abstract method called when this item is dropped on an area with no
18378      * drop target
18379      * @method onInvalidDrop
18380      * @param {Event} e the mouseup event
18381      */
18382     onInvalidDrop: function(e) { /* override this */ },
18383
18384     /**
18385      * Code that executes immediately before the endDrag event
18386      * @method b4EndDrag
18387      * @private
18388      */
18389     b4EndDrag: function(e) { },
18390
18391     /**
18392      * Fired when we are done dragging the object
18393      * @method endDrag
18394      * @param {Event} e the mouseup event
18395      */
18396     endDrag: function(e) { /* override this */ },
18397
18398     /**
18399      * Code executed immediately before the onMouseDown event
18400      * @method b4MouseDown
18401      * @param {Event} e the mousedown event
18402      * @private
18403      */
18404     b4MouseDown: function(e) {  },
18405
18406     /**
18407      * Event handler that fires when a drag/drop obj gets a mousedown
18408      * @method onMouseDown
18409      * @param {Event} e the mousedown event
18410      */
18411     onMouseDown: function(e) { /* override this */ },
18412
18413     /**
18414      * Event handler that fires when a drag/drop obj gets a mouseup
18415      * @method onMouseUp
18416      * @param {Event} e the mouseup event
18417      */
18418     onMouseUp: function(e) { /* override this */ },
18419
18420     /**
18421      * Override the onAvailable method to do what is needed after the initial
18422      * position was determined.
18423      * @method onAvailable
18424      */
18425     onAvailable: function () {
18426     },
18427
18428     /*
18429      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18430      * @type Object
18431      */
18432     defaultPadding : {left:0, right:0, top:0, bottom:0},
18433
18434     /*
18435      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18436  *
18437  * Usage:
18438  <pre><code>
18439  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18440                 { dragElId: "existingProxyDiv" });
18441  dd.startDrag = function(){
18442      this.constrainTo("parent-id");
18443  };
18444  </code></pre>
18445  * Or you can initalize it using the {@link Roo.Element} object:
18446  <pre><code>
18447  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18448      startDrag : function(){
18449          this.constrainTo("parent-id");
18450      }
18451  });
18452  </code></pre>
18453      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18454      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18455      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18456      * an object containing the sides to pad. For example: {right:10, bottom:10}
18457      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18458      */
18459     constrainTo : function(constrainTo, pad, inContent){
18460         if(typeof pad == "number"){
18461             pad = {left: pad, right:pad, top:pad, bottom:pad};
18462         }
18463         pad = pad || this.defaultPadding;
18464         var b = Roo.get(this.getEl()).getBox();
18465         var ce = Roo.get(constrainTo);
18466         var s = ce.getScroll();
18467         var c, cd = ce.dom;
18468         if(cd == document.body){
18469             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18470         }else{
18471             xy = ce.getXY();
18472             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18473         }
18474
18475
18476         var topSpace = b.y - c.y;
18477         var leftSpace = b.x - c.x;
18478
18479         this.resetConstraints();
18480         this.setXConstraint(leftSpace - (pad.left||0), // left
18481                 c.width - leftSpace - b.width - (pad.right||0) //right
18482         );
18483         this.setYConstraint(topSpace - (pad.top||0), //top
18484                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18485         );
18486     },
18487
18488     /**
18489      * Returns a reference to the linked element
18490      * @method getEl
18491      * @return {HTMLElement} the html element
18492      */
18493     getEl: function() {
18494         if (!this._domRef) {
18495             this._domRef = Roo.getDom(this.id);
18496         }
18497
18498         return this._domRef;
18499     },
18500
18501     /**
18502      * Returns a reference to the actual element to drag.  By default this is
18503      * the same as the html element, but it can be assigned to another
18504      * element. An example of this can be found in Roo.dd.DDProxy
18505      * @method getDragEl
18506      * @return {HTMLElement} the html element
18507      */
18508     getDragEl: function() {
18509         return Roo.getDom(this.dragElId);
18510     },
18511
18512     /**
18513      * Sets up the DragDrop object.  Must be called in the constructor of any
18514      * Roo.dd.DragDrop subclass
18515      * @method init
18516      * @param id the id of the linked element
18517      * @param {String} sGroup the group of related items
18518      * @param {object} config configuration attributes
18519      */
18520     init: function(id, sGroup, config) {
18521         this.initTarget(id, sGroup, config);
18522         if (!Roo.isTouch) {
18523             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18524         }
18525         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18526         // Event.on(this.id, "selectstart", Event.preventDefault);
18527     },
18528
18529     /**
18530      * Initializes Targeting functionality only... the object does not
18531      * get a mousedown handler.
18532      * @method initTarget
18533      * @param id the id of the linked element
18534      * @param {String} sGroup the group of related items
18535      * @param {object} config configuration attributes
18536      */
18537     initTarget: function(id, sGroup, config) {
18538
18539         // configuration attributes
18540         this.config = config || {};
18541
18542         // create a local reference to the drag and drop manager
18543         this.DDM = Roo.dd.DDM;
18544         // initialize the groups array
18545         this.groups = {};
18546
18547         // assume that we have an element reference instead of an id if the
18548         // parameter is not a string
18549         if (typeof id !== "string") {
18550             id = Roo.id(id);
18551         }
18552
18553         // set the id
18554         this.id = id;
18555
18556         // add to an interaction group
18557         this.addToGroup((sGroup) ? sGroup : "default");
18558
18559         // We don't want to register this as the handle with the manager
18560         // so we just set the id rather than calling the setter.
18561         this.handleElId = id;
18562
18563         // the linked element is the element that gets dragged by default
18564         this.setDragElId(id);
18565
18566         // by default, clicked anchors will not start drag operations.
18567         this.invalidHandleTypes = { A: "A" };
18568         this.invalidHandleIds = {};
18569         this.invalidHandleClasses = [];
18570
18571         this.applyConfig();
18572
18573         this.handleOnAvailable();
18574     },
18575
18576     /**
18577      * Applies the configuration parameters that were passed into the constructor.
18578      * This is supposed to happen at each level through the inheritance chain.  So
18579      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18580      * DragDrop in order to get all of the parameters that are available in
18581      * each object.
18582      * @method applyConfig
18583      */
18584     applyConfig: function() {
18585
18586         // configurable properties:
18587         //    padding, isTarget, maintainOffset, primaryButtonOnly
18588         this.padding           = this.config.padding || [0, 0, 0, 0];
18589         this.isTarget          = (this.config.isTarget !== false);
18590         this.maintainOffset    = (this.config.maintainOffset);
18591         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18592
18593     },
18594
18595     /**
18596      * Executed when the linked element is available
18597      * @method handleOnAvailable
18598      * @private
18599      */
18600     handleOnAvailable: function() {
18601         this.available = true;
18602         this.resetConstraints();
18603         this.onAvailable();
18604     },
18605
18606      /**
18607      * Configures the padding for the target zone in px.  Effectively expands
18608      * (or reduces) the virtual object size for targeting calculations.
18609      * Supports css-style shorthand; if only one parameter is passed, all sides
18610      * will have that padding, and if only two are passed, the top and bottom
18611      * will have the first param, the left and right the second.
18612      * @method setPadding
18613      * @param {int} iTop    Top pad
18614      * @param {int} iRight  Right pad
18615      * @param {int} iBot    Bot pad
18616      * @param {int} iLeft   Left pad
18617      */
18618     setPadding: function(iTop, iRight, iBot, iLeft) {
18619         // this.padding = [iLeft, iRight, iTop, iBot];
18620         if (!iRight && 0 !== iRight) {
18621             this.padding = [iTop, iTop, iTop, iTop];
18622         } else if (!iBot && 0 !== iBot) {
18623             this.padding = [iTop, iRight, iTop, iRight];
18624         } else {
18625             this.padding = [iTop, iRight, iBot, iLeft];
18626         }
18627     },
18628
18629     /**
18630      * Stores the initial placement of the linked element.
18631      * @method setInitialPosition
18632      * @param {int} diffX   the X offset, default 0
18633      * @param {int} diffY   the Y offset, default 0
18634      */
18635     setInitPosition: function(diffX, diffY) {
18636         var el = this.getEl();
18637
18638         if (!this.DDM.verifyEl(el)) {
18639             return;
18640         }
18641
18642         var dx = diffX || 0;
18643         var dy = diffY || 0;
18644
18645         var p = Dom.getXY( el );
18646
18647         this.initPageX = p[0] - dx;
18648         this.initPageY = p[1] - dy;
18649
18650         this.lastPageX = p[0];
18651         this.lastPageY = p[1];
18652
18653
18654         this.setStartPosition(p);
18655     },
18656
18657     /**
18658      * Sets the start position of the element.  This is set when the obj
18659      * is initialized, the reset when a drag is started.
18660      * @method setStartPosition
18661      * @param pos current position (from previous lookup)
18662      * @private
18663      */
18664     setStartPosition: function(pos) {
18665         var p = pos || Dom.getXY( this.getEl() );
18666         this.deltaSetXY = null;
18667
18668         this.startPageX = p[0];
18669         this.startPageY = p[1];
18670     },
18671
18672     /**
18673      * Add this instance to a group of related drag/drop objects.  All
18674      * instances belong to at least one group, and can belong to as many
18675      * groups as needed.
18676      * @method addToGroup
18677      * @param sGroup {string} the name of the group
18678      */
18679     addToGroup: function(sGroup) {
18680         this.groups[sGroup] = true;
18681         this.DDM.regDragDrop(this, sGroup);
18682     },
18683
18684     /**
18685      * Remove's this instance from the supplied interaction group
18686      * @method removeFromGroup
18687      * @param {string}  sGroup  The group to drop
18688      */
18689     removeFromGroup: function(sGroup) {
18690         if (this.groups[sGroup]) {
18691             delete this.groups[sGroup];
18692         }
18693
18694         this.DDM.removeDDFromGroup(this, sGroup);
18695     },
18696
18697     /**
18698      * Allows you to specify that an element other than the linked element
18699      * will be moved with the cursor during a drag
18700      * @method setDragElId
18701      * @param id {string} the id of the element that will be used to initiate the drag
18702      */
18703     setDragElId: function(id) {
18704         this.dragElId = id;
18705     },
18706
18707     /**
18708      * Allows you to specify a child of the linked element that should be
18709      * used to initiate the drag operation.  An example of this would be if
18710      * you have a content div with text and links.  Clicking anywhere in the
18711      * content area would normally start the drag operation.  Use this method
18712      * to specify that an element inside of the content div is the element
18713      * that starts the drag operation.
18714      * @method setHandleElId
18715      * @param id {string} the id of the element that will be used to
18716      * initiate the drag.
18717      */
18718     setHandleElId: function(id) {
18719         if (typeof id !== "string") {
18720             id = Roo.id(id);
18721         }
18722         this.handleElId = id;
18723         this.DDM.regHandle(this.id, id);
18724     },
18725
18726     /**
18727      * Allows you to set an element outside of the linked element as a drag
18728      * handle
18729      * @method setOuterHandleElId
18730      * @param id the id of the element that will be used to initiate the drag
18731      */
18732     setOuterHandleElId: function(id) {
18733         if (typeof id !== "string") {
18734             id = Roo.id(id);
18735         }
18736         Event.on(id, "mousedown",
18737                 this.handleMouseDown, this);
18738         this.setHandleElId(id);
18739
18740         this.hasOuterHandles = true;
18741     },
18742
18743     /**
18744      * Remove all drag and drop hooks for this element
18745      * @method unreg
18746      */
18747     unreg: function() {
18748         Event.un(this.id, "mousedown",
18749                 this.handleMouseDown);
18750         Event.un(this.id, "touchstart",
18751                 this.handleMouseDown);
18752         this._domRef = null;
18753         this.DDM._remove(this);
18754     },
18755
18756     destroy : function(){
18757         this.unreg();
18758     },
18759
18760     /**
18761      * Returns true if this instance is locked, or the drag drop mgr is locked
18762      * (meaning that all drag/drop is disabled on the page.)
18763      * @method isLocked
18764      * @return {boolean} true if this obj or all drag/drop is locked, else
18765      * false
18766      */
18767     isLocked: function() {
18768         return (this.DDM.isLocked() || this.locked);
18769     },
18770
18771     /**
18772      * Fired when this object is clicked
18773      * @method handleMouseDown
18774      * @param {Event} e
18775      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18776      * @private
18777      */
18778     handleMouseDown: function(e, oDD){
18779      
18780         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18781             //Roo.log('not touch/ button !=0');
18782             return;
18783         }
18784         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18785             return; // double touch..
18786         }
18787         
18788
18789         if (this.isLocked()) {
18790             //Roo.log('locked');
18791             return;
18792         }
18793
18794         this.DDM.refreshCache(this.groups);
18795 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18796         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18797         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18798             //Roo.log('no outer handes or not over target');
18799                 // do nothing.
18800         } else {
18801 //            Roo.log('check validator');
18802             if (this.clickValidator(e)) {
18803 //                Roo.log('validate success');
18804                 // set the initial element position
18805                 this.setStartPosition();
18806
18807
18808                 this.b4MouseDown(e);
18809                 this.onMouseDown(e);
18810
18811                 this.DDM.handleMouseDown(e, this);
18812
18813                 this.DDM.stopEvent(e);
18814             } else {
18815
18816
18817             }
18818         }
18819     },
18820
18821     clickValidator: function(e) {
18822         var target = e.getTarget();
18823         return ( this.isValidHandleChild(target) &&
18824                     (this.id == this.handleElId ||
18825                         this.DDM.handleWasClicked(target, this.id)) );
18826     },
18827
18828     /**
18829      * Allows you to specify a tag name that should not start a drag operation
18830      * when clicked.  This is designed to facilitate embedding links within a
18831      * drag handle that do something other than start the drag.
18832      * @method addInvalidHandleType
18833      * @param {string} tagName the type of element to exclude
18834      */
18835     addInvalidHandleType: function(tagName) {
18836         var type = tagName.toUpperCase();
18837         this.invalidHandleTypes[type] = type;
18838     },
18839
18840     /**
18841      * Lets you to specify an element id for a child of a drag handle
18842      * that should not initiate a drag
18843      * @method addInvalidHandleId
18844      * @param {string} id the element id of the element you wish to ignore
18845      */
18846     addInvalidHandleId: function(id) {
18847         if (typeof id !== "string") {
18848             id = Roo.id(id);
18849         }
18850         this.invalidHandleIds[id] = id;
18851     },
18852
18853     /**
18854      * Lets you specify a css class of elements that will not initiate a drag
18855      * @method addInvalidHandleClass
18856      * @param {string} cssClass the class of the elements you wish to ignore
18857      */
18858     addInvalidHandleClass: function(cssClass) {
18859         this.invalidHandleClasses.push(cssClass);
18860     },
18861
18862     /**
18863      * Unsets an excluded tag name set by addInvalidHandleType
18864      * @method removeInvalidHandleType
18865      * @param {string} tagName the type of element to unexclude
18866      */
18867     removeInvalidHandleType: function(tagName) {
18868         var type = tagName.toUpperCase();
18869         // this.invalidHandleTypes[type] = null;
18870         delete this.invalidHandleTypes[type];
18871     },
18872
18873     /**
18874      * Unsets an invalid handle id
18875      * @method removeInvalidHandleId
18876      * @param {string} id the id of the element to re-enable
18877      */
18878     removeInvalidHandleId: function(id) {
18879         if (typeof id !== "string") {
18880             id = Roo.id(id);
18881         }
18882         delete this.invalidHandleIds[id];
18883     },
18884
18885     /**
18886      * Unsets an invalid css class
18887      * @method removeInvalidHandleClass
18888      * @param {string} cssClass the class of the element(s) you wish to
18889      * re-enable
18890      */
18891     removeInvalidHandleClass: function(cssClass) {
18892         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18893             if (this.invalidHandleClasses[i] == cssClass) {
18894                 delete this.invalidHandleClasses[i];
18895             }
18896         }
18897     },
18898
18899     /**
18900      * Checks the tag exclusion list to see if this click should be ignored
18901      * @method isValidHandleChild
18902      * @param {HTMLElement} node the HTMLElement to evaluate
18903      * @return {boolean} true if this is a valid tag type, false if not
18904      */
18905     isValidHandleChild: function(node) {
18906
18907         var valid = true;
18908         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18909         var nodeName;
18910         try {
18911             nodeName = node.nodeName.toUpperCase();
18912         } catch(e) {
18913             nodeName = node.nodeName;
18914         }
18915         valid = valid && !this.invalidHandleTypes[nodeName];
18916         valid = valid && !this.invalidHandleIds[node.id];
18917
18918         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18919             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18920         }
18921
18922
18923         return valid;
18924
18925     },
18926
18927     /**
18928      * Create the array of horizontal tick marks if an interval was specified
18929      * in setXConstraint().
18930      * @method setXTicks
18931      * @private
18932      */
18933     setXTicks: function(iStartX, iTickSize) {
18934         this.xTicks = [];
18935         this.xTickSize = iTickSize;
18936
18937         var tickMap = {};
18938
18939         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18940             if (!tickMap[i]) {
18941                 this.xTicks[this.xTicks.length] = i;
18942                 tickMap[i] = true;
18943             }
18944         }
18945
18946         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18947             if (!tickMap[i]) {
18948                 this.xTicks[this.xTicks.length] = i;
18949                 tickMap[i] = true;
18950             }
18951         }
18952
18953         this.xTicks.sort(this.DDM.numericSort) ;
18954     },
18955
18956     /**
18957      * Create the array of vertical tick marks if an interval was specified in
18958      * setYConstraint().
18959      * @method setYTicks
18960      * @private
18961      */
18962     setYTicks: function(iStartY, iTickSize) {
18963         this.yTicks = [];
18964         this.yTickSize = iTickSize;
18965
18966         var tickMap = {};
18967
18968         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18969             if (!tickMap[i]) {
18970                 this.yTicks[this.yTicks.length] = i;
18971                 tickMap[i] = true;
18972             }
18973         }
18974
18975         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18976             if (!tickMap[i]) {
18977                 this.yTicks[this.yTicks.length] = i;
18978                 tickMap[i] = true;
18979             }
18980         }
18981
18982         this.yTicks.sort(this.DDM.numericSort) ;
18983     },
18984
18985     /**
18986      * By default, the element can be dragged any place on the screen.  Use
18987      * this method to limit the horizontal travel of the element.  Pass in
18988      * 0,0 for the parameters if you want to lock the drag to the y axis.
18989      * @method setXConstraint
18990      * @param {int} iLeft the number of pixels the element can move to the left
18991      * @param {int} iRight the number of pixels the element can move to the
18992      * right
18993      * @param {int} iTickSize optional parameter for specifying that the
18994      * element
18995      * should move iTickSize pixels at a time.
18996      */
18997     setXConstraint: function(iLeft, iRight, iTickSize) {
18998         this.leftConstraint = iLeft;
18999         this.rightConstraint = iRight;
19000
19001         this.minX = this.initPageX - iLeft;
19002         this.maxX = this.initPageX + iRight;
19003         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19004
19005         this.constrainX = true;
19006     },
19007
19008     /**
19009      * Clears any constraints applied to this instance.  Also clears ticks
19010      * since they can't exist independent of a constraint at this time.
19011      * @method clearConstraints
19012      */
19013     clearConstraints: function() {
19014         this.constrainX = false;
19015         this.constrainY = false;
19016         this.clearTicks();
19017     },
19018
19019     /**
19020      * Clears any tick interval defined for this instance
19021      * @method clearTicks
19022      */
19023     clearTicks: function() {
19024         this.xTicks = null;
19025         this.yTicks = null;
19026         this.xTickSize = 0;
19027         this.yTickSize = 0;
19028     },
19029
19030     /**
19031      * By default, the element can be dragged any place on the screen.  Set
19032      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19033      * parameters if you want to lock the drag to the x axis.
19034      * @method setYConstraint
19035      * @param {int} iUp the number of pixels the element can move up
19036      * @param {int} iDown the number of pixels the element can move down
19037      * @param {int} iTickSize optional parameter for specifying that the
19038      * element should move iTickSize pixels at a time.
19039      */
19040     setYConstraint: function(iUp, iDown, iTickSize) {
19041         this.topConstraint = iUp;
19042         this.bottomConstraint = iDown;
19043
19044         this.minY = this.initPageY - iUp;
19045         this.maxY = this.initPageY + iDown;
19046         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19047
19048         this.constrainY = true;
19049
19050     },
19051
19052     /**
19053      * resetConstraints must be called if you manually reposition a dd element.
19054      * @method resetConstraints
19055      * @param {boolean} maintainOffset
19056      */
19057     resetConstraints: function() {
19058
19059
19060         // Maintain offsets if necessary
19061         if (this.initPageX || this.initPageX === 0) {
19062             // figure out how much this thing has moved
19063             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19064             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19065
19066             this.setInitPosition(dx, dy);
19067
19068         // This is the first time we have detected the element's position
19069         } else {
19070             this.setInitPosition();
19071         }
19072
19073         if (this.constrainX) {
19074             this.setXConstraint( this.leftConstraint,
19075                                  this.rightConstraint,
19076                                  this.xTickSize        );
19077         }
19078
19079         if (this.constrainY) {
19080             this.setYConstraint( this.topConstraint,
19081                                  this.bottomConstraint,
19082                                  this.yTickSize         );
19083         }
19084     },
19085
19086     /**
19087      * Normally the drag element is moved pixel by pixel, but we can specify
19088      * that it move a number of pixels at a time.  This method resolves the
19089      * location when we have it set up like this.
19090      * @method getTick
19091      * @param {int} val where we want to place the object
19092      * @param {int[]} tickArray sorted array of valid points
19093      * @return {int} the closest tick
19094      * @private
19095      */
19096     getTick: function(val, tickArray) {
19097
19098         if (!tickArray) {
19099             // If tick interval is not defined, it is effectively 1 pixel,
19100             // so we return the value passed to us.
19101             return val;
19102         } else if (tickArray[0] >= val) {
19103             // The value is lower than the first tick, so we return the first
19104             // tick.
19105             return tickArray[0];
19106         } else {
19107             for (var i=0, len=tickArray.length; i<len; ++i) {
19108                 var next = i + 1;
19109                 if (tickArray[next] && tickArray[next] >= val) {
19110                     var diff1 = val - tickArray[i];
19111                     var diff2 = tickArray[next] - val;
19112                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19113                 }
19114             }
19115
19116             // The value is larger than the last tick, so we return the last
19117             // tick.
19118             return tickArray[tickArray.length - 1];
19119         }
19120     },
19121
19122     /**
19123      * toString method
19124      * @method toString
19125      * @return {string} string representation of the dd obj
19126      */
19127     toString: function() {
19128         return ("DragDrop " + this.id);
19129     }
19130
19131 });
19132
19133 })();
19134 /*
19135  * Based on:
19136  * Ext JS Library 1.1.1
19137  * Copyright(c) 2006-2007, Ext JS, LLC.
19138  *
19139  * Originally Released Under LGPL - original licence link has changed is not relivant.
19140  *
19141  * Fork - LGPL
19142  * <script type="text/javascript">
19143  */
19144
19145
19146 /**
19147  * The drag and drop utility provides a framework for building drag and drop
19148  * applications.  In addition to enabling drag and drop for specific elements,
19149  * the drag and drop elements are tracked by the manager class, and the
19150  * interactions between the various elements are tracked during the drag and
19151  * the implementing code is notified about these important moments.
19152  */
19153
19154 // Only load the library once.  Rewriting the manager class would orphan
19155 // existing drag and drop instances.
19156 if (!Roo.dd.DragDropMgr) {
19157
19158 /**
19159  * @class Roo.dd.DragDropMgr
19160  * DragDropMgr is a singleton that tracks the element interaction for
19161  * all DragDrop items in the window.  Generally, you will not call
19162  * this class directly, but it does have helper methods that could
19163  * be useful in your DragDrop implementations.
19164  * @singleton
19165  */
19166 Roo.dd.DragDropMgr = function() {
19167
19168     var Event = Roo.EventManager;
19169
19170     return {
19171
19172         /**
19173          * Two dimensional Array of registered DragDrop objects.  The first
19174          * dimension is the DragDrop item group, the second the DragDrop
19175          * object.
19176          * @property ids
19177          * @type {string: string}
19178          * @private
19179          * @static
19180          */
19181         ids: {},
19182
19183         /**
19184          * Array of element ids defined as drag handles.  Used to determine
19185          * if the element that generated the mousedown event is actually the
19186          * handle and not the html element itself.
19187          * @property handleIds
19188          * @type {string: string}
19189          * @private
19190          * @static
19191          */
19192         handleIds: {},
19193
19194         /**
19195          * the DragDrop object that is currently being dragged
19196          * @property dragCurrent
19197          * @type DragDrop
19198          * @private
19199          * @static
19200          **/
19201         dragCurrent: null,
19202
19203         /**
19204          * the DragDrop object(s) that are being hovered over
19205          * @property dragOvers
19206          * @type Array
19207          * @private
19208          * @static
19209          */
19210         dragOvers: {},
19211
19212         /**
19213          * the X distance between the cursor and the object being dragged
19214          * @property deltaX
19215          * @type int
19216          * @private
19217          * @static
19218          */
19219         deltaX: 0,
19220
19221         /**
19222          * the Y distance between the cursor and the object being dragged
19223          * @property deltaY
19224          * @type int
19225          * @private
19226          * @static
19227          */
19228         deltaY: 0,
19229
19230         /**
19231          * Flag to determine if we should prevent the default behavior of the
19232          * events we define. By default this is true, but this can be set to
19233          * false if you need the default behavior (not recommended)
19234          * @property preventDefault
19235          * @type boolean
19236          * @static
19237          */
19238         preventDefault: true,
19239
19240         /**
19241          * Flag to determine if we should stop the propagation of the events
19242          * we generate. This is true by default but you may want to set it to
19243          * false if the html element contains other features that require the
19244          * mouse click.
19245          * @property stopPropagation
19246          * @type boolean
19247          * @static
19248          */
19249         stopPropagation: true,
19250
19251         /**
19252          * Internal flag that is set to true when drag and drop has been
19253          * intialized
19254          * @property initialized
19255          * @private
19256          * @static
19257          */
19258         initalized: false,
19259
19260         /**
19261          * All drag and drop can be disabled.
19262          * @property locked
19263          * @private
19264          * @static
19265          */
19266         locked: false,
19267
19268         /**
19269          * Called the first time an element is registered.
19270          * @method init
19271          * @private
19272          * @static
19273          */
19274         init: function() {
19275             this.initialized = true;
19276         },
19277
19278         /**
19279          * In point mode, drag and drop interaction is defined by the
19280          * location of the cursor during the drag/drop
19281          * @property POINT
19282          * @type int
19283          * @static
19284          */
19285         POINT: 0,
19286
19287         /**
19288          * In intersect mode, drag and drop interactio nis defined by the
19289          * overlap of two or more drag and drop objects.
19290          * @property INTERSECT
19291          * @type int
19292          * @static
19293          */
19294         INTERSECT: 1,
19295
19296         /**
19297          * The current drag and drop mode.  Default: POINT
19298          * @property mode
19299          * @type int
19300          * @static
19301          */
19302         mode: 0,
19303
19304         /**
19305          * Runs method on all drag and drop objects
19306          * @method _execOnAll
19307          * @private
19308          * @static
19309          */
19310         _execOnAll: function(sMethod, args) {
19311             for (var i in this.ids) {
19312                 for (var j in this.ids[i]) {
19313                     var oDD = this.ids[i][j];
19314                     if (! this.isTypeOfDD(oDD)) {
19315                         continue;
19316                     }
19317                     oDD[sMethod].apply(oDD, args);
19318                 }
19319             }
19320         },
19321
19322         /**
19323          * Drag and drop initialization.  Sets up the global event handlers
19324          * @method _onLoad
19325          * @private
19326          * @static
19327          */
19328         _onLoad: function() {
19329
19330             this.init();
19331
19332             if (!Roo.isTouch) {
19333                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19334                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19335             }
19336             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19337             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19338             
19339             Event.on(window,   "unload",    this._onUnload, this, true);
19340             Event.on(window,   "resize",    this._onResize, this, true);
19341             // Event.on(window,   "mouseout",    this._test);
19342
19343         },
19344
19345         /**
19346          * Reset constraints on all drag and drop objs
19347          * @method _onResize
19348          * @private
19349          * @static
19350          */
19351         _onResize: function(e) {
19352             this._execOnAll("resetConstraints", []);
19353         },
19354
19355         /**
19356          * Lock all drag and drop functionality
19357          * @method lock
19358          * @static
19359          */
19360         lock: function() { this.locked = true; },
19361
19362         /**
19363          * Unlock all drag and drop functionality
19364          * @method unlock
19365          * @static
19366          */
19367         unlock: function() { this.locked = false; },
19368
19369         /**
19370          * Is drag and drop locked?
19371          * @method isLocked
19372          * @return {boolean} True if drag and drop is locked, false otherwise.
19373          * @static
19374          */
19375         isLocked: function() { return this.locked; },
19376
19377         /**
19378          * Location cache that is set for all drag drop objects when a drag is
19379          * initiated, cleared when the drag is finished.
19380          * @property locationCache
19381          * @private
19382          * @static
19383          */
19384         locationCache: {},
19385
19386         /**
19387          * Set useCache to false if you want to force object the lookup of each
19388          * drag and drop linked element constantly during a drag.
19389          * @property useCache
19390          * @type boolean
19391          * @static
19392          */
19393         useCache: true,
19394
19395         /**
19396          * The number of pixels that the mouse needs to move after the
19397          * mousedown before the drag is initiated.  Default=3;
19398          * @property clickPixelThresh
19399          * @type int
19400          * @static
19401          */
19402         clickPixelThresh: 3,
19403
19404         /**
19405          * The number of milliseconds after the mousedown event to initiate the
19406          * drag if we don't get a mouseup event. Default=1000
19407          * @property clickTimeThresh
19408          * @type int
19409          * @static
19410          */
19411         clickTimeThresh: 350,
19412
19413         /**
19414          * Flag that indicates that either the drag pixel threshold or the
19415          * mousdown time threshold has been met
19416          * @property dragThreshMet
19417          * @type boolean
19418          * @private
19419          * @static
19420          */
19421         dragThreshMet: false,
19422
19423         /**
19424          * Timeout used for the click time threshold
19425          * @property clickTimeout
19426          * @type Object
19427          * @private
19428          * @static
19429          */
19430         clickTimeout: null,
19431
19432         /**
19433          * The X position of the mousedown event stored for later use when a
19434          * drag threshold is met.
19435          * @property startX
19436          * @type int
19437          * @private
19438          * @static
19439          */
19440         startX: 0,
19441
19442         /**
19443          * The Y position of the mousedown event stored for later use when a
19444          * drag threshold is met.
19445          * @property startY
19446          * @type int
19447          * @private
19448          * @static
19449          */
19450         startY: 0,
19451
19452         /**
19453          * Each DragDrop instance must be registered with the DragDropMgr.
19454          * This is executed in DragDrop.init()
19455          * @method regDragDrop
19456          * @param {DragDrop} oDD the DragDrop object to register
19457          * @param {String} sGroup the name of the group this element belongs to
19458          * @static
19459          */
19460         regDragDrop: function(oDD, sGroup) {
19461             if (!this.initialized) { this.init(); }
19462
19463             if (!this.ids[sGroup]) {
19464                 this.ids[sGroup] = {};
19465             }
19466             this.ids[sGroup][oDD.id] = oDD;
19467         },
19468
19469         /**
19470          * Removes the supplied dd instance from the supplied group. Executed
19471          * by DragDrop.removeFromGroup, so don't call this function directly.
19472          * @method removeDDFromGroup
19473          * @private
19474          * @static
19475          */
19476         removeDDFromGroup: function(oDD, sGroup) {
19477             if (!this.ids[sGroup]) {
19478                 this.ids[sGroup] = {};
19479             }
19480
19481             var obj = this.ids[sGroup];
19482             if (obj && obj[oDD.id]) {
19483                 delete obj[oDD.id];
19484             }
19485         },
19486
19487         /**
19488          * Unregisters a drag and drop item.  This is executed in
19489          * DragDrop.unreg, use that method instead of calling this directly.
19490          * @method _remove
19491          * @private
19492          * @static
19493          */
19494         _remove: function(oDD) {
19495             for (var g in oDD.groups) {
19496                 if (g && this.ids[g][oDD.id]) {
19497                     delete this.ids[g][oDD.id];
19498                 }
19499             }
19500             delete this.handleIds[oDD.id];
19501         },
19502
19503         /**
19504          * Each DragDrop handle element must be registered.  This is done
19505          * automatically when executing DragDrop.setHandleElId()
19506          * @method regHandle
19507          * @param {String} sDDId the DragDrop id this element is a handle for
19508          * @param {String} sHandleId the id of the element that is the drag
19509          * handle
19510          * @static
19511          */
19512         regHandle: function(sDDId, sHandleId) {
19513             if (!this.handleIds[sDDId]) {
19514                 this.handleIds[sDDId] = {};
19515             }
19516             this.handleIds[sDDId][sHandleId] = sHandleId;
19517         },
19518
19519         /**
19520          * Utility function to determine if a given element has been
19521          * registered as a drag drop item.
19522          * @method isDragDrop
19523          * @param {String} id the element id to check
19524          * @return {boolean} true if this element is a DragDrop item,
19525          * false otherwise
19526          * @static
19527          */
19528         isDragDrop: function(id) {
19529             return ( this.getDDById(id) ) ? true : false;
19530         },
19531
19532         /**
19533          * Returns the drag and drop instances that are in all groups the
19534          * passed in instance belongs to.
19535          * @method getRelated
19536          * @param {DragDrop} p_oDD the obj to get related data for
19537          * @param {boolean} bTargetsOnly if true, only return targetable objs
19538          * @return {DragDrop[]} the related instances
19539          * @static
19540          */
19541         getRelated: function(p_oDD, bTargetsOnly) {
19542             var oDDs = [];
19543             for (var i in p_oDD.groups) {
19544                 for (j in this.ids[i]) {
19545                     var dd = this.ids[i][j];
19546                     if (! this.isTypeOfDD(dd)) {
19547                         continue;
19548                     }
19549                     if (!bTargetsOnly || dd.isTarget) {
19550                         oDDs[oDDs.length] = dd;
19551                     }
19552                 }
19553             }
19554
19555             return oDDs;
19556         },
19557
19558         /**
19559          * Returns true if the specified dd target is a legal target for
19560          * the specifice drag obj
19561          * @method isLegalTarget
19562          * @param {DragDrop} the drag obj
19563          * @param {DragDrop} the target
19564          * @return {boolean} true if the target is a legal target for the
19565          * dd obj
19566          * @static
19567          */
19568         isLegalTarget: function (oDD, oTargetDD) {
19569             var targets = this.getRelated(oDD, true);
19570             for (var i=0, len=targets.length;i<len;++i) {
19571                 if (targets[i].id == oTargetDD.id) {
19572                     return true;
19573                 }
19574             }
19575
19576             return false;
19577         },
19578
19579         /**
19580          * My goal is to be able to transparently determine if an object is
19581          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19582          * returns "object", oDD.constructor.toString() always returns
19583          * "DragDrop" and not the name of the subclass.  So for now it just
19584          * evaluates a well-known variable in DragDrop.
19585          * @method isTypeOfDD
19586          * @param {Object} the object to evaluate
19587          * @return {boolean} true if typeof oDD = DragDrop
19588          * @static
19589          */
19590         isTypeOfDD: function (oDD) {
19591             return (oDD && oDD.__ygDragDrop);
19592         },
19593
19594         /**
19595          * Utility function to determine if a given element has been
19596          * registered as a drag drop handle for the given Drag Drop object.
19597          * @method isHandle
19598          * @param {String} id the element id to check
19599          * @return {boolean} true if this element is a DragDrop handle, false
19600          * otherwise
19601          * @static
19602          */
19603         isHandle: function(sDDId, sHandleId) {
19604             return ( this.handleIds[sDDId] &&
19605                             this.handleIds[sDDId][sHandleId] );
19606         },
19607
19608         /**
19609          * Returns the DragDrop instance for a given id
19610          * @method getDDById
19611          * @param {String} id the id of the DragDrop object
19612          * @return {DragDrop} the drag drop object, null if it is not found
19613          * @static
19614          */
19615         getDDById: function(id) {
19616             for (var i in this.ids) {
19617                 if (this.ids[i][id]) {
19618                     return this.ids[i][id];
19619                 }
19620             }
19621             return null;
19622         },
19623
19624         /**
19625          * Fired after a registered DragDrop object gets the mousedown event.
19626          * Sets up the events required to track the object being dragged
19627          * @method handleMouseDown
19628          * @param {Event} e the event
19629          * @param oDD the DragDrop object being dragged
19630          * @private
19631          * @static
19632          */
19633         handleMouseDown: function(e, oDD) {
19634             if(Roo.QuickTips){
19635                 Roo.QuickTips.disable();
19636             }
19637             this.currentTarget = e.getTarget();
19638
19639             this.dragCurrent = oDD;
19640
19641             var el = oDD.getEl();
19642
19643             // track start position
19644             this.startX = e.getPageX();
19645             this.startY = e.getPageY();
19646
19647             this.deltaX = this.startX - el.offsetLeft;
19648             this.deltaY = this.startY - el.offsetTop;
19649
19650             this.dragThreshMet = false;
19651
19652             this.clickTimeout = setTimeout(
19653                     function() {
19654                         var DDM = Roo.dd.DDM;
19655                         DDM.startDrag(DDM.startX, DDM.startY);
19656                     },
19657                     this.clickTimeThresh );
19658         },
19659
19660         /**
19661          * Fired when either the drag pixel threshol or the mousedown hold
19662          * time threshold has been met.
19663          * @method startDrag
19664          * @param x {int} the X position of the original mousedown
19665          * @param y {int} the Y position of the original mousedown
19666          * @static
19667          */
19668         startDrag: function(x, y) {
19669             clearTimeout(this.clickTimeout);
19670             if (this.dragCurrent) {
19671                 this.dragCurrent.b4StartDrag(x, y);
19672                 this.dragCurrent.startDrag(x, y);
19673             }
19674             this.dragThreshMet = true;
19675         },
19676
19677         /**
19678          * Internal function to handle the mouseup event.  Will be invoked
19679          * from the context of the document.
19680          * @method handleMouseUp
19681          * @param {Event} e the event
19682          * @private
19683          * @static
19684          */
19685         handleMouseUp: function(e) {
19686
19687             if(Roo.QuickTips){
19688                 Roo.QuickTips.enable();
19689             }
19690             if (! this.dragCurrent) {
19691                 return;
19692             }
19693
19694             clearTimeout(this.clickTimeout);
19695
19696             if (this.dragThreshMet) {
19697                 this.fireEvents(e, true);
19698             } else {
19699             }
19700
19701             this.stopDrag(e);
19702
19703             this.stopEvent(e);
19704         },
19705
19706         /**
19707          * Utility to stop event propagation and event default, if these
19708          * features are turned on.
19709          * @method stopEvent
19710          * @param {Event} e the event as returned by this.getEvent()
19711          * @static
19712          */
19713         stopEvent: function(e){
19714             if(this.stopPropagation) {
19715                 e.stopPropagation();
19716             }
19717
19718             if (this.preventDefault) {
19719                 e.preventDefault();
19720             }
19721         },
19722
19723         /**
19724          * Internal function to clean up event handlers after the drag
19725          * operation is complete
19726          * @method stopDrag
19727          * @param {Event} e the event
19728          * @private
19729          * @static
19730          */
19731         stopDrag: function(e) {
19732             // Fire the drag end event for the item that was dragged
19733             if (this.dragCurrent) {
19734                 if (this.dragThreshMet) {
19735                     this.dragCurrent.b4EndDrag(e);
19736                     this.dragCurrent.endDrag(e);
19737                 }
19738
19739                 this.dragCurrent.onMouseUp(e);
19740             }
19741
19742             this.dragCurrent = null;
19743             this.dragOvers = {};
19744         },
19745
19746         /**
19747          * Internal function to handle the mousemove event.  Will be invoked
19748          * from the context of the html element.
19749          *
19750          * @TODO figure out what we can do about mouse events lost when the
19751          * user drags objects beyond the window boundary.  Currently we can
19752          * detect this in internet explorer by verifying that the mouse is
19753          * down during the mousemove event.  Firefox doesn't give us the
19754          * button state on the mousemove event.
19755          * @method handleMouseMove
19756          * @param {Event} e the event
19757          * @private
19758          * @static
19759          */
19760         handleMouseMove: function(e) {
19761             if (! this.dragCurrent) {
19762                 return true;
19763             }
19764
19765             // var button = e.which || e.button;
19766
19767             // check for IE mouseup outside of page boundary
19768             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19769                 this.stopEvent(e);
19770                 return this.handleMouseUp(e);
19771             }
19772
19773             if (!this.dragThreshMet) {
19774                 var diffX = Math.abs(this.startX - e.getPageX());
19775                 var diffY = Math.abs(this.startY - e.getPageY());
19776                 if (diffX > this.clickPixelThresh ||
19777                             diffY > this.clickPixelThresh) {
19778                     this.startDrag(this.startX, this.startY);
19779                 }
19780             }
19781
19782             if (this.dragThreshMet) {
19783                 this.dragCurrent.b4Drag(e);
19784                 this.dragCurrent.onDrag(e);
19785                 if(!this.dragCurrent.moveOnly){
19786                     this.fireEvents(e, false);
19787                 }
19788             }
19789
19790             this.stopEvent(e);
19791
19792             return true;
19793         },
19794
19795         /**
19796          * Iterates over all of the DragDrop elements to find ones we are
19797          * hovering over or dropping on
19798          * @method fireEvents
19799          * @param {Event} e the event
19800          * @param {boolean} isDrop is this a drop op or a mouseover op?
19801          * @private
19802          * @static
19803          */
19804         fireEvents: function(e, isDrop) {
19805             var dc = this.dragCurrent;
19806
19807             // If the user did the mouse up outside of the window, we could
19808             // get here even though we have ended the drag.
19809             if (!dc || dc.isLocked()) {
19810                 return;
19811             }
19812
19813             var pt = e.getPoint();
19814
19815             // cache the previous dragOver array
19816             var oldOvers = [];
19817
19818             var outEvts   = [];
19819             var overEvts  = [];
19820             var dropEvts  = [];
19821             var enterEvts = [];
19822
19823             // Check to see if the object(s) we were hovering over is no longer
19824             // being hovered over so we can fire the onDragOut event
19825             for (var i in this.dragOvers) {
19826
19827                 var ddo = this.dragOvers[i];
19828
19829                 if (! this.isTypeOfDD(ddo)) {
19830                     continue;
19831                 }
19832
19833                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19834                     outEvts.push( ddo );
19835                 }
19836
19837                 oldOvers[i] = true;
19838                 delete this.dragOvers[i];
19839             }
19840
19841             for (var sGroup in dc.groups) {
19842
19843                 if ("string" != typeof sGroup) {
19844                     continue;
19845                 }
19846
19847                 for (i in this.ids[sGroup]) {
19848                     var oDD = this.ids[sGroup][i];
19849                     if (! this.isTypeOfDD(oDD)) {
19850                         continue;
19851                     }
19852
19853                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19854                         if (this.isOverTarget(pt, oDD, this.mode)) {
19855                             // look for drop interactions
19856                             if (isDrop) {
19857                                 dropEvts.push( oDD );
19858                             // look for drag enter and drag over interactions
19859                             } else {
19860
19861                                 // initial drag over: dragEnter fires
19862                                 if (!oldOvers[oDD.id]) {
19863                                     enterEvts.push( oDD );
19864                                 // subsequent drag overs: dragOver fires
19865                                 } else {
19866                                     overEvts.push( oDD );
19867                                 }
19868
19869                                 this.dragOvers[oDD.id] = oDD;
19870                             }
19871                         }
19872                     }
19873                 }
19874             }
19875
19876             if (this.mode) {
19877                 if (outEvts.length) {
19878                     dc.b4DragOut(e, outEvts);
19879                     dc.onDragOut(e, outEvts);
19880                 }
19881
19882                 if (enterEvts.length) {
19883                     dc.onDragEnter(e, enterEvts);
19884                 }
19885
19886                 if (overEvts.length) {
19887                     dc.b4DragOver(e, overEvts);
19888                     dc.onDragOver(e, overEvts);
19889                 }
19890
19891                 if (dropEvts.length) {
19892                     dc.b4DragDrop(e, dropEvts);
19893                     dc.onDragDrop(e, dropEvts);
19894                 }
19895
19896             } else {
19897                 // fire dragout events
19898                 var len = 0;
19899                 for (i=0, len=outEvts.length; i<len; ++i) {
19900                     dc.b4DragOut(e, outEvts[i].id);
19901                     dc.onDragOut(e, outEvts[i].id);
19902                 }
19903
19904                 // fire enter events
19905                 for (i=0,len=enterEvts.length; i<len; ++i) {
19906                     // dc.b4DragEnter(e, oDD.id);
19907                     dc.onDragEnter(e, enterEvts[i].id);
19908                 }
19909
19910                 // fire over events
19911                 for (i=0,len=overEvts.length; i<len; ++i) {
19912                     dc.b4DragOver(e, overEvts[i].id);
19913                     dc.onDragOver(e, overEvts[i].id);
19914                 }
19915
19916                 // fire drop events
19917                 for (i=0, len=dropEvts.length; i<len; ++i) {
19918                     dc.b4DragDrop(e, dropEvts[i].id);
19919                     dc.onDragDrop(e, dropEvts[i].id);
19920                 }
19921
19922             }
19923
19924             // notify about a drop that did not find a target
19925             if (isDrop && !dropEvts.length) {
19926                 dc.onInvalidDrop(e);
19927             }
19928
19929         },
19930
19931         /**
19932          * Helper function for getting the best match from the list of drag
19933          * and drop objects returned by the drag and drop events when we are
19934          * in INTERSECT mode.  It returns either the first object that the
19935          * cursor is over, or the object that has the greatest overlap with
19936          * the dragged element.
19937          * @method getBestMatch
19938          * @param  {DragDrop[]} dds The array of drag and drop objects
19939          * targeted
19940          * @return {DragDrop}       The best single match
19941          * @static
19942          */
19943         getBestMatch: function(dds) {
19944             var winner = null;
19945             // Return null if the input is not what we expect
19946             //if (!dds || !dds.length || dds.length == 0) {
19947                // winner = null;
19948             // If there is only one item, it wins
19949             //} else if (dds.length == 1) {
19950
19951             var len = dds.length;
19952
19953             if (len == 1) {
19954                 winner = dds[0];
19955             } else {
19956                 // Loop through the targeted items
19957                 for (var i=0; i<len; ++i) {
19958                     var dd = dds[i];
19959                     // If the cursor is over the object, it wins.  If the
19960                     // cursor is over multiple matches, the first one we come
19961                     // to wins.
19962                     if (dd.cursorIsOver) {
19963                         winner = dd;
19964                         break;
19965                     // Otherwise the object with the most overlap wins
19966                     } else {
19967                         if (!winner ||
19968                             winner.overlap.getArea() < dd.overlap.getArea()) {
19969                             winner = dd;
19970                         }
19971                     }
19972                 }
19973             }
19974
19975             return winner;
19976         },
19977
19978         /**
19979          * Refreshes the cache of the top-left and bottom-right points of the
19980          * drag and drop objects in the specified group(s).  This is in the
19981          * format that is stored in the drag and drop instance, so typical
19982          * usage is:
19983          * <code>
19984          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19985          * </code>
19986          * Alternatively:
19987          * <code>
19988          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19989          * </code>
19990          * @TODO this really should be an indexed array.  Alternatively this
19991          * method could accept both.
19992          * @method refreshCache
19993          * @param {Object} groups an associative array of groups to refresh
19994          * @static
19995          */
19996         refreshCache: function(groups) {
19997             for (var sGroup in groups) {
19998                 if ("string" != typeof sGroup) {
19999                     continue;
20000                 }
20001                 for (var i in this.ids[sGroup]) {
20002                     var oDD = this.ids[sGroup][i];
20003
20004                     if (this.isTypeOfDD(oDD)) {
20005                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20006                         var loc = this.getLocation(oDD);
20007                         if (loc) {
20008                             this.locationCache[oDD.id] = loc;
20009                         } else {
20010                             delete this.locationCache[oDD.id];
20011                             // this will unregister the drag and drop object if
20012                             // the element is not in a usable state
20013                             // oDD.unreg();
20014                         }
20015                     }
20016                 }
20017             }
20018         },
20019
20020         /**
20021          * This checks to make sure an element exists and is in the DOM.  The
20022          * main purpose is to handle cases where innerHTML is used to remove
20023          * drag and drop objects from the DOM.  IE provides an 'unspecified
20024          * error' when trying to access the offsetParent of such an element
20025          * @method verifyEl
20026          * @param {HTMLElement} el the element to check
20027          * @return {boolean} true if the element looks usable
20028          * @static
20029          */
20030         verifyEl: function(el) {
20031             if (el) {
20032                 var parent;
20033                 if(Roo.isIE){
20034                     try{
20035                         parent = el.offsetParent;
20036                     }catch(e){}
20037                 }else{
20038                     parent = el.offsetParent;
20039                 }
20040                 if (parent) {
20041                     return true;
20042                 }
20043             }
20044
20045             return false;
20046         },
20047
20048         /**
20049          * Returns a Region object containing the drag and drop element's position
20050          * and size, including the padding configured for it
20051          * @method getLocation
20052          * @param {DragDrop} oDD the drag and drop object to get the
20053          *                       location for
20054          * @return {Roo.lib.Region} a Region object representing the total area
20055          *                             the element occupies, including any padding
20056          *                             the instance is configured for.
20057          * @static
20058          */
20059         getLocation: function(oDD) {
20060             if (! this.isTypeOfDD(oDD)) {
20061                 return null;
20062             }
20063
20064             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20065
20066             try {
20067                 pos= Roo.lib.Dom.getXY(el);
20068             } catch (e) { }
20069
20070             if (!pos) {
20071                 return null;
20072             }
20073
20074             x1 = pos[0];
20075             x2 = x1 + el.offsetWidth;
20076             y1 = pos[1];
20077             y2 = y1 + el.offsetHeight;
20078
20079             t = y1 - oDD.padding[0];
20080             r = x2 + oDD.padding[1];
20081             b = y2 + oDD.padding[2];
20082             l = x1 - oDD.padding[3];
20083
20084             return new Roo.lib.Region( t, r, b, l );
20085         },
20086
20087         /**
20088          * Checks the cursor location to see if it over the target
20089          * @method isOverTarget
20090          * @param {Roo.lib.Point} pt The point to evaluate
20091          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20092          * @return {boolean} true if the mouse is over the target
20093          * @private
20094          * @static
20095          */
20096         isOverTarget: function(pt, oTarget, intersect) {
20097             // use cache if available
20098             var loc = this.locationCache[oTarget.id];
20099             if (!loc || !this.useCache) {
20100                 loc = this.getLocation(oTarget);
20101                 this.locationCache[oTarget.id] = loc;
20102
20103             }
20104
20105             if (!loc) {
20106                 return false;
20107             }
20108
20109             oTarget.cursorIsOver = loc.contains( pt );
20110
20111             // DragDrop is using this as a sanity check for the initial mousedown
20112             // in this case we are done.  In POINT mode, if the drag obj has no
20113             // contraints, we are also done. Otherwise we need to evaluate the
20114             // location of the target as related to the actual location of the
20115             // dragged element.
20116             var dc = this.dragCurrent;
20117             if (!dc || !dc.getTargetCoord ||
20118                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20119                 return oTarget.cursorIsOver;
20120             }
20121
20122             oTarget.overlap = null;
20123
20124             // Get the current location of the drag element, this is the
20125             // location of the mouse event less the delta that represents
20126             // where the original mousedown happened on the element.  We
20127             // need to consider constraints and ticks as well.
20128             var pos = dc.getTargetCoord(pt.x, pt.y);
20129
20130             var el = dc.getDragEl();
20131             var curRegion = new Roo.lib.Region( pos.y,
20132                                                    pos.x + el.offsetWidth,
20133                                                    pos.y + el.offsetHeight,
20134                                                    pos.x );
20135
20136             var overlap = curRegion.intersect(loc);
20137
20138             if (overlap) {
20139                 oTarget.overlap = overlap;
20140                 return (intersect) ? true : oTarget.cursorIsOver;
20141             } else {
20142                 return false;
20143             }
20144         },
20145
20146         /**
20147          * unload event handler
20148          * @method _onUnload
20149          * @private
20150          * @static
20151          */
20152         _onUnload: function(e, me) {
20153             Roo.dd.DragDropMgr.unregAll();
20154         },
20155
20156         /**
20157          * Cleans up the drag and drop events and objects.
20158          * @method unregAll
20159          * @private
20160          * @static
20161          */
20162         unregAll: function() {
20163
20164             if (this.dragCurrent) {
20165                 this.stopDrag();
20166                 this.dragCurrent = null;
20167             }
20168
20169             this._execOnAll("unreg", []);
20170
20171             for (i in this.elementCache) {
20172                 delete this.elementCache[i];
20173             }
20174
20175             this.elementCache = {};
20176             this.ids = {};
20177         },
20178
20179         /**
20180          * A cache of DOM elements
20181          * @property elementCache
20182          * @private
20183          * @static
20184          */
20185         elementCache: {},
20186
20187         /**
20188          * Get the wrapper for the DOM element specified
20189          * @method getElWrapper
20190          * @param {String} id the id of the element to get
20191          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20192          * @private
20193          * @deprecated This wrapper isn't that useful
20194          * @static
20195          */
20196         getElWrapper: function(id) {
20197             var oWrapper = this.elementCache[id];
20198             if (!oWrapper || !oWrapper.el) {
20199                 oWrapper = this.elementCache[id] =
20200                     new this.ElementWrapper(Roo.getDom(id));
20201             }
20202             return oWrapper;
20203         },
20204
20205         /**
20206          * Returns the actual DOM element
20207          * @method getElement
20208          * @param {String} id the id of the elment to get
20209          * @return {Object} The element
20210          * @deprecated use Roo.getDom instead
20211          * @static
20212          */
20213         getElement: function(id) {
20214             return Roo.getDom(id);
20215         },
20216
20217         /**
20218          * Returns the style property for the DOM element (i.e.,
20219          * document.getElById(id).style)
20220          * @method getCss
20221          * @param {String} id the id of the elment to get
20222          * @return {Object} The style property of the element
20223          * @deprecated use Roo.getDom instead
20224          * @static
20225          */
20226         getCss: function(id) {
20227             var el = Roo.getDom(id);
20228             return (el) ? el.style : null;
20229         },
20230
20231         /**
20232          * Inner class for cached elements
20233          * @class DragDropMgr.ElementWrapper
20234          * @for DragDropMgr
20235          * @private
20236          * @deprecated
20237          */
20238         ElementWrapper: function(el) {
20239                 /**
20240                  * The element
20241                  * @property el
20242                  */
20243                 this.el = el || null;
20244                 /**
20245                  * The element id
20246                  * @property id
20247                  */
20248                 this.id = this.el && el.id;
20249                 /**
20250                  * A reference to the style property
20251                  * @property css
20252                  */
20253                 this.css = this.el && el.style;
20254             },
20255
20256         /**
20257          * Returns the X position of an html element
20258          * @method getPosX
20259          * @param el the element for which to get the position
20260          * @return {int} the X coordinate
20261          * @for DragDropMgr
20262          * @deprecated use Roo.lib.Dom.getX instead
20263          * @static
20264          */
20265         getPosX: function(el) {
20266             return Roo.lib.Dom.getX(el);
20267         },
20268
20269         /**
20270          * Returns the Y position of an html element
20271          * @method getPosY
20272          * @param el the element for which to get the position
20273          * @return {int} the Y coordinate
20274          * @deprecated use Roo.lib.Dom.getY instead
20275          * @static
20276          */
20277         getPosY: function(el) {
20278             return Roo.lib.Dom.getY(el);
20279         },
20280
20281         /**
20282          * Swap two nodes.  In IE, we use the native method, for others we
20283          * emulate the IE behavior
20284          * @method swapNode
20285          * @param n1 the first node to swap
20286          * @param n2 the other node to swap
20287          * @static
20288          */
20289         swapNode: function(n1, n2) {
20290             if (n1.swapNode) {
20291                 n1.swapNode(n2);
20292             } else {
20293                 var p = n2.parentNode;
20294                 var s = n2.nextSibling;
20295
20296                 if (s == n1) {
20297                     p.insertBefore(n1, n2);
20298                 } else if (n2 == n1.nextSibling) {
20299                     p.insertBefore(n2, n1);
20300                 } else {
20301                     n1.parentNode.replaceChild(n2, n1);
20302                     p.insertBefore(n1, s);
20303                 }
20304             }
20305         },
20306
20307         /**
20308          * Returns the current scroll position
20309          * @method getScroll
20310          * @private
20311          * @static
20312          */
20313         getScroll: function () {
20314             var t, l, dde=document.documentElement, db=document.body;
20315             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20316                 t = dde.scrollTop;
20317                 l = dde.scrollLeft;
20318             } else if (db) {
20319                 t = db.scrollTop;
20320                 l = db.scrollLeft;
20321             } else {
20322
20323             }
20324             return { top: t, left: l };
20325         },
20326
20327         /**
20328          * Returns the specified element style property
20329          * @method getStyle
20330          * @param {HTMLElement} el          the element
20331          * @param {string}      styleProp   the style property
20332          * @return {string} The value of the style property
20333          * @deprecated use Roo.lib.Dom.getStyle
20334          * @static
20335          */
20336         getStyle: function(el, styleProp) {
20337             return Roo.fly(el).getStyle(styleProp);
20338         },
20339
20340         /**
20341          * Gets the scrollTop
20342          * @method getScrollTop
20343          * @return {int} the document's scrollTop
20344          * @static
20345          */
20346         getScrollTop: function () { return this.getScroll().top; },
20347
20348         /**
20349          * Gets the scrollLeft
20350          * @method getScrollLeft
20351          * @return {int} the document's scrollTop
20352          * @static
20353          */
20354         getScrollLeft: function () { return this.getScroll().left; },
20355
20356         /**
20357          * Sets the x/y position of an element to the location of the
20358          * target element.
20359          * @method moveToEl
20360          * @param {HTMLElement} moveEl      The element to move
20361          * @param {HTMLElement} targetEl    The position reference element
20362          * @static
20363          */
20364         moveToEl: function (moveEl, targetEl) {
20365             var aCoord = Roo.lib.Dom.getXY(targetEl);
20366             Roo.lib.Dom.setXY(moveEl, aCoord);
20367         },
20368
20369         /**
20370          * Numeric array sort function
20371          * @method numericSort
20372          * @static
20373          */
20374         numericSort: function(a, b) { return (a - b); },
20375
20376         /**
20377          * Internal counter
20378          * @property _timeoutCount
20379          * @private
20380          * @static
20381          */
20382         _timeoutCount: 0,
20383
20384         /**
20385          * Trying to make the load order less important.  Without this we get
20386          * an error if this file is loaded before the Event Utility.
20387          * @method _addListeners
20388          * @private
20389          * @static
20390          */
20391         _addListeners: function() {
20392             var DDM = Roo.dd.DDM;
20393             if ( Roo.lib.Event && document ) {
20394                 DDM._onLoad();
20395             } else {
20396                 if (DDM._timeoutCount > 2000) {
20397                 } else {
20398                     setTimeout(DDM._addListeners, 10);
20399                     if (document && document.body) {
20400                         DDM._timeoutCount += 1;
20401                     }
20402                 }
20403             }
20404         },
20405
20406         /**
20407          * Recursively searches the immediate parent and all child nodes for
20408          * the handle element in order to determine wheter or not it was
20409          * clicked.
20410          * @method handleWasClicked
20411          * @param node the html element to inspect
20412          * @static
20413          */
20414         handleWasClicked: function(node, id) {
20415             if (this.isHandle(id, node.id)) {
20416                 return true;
20417             } else {
20418                 // check to see if this is a text node child of the one we want
20419                 var p = node.parentNode;
20420
20421                 while (p) {
20422                     if (this.isHandle(id, p.id)) {
20423                         return true;
20424                     } else {
20425                         p = p.parentNode;
20426                     }
20427                 }
20428             }
20429
20430             return false;
20431         }
20432
20433     };
20434
20435 }();
20436
20437 // shorter alias, save a few bytes
20438 Roo.dd.DDM = Roo.dd.DragDropMgr;
20439 Roo.dd.DDM._addListeners();
20440
20441 }/*
20442  * Based on:
20443  * Ext JS Library 1.1.1
20444  * Copyright(c) 2006-2007, Ext JS, LLC.
20445  *
20446  * Originally Released Under LGPL - original licence link has changed is not relivant.
20447  *
20448  * Fork - LGPL
20449  * <script type="text/javascript">
20450  */
20451
20452 /**
20453  * @class Roo.dd.DD
20454  * A DragDrop implementation where the linked element follows the
20455  * mouse cursor during a drag.
20456  * @extends Roo.dd.DragDrop
20457  * @constructor
20458  * @param {String} id the id of the linked element
20459  * @param {String} sGroup the group of related DragDrop items
20460  * @param {object} config an object containing configurable attributes
20461  *                Valid properties for DD:
20462  *                    scroll
20463  */
20464 Roo.dd.DD = function(id, sGroup, config) {
20465     if (id) {
20466         this.init(id, sGroup, config);
20467     }
20468 };
20469
20470 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20471
20472     /**
20473      * When set to true, the utility automatically tries to scroll the browser
20474      * window wehn a drag and drop element is dragged near the viewport boundary.
20475      * Defaults to true.
20476      * @property scroll
20477      * @type boolean
20478      */
20479     scroll: true,
20480
20481     /**
20482      * Sets the pointer offset to the distance between the linked element's top
20483      * left corner and the location the element was clicked
20484      * @method autoOffset
20485      * @param {int} iPageX the X coordinate of the click
20486      * @param {int} iPageY the Y coordinate of the click
20487      */
20488     autoOffset: function(iPageX, iPageY) {
20489         var x = iPageX - this.startPageX;
20490         var y = iPageY - this.startPageY;
20491         this.setDelta(x, y);
20492     },
20493
20494     /**
20495      * Sets the pointer offset.  You can call this directly to force the
20496      * offset to be in a particular location (e.g., pass in 0,0 to set it
20497      * to the center of the object)
20498      * @method setDelta
20499      * @param {int} iDeltaX the distance from the left
20500      * @param {int} iDeltaY the distance from the top
20501      */
20502     setDelta: function(iDeltaX, iDeltaY) {
20503         this.deltaX = iDeltaX;
20504         this.deltaY = iDeltaY;
20505     },
20506
20507     /**
20508      * Sets the drag element to the location of the mousedown or click event,
20509      * maintaining the cursor location relative to the location on the element
20510      * that was clicked.  Override this if you want to place the element in a
20511      * location other than where the cursor is.
20512      * @method setDragElPos
20513      * @param {int} iPageX the X coordinate of the mousedown or drag event
20514      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20515      */
20516     setDragElPos: function(iPageX, iPageY) {
20517         // the first time we do this, we are going to check to make sure
20518         // the element has css positioning
20519
20520         var el = this.getDragEl();
20521         this.alignElWithMouse(el, iPageX, iPageY);
20522     },
20523
20524     /**
20525      * Sets the element to the location of the mousedown or click event,
20526      * maintaining the cursor location relative to the location on the element
20527      * that was clicked.  Override this if you want to place the element in a
20528      * location other than where the cursor is.
20529      * @method alignElWithMouse
20530      * @param {HTMLElement} el the element to move
20531      * @param {int} iPageX the X coordinate of the mousedown or drag event
20532      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20533      */
20534     alignElWithMouse: function(el, iPageX, iPageY) {
20535         var oCoord = this.getTargetCoord(iPageX, iPageY);
20536         var fly = el.dom ? el : Roo.fly(el);
20537         if (!this.deltaSetXY) {
20538             var aCoord = [oCoord.x, oCoord.y];
20539             fly.setXY(aCoord);
20540             var newLeft = fly.getLeft(true);
20541             var newTop  = fly.getTop(true);
20542             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20543         } else {
20544             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20545         }
20546
20547         this.cachePosition(oCoord.x, oCoord.y);
20548         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20549         return oCoord;
20550     },
20551
20552     /**
20553      * Saves the most recent position so that we can reset the constraints and
20554      * tick marks on-demand.  We need to know this so that we can calculate the
20555      * number of pixels the element is offset from its original position.
20556      * @method cachePosition
20557      * @param iPageX the current x position (optional, this just makes it so we
20558      * don't have to look it up again)
20559      * @param iPageY the current y position (optional, this just makes it so we
20560      * don't have to look it up again)
20561      */
20562     cachePosition: function(iPageX, iPageY) {
20563         if (iPageX) {
20564             this.lastPageX = iPageX;
20565             this.lastPageY = iPageY;
20566         } else {
20567             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20568             this.lastPageX = aCoord[0];
20569             this.lastPageY = aCoord[1];
20570         }
20571     },
20572
20573     /**
20574      * Auto-scroll the window if the dragged object has been moved beyond the
20575      * visible window boundary.
20576      * @method autoScroll
20577      * @param {int} x the drag element's x position
20578      * @param {int} y the drag element's y position
20579      * @param {int} h the height of the drag element
20580      * @param {int} w the width of the drag element
20581      * @private
20582      */
20583     autoScroll: function(x, y, h, w) {
20584
20585         if (this.scroll) {
20586             // The client height
20587             var clientH = Roo.lib.Dom.getViewWidth();
20588
20589             // The client width
20590             var clientW = Roo.lib.Dom.getViewHeight();
20591
20592             // The amt scrolled down
20593             var st = this.DDM.getScrollTop();
20594
20595             // The amt scrolled right
20596             var sl = this.DDM.getScrollLeft();
20597
20598             // Location of the bottom of the element
20599             var bot = h + y;
20600
20601             // Location of the right of the element
20602             var right = w + x;
20603
20604             // The distance from the cursor to the bottom of the visible area,
20605             // adjusted so that we don't scroll if the cursor is beyond the
20606             // element drag constraints
20607             var toBot = (clientH + st - y - this.deltaY);
20608
20609             // The distance from the cursor to the right of the visible area
20610             var toRight = (clientW + sl - x - this.deltaX);
20611
20612
20613             // How close to the edge the cursor must be before we scroll
20614             // var thresh = (document.all) ? 100 : 40;
20615             var thresh = 40;
20616
20617             // How many pixels to scroll per autoscroll op.  This helps to reduce
20618             // clunky scrolling. IE is more sensitive about this ... it needs this
20619             // value to be higher.
20620             var scrAmt = (document.all) ? 80 : 30;
20621
20622             // Scroll down if we are near the bottom of the visible page and the
20623             // obj extends below the crease
20624             if ( bot > clientH && toBot < thresh ) {
20625                 window.scrollTo(sl, st + scrAmt);
20626             }
20627
20628             // Scroll up if the window is scrolled down and the top of the object
20629             // goes above the top border
20630             if ( y < st && st > 0 && y - st < thresh ) {
20631                 window.scrollTo(sl, st - scrAmt);
20632             }
20633
20634             // Scroll right if the obj is beyond the right border and the cursor is
20635             // near the border.
20636             if ( right > clientW && toRight < thresh ) {
20637                 window.scrollTo(sl + scrAmt, st);
20638             }
20639
20640             // Scroll left if the window has been scrolled to the right and the obj
20641             // extends past the left border
20642             if ( x < sl && sl > 0 && x - sl < thresh ) {
20643                 window.scrollTo(sl - scrAmt, st);
20644             }
20645         }
20646     },
20647
20648     /**
20649      * Finds the location the element should be placed if we want to move
20650      * it to where the mouse location less the click offset would place us.
20651      * @method getTargetCoord
20652      * @param {int} iPageX the X coordinate of the click
20653      * @param {int} iPageY the Y coordinate of the click
20654      * @return an object that contains the coordinates (Object.x and Object.y)
20655      * @private
20656      */
20657     getTargetCoord: function(iPageX, iPageY) {
20658
20659
20660         var x = iPageX - this.deltaX;
20661         var y = iPageY - this.deltaY;
20662
20663         if (this.constrainX) {
20664             if (x < this.minX) { x = this.minX; }
20665             if (x > this.maxX) { x = this.maxX; }
20666         }
20667
20668         if (this.constrainY) {
20669             if (y < this.minY) { y = this.minY; }
20670             if (y > this.maxY) { y = this.maxY; }
20671         }
20672
20673         x = this.getTick(x, this.xTicks);
20674         y = this.getTick(y, this.yTicks);
20675
20676
20677         return {x:x, y:y};
20678     },
20679
20680     /*
20681      * Sets up config options specific to this class. Overrides
20682      * Roo.dd.DragDrop, but all versions of this method through the
20683      * inheritance chain are called
20684      */
20685     applyConfig: function() {
20686         Roo.dd.DD.superclass.applyConfig.call(this);
20687         this.scroll = (this.config.scroll !== false);
20688     },
20689
20690     /*
20691      * Event that fires prior to the onMouseDown event.  Overrides
20692      * Roo.dd.DragDrop.
20693      */
20694     b4MouseDown: function(e) {
20695         // this.resetConstraints();
20696         this.autoOffset(e.getPageX(),
20697                             e.getPageY());
20698     },
20699
20700     /*
20701      * Event that fires prior to the onDrag event.  Overrides
20702      * Roo.dd.DragDrop.
20703      */
20704     b4Drag: function(e) {
20705         this.setDragElPos(e.getPageX(),
20706                             e.getPageY());
20707     },
20708
20709     toString: function() {
20710         return ("DD " + this.id);
20711     }
20712
20713     //////////////////////////////////////////////////////////////////////////
20714     // Debugging ygDragDrop events that can be overridden
20715     //////////////////////////////////////////////////////////////////////////
20716     /*
20717     startDrag: function(x, y) {
20718     },
20719
20720     onDrag: function(e) {
20721     },
20722
20723     onDragEnter: function(e, id) {
20724     },
20725
20726     onDragOver: function(e, id) {
20727     },
20728
20729     onDragOut: function(e, id) {
20730     },
20731
20732     onDragDrop: function(e, id) {
20733     },
20734
20735     endDrag: function(e) {
20736     }
20737
20738     */
20739
20740 });/*
20741  * Based on:
20742  * Ext JS Library 1.1.1
20743  * Copyright(c) 2006-2007, Ext JS, LLC.
20744  *
20745  * Originally Released Under LGPL - original licence link has changed is not relivant.
20746  *
20747  * Fork - LGPL
20748  * <script type="text/javascript">
20749  */
20750
20751 /**
20752  * @class Roo.dd.DDProxy
20753  * A DragDrop implementation that inserts an empty, bordered div into
20754  * the document that follows the cursor during drag operations.  At the time of
20755  * the click, the frame div is resized to the dimensions of the linked html
20756  * element, and moved to the exact location of the linked element.
20757  *
20758  * References to the "frame" element refer to the single proxy element that
20759  * was created to be dragged in place of all DDProxy elements on the
20760  * page.
20761  *
20762  * @extends Roo.dd.DD
20763  * @constructor
20764  * @param {String} id the id of the linked html element
20765  * @param {String} sGroup the group of related DragDrop objects
20766  * @param {object} config an object containing configurable attributes
20767  *                Valid properties for DDProxy in addition to those in DragDrop:
20768  *                   resizeFrame, centerFrame, dragElId
20769  */
20770 Roo.dd.DDProxy = function(id, sGroup, config) {
20771     if (id) {
20772         this.init(id, sGroup, config);
20773         this.initFrame();
20774     }
20775 };
20776
20777 /**
20778  * The default drag frame div id
20779  * @property Roo.dd.DDProxy.dragElId
20780  * @type String
20781  * @static
20782  */
20783 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20784
20785 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20786
20787     /**
20788      * By default we resize the drag frame to be the same size as the element
20789      * we want to drag (this is to get the frame effect).  We can turn it off
20790      * if we want a different behavior.
20791      * @property resizeFrame
20792      * @type boolean
20793      */
20794     resizeFrame: true,
20795
20796     /**
20797      * By default the frame is positioned exactly where the drag element is, so
20798      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20799      * you do not have constraints on the obj is to have the drag frame centered
20800      * around the cursor.  Set centerFrame to true for this effect.
20801      * @property centerFrame
20802      * @type boolean
20803      */
20804     centerFrame: false,
20805
20806     /**
20807      * Creates the proxy element if it does not yet exist
20808      * @method createFrame
20809      */
20810     createFrame: function() {
20811         var self = this;
20812         var body = document.body;
20813
20814         if (!body || !body.firstChild) {
20815             setTimeout( function() { self.createFrame(); }, 50 );
20816             return;
20817         }
20818
20819         var div = this.getDragEl();
20820
20821         if (!div) {
20822             div    = document.createElement("div");
20823             div.id = this.dragElId;
20824             var s  = div.style;
20825
20826             s.position   = "absolute";
20827             s.visibility = "hidden";
20828             s.cursor     = "move";
20829             s.border     = "2px solid #aaa";
20830             s.zIndex     = 999;
20831
20832             // appendChild can blow up IE if invoked prior to the window load event
20833             // while rendering a table.  It is possible there are other scenarios
20834             // that would cause this to happen as well.
20835             body.insertBefore(div, body.firstChild);
20836         }
20837     },
20838
20839     /**
20840      * Initialization for the drag frame element.  Must be called in the
20841      * constructor of all subclasses
20842      * @method initFrame
20843      */
20844     initFrame: function() {
20845         this.createFrame();
20846     },
20847
20848     applyConfig: function() {
20849         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20850
20851         this.resizeFrame = (this.config.resizeFrame !== false);
20852         this.centerFrame = (this.config.centerFrame);
20853         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20854     },
20855
20856     /**
20857      * Resizes the drag frame to the dimensions of the clicked object, positions
20858      * it over the object, and finally displays it
20859      * @method showFrame
20860      * @param {int} iPageX X click position
20861      * @param {int} iPageY Y click position
20862      * @private
20863      */
20864     showFrame: function(iPageX, iPageY) {
20865         var el = this.getEl();
20866         var dragEl = this.getDragEl();
20867         var s = dragEl.style;
20868
20869         this._resizeProxy();
20870
20871         if (this.centerFrame) {
20872             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20873                            Math.round(parseInt(s.height, 10)/2) );
20874         }
20875
20876         this.setDragElPos(iPageX, iPageY);
20877
20878         Roo.fly(dragEl).show();
20879     },
20880
20881     /**
20882      * The proxy is automatically resized to the dimensions of the linked
20883      * element when a drag is initiated, unless resizeFrame is set to false
20884      * @method _resizeProxy
20885      * @private
20886      */
20887     _resizeProxy: function() {
20888         if (this.resizeFrame) {
20889             var el = this.getEl();
20890             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20891         }
20892     },
20893
20894     // overrides Roo.dd.DragDrop
20895     b4MouseDown: function(e) {
20896         var x = e.getPageX();
20897         var y = e.getPageY();
20898         this.autoOffset(x, y);
20899         this.setDragElPos(x, y);
20900     },
20901
20902     // overrides Roo.dd.DragDrop
20903     b4StartDrag: function(x, y) {
20904         // show the drag frame
20905         this.showFrame(x, y);
20906     },
20907
20908     // overrides Roo.dd.DragDrop
20909     b4EndDrag: function(e) {
20910         Roo.fly(this.getDragEl()).hide();
20911     },
20912
20913     // overrides Roo.dd.DragDrop
20914     // By default we try to move the element to the last location of the frame.
20915     // This is so that the default behavior mirrors that of Roo.dd.DD.
20916     endDrag: function(e) {
20917
20918         var lel = this.getEl();
20919         var del = this.getDragEl();
20920
20921         // Show the drag frame briefly so we can get its position
20922         del.style.visibility = "";
20923
20924         this.beforeMove();
20925         // Hide the linked element before the move to get around a Safari
20926         // rendering bug.
20927         lel.style.visibility = "hidden";
20928         Roo.dd.DDM.moveToEl(lel, del);
20929         del.style.visibility = "hidden";
20930         lel.style.visibility = "";
20931
20932         this.afterDrag();
20933     },
20934
20935     beforeMove : function(){
20936
20937     },
20938
20939     afterDrag : function(){
20940
20941     },
20942
20943     toString: function() {
20944         return ("DDProxy " + this.id);
20945     }
20946
20947 });
20948 /*
20949  * Based on:
20950  * Ext JS Library 1.1.1
20951  * Copyright(c) 2006-2007, Ext JS, LLC.
20952  *
20953  * Originally Released Under LGPL - original licence link has changed is not relivant.
20954  *
20955  * Fork - LGPL
20956  * <script type="text/javascript">
20957  */
20958
20959  /**
20960  * @class Roo.dd.DDTarget
20961  * A DragDrop implementation that does not move, but can be a drop
20962  * target.  You would get the same result by simply omitting implementation
20963  * for the event callbacks, but this way we reduce the processing cost of the
20964  * event listener and the callbacks.
20965  * @extends Roo.dd.DragDrop
20966  * @constructor
20967  * @param {String} id the id of the element that is a drop target
20968  * @param {String} sGroup the group of related DragDrop objects
20969  * @param {object} config an object containing configurable attributes
20970  *                 Valid properties for DDTarget in addition to those in
20971  *                 DragDrop:
20972  *                    none
20973  */
20974 Roo.dd.DDTarget = function(id, sGroup, config) {
20975     if (id) {
20976         this.initTarget(id, sGroup, config);
20977     }
20978     if (config.listeners || config.events) { 
20979        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20980             listeners : config.listeners || {}, 
20981             events : config.events || {} 
20982         });    
20983     }
20984 };
20985
20986 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20987 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20988     toString: function() {
20989         return ("DDTarget " + this.id);
20990     }
20991 });
20992 /*
20993  * Based on:
20994  * Ext JS Library 1.1.1
20995  * Copyright(c) 2006-2007, Ext JS, LLC.
20996  *
20997  * Originally Released Under LGPL - original licence link has changed is not relivant.
20998  *
20999  * Fork - LGPL
21000  * <script type="text/javascript">
21001  */
21002  
21003
21004 /**
21005  * @class Roo.dd.ScrollManager
21006  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21007  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21008  * @singleton
21009  */
21010 Roo.dd.ScrollManager = function(){
21011     var ddm = Roo.dd.DragDropMgr;
21012     var els = {};
21013     var dragEl = null;
21014     var proc = {};
21015     
21016     
21017     
21018     var onStop = function(e){
21019         dragEl = null;
21020         clearProc();
21021     };
21022     
21023     var triggerRefresh = function(){
21024         if(ddm.dragCurrent){
21025              ddm.refreshCache(ddm.dragCurrent.groups);
21026         }
21027     };
21028     
21029     var doScroll = function(){
21030         if(ddm.dragCurrent){
21031             var dds = Roo.dd.ScrollManager;
21032             if(!dds.animate){
21033                 if(proc.el.scroll(proc.dir, dds.increment)){
21034                     triggerRefresh();
21035                 }
21036             }else{
21037                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21038             }
21039         }
21040     };
21041     
21042     var clearProc = function(){
21043         if(proc.id){
21044             clearInterval(proc.id);
21045         }
21046         proc.id = 0;
21047         proc.el = null;
21048         proc.dir = "";
21049     };
21050     
21051     var startProc = function(el, dir){
21052          Roo.log('scroll startproc');
21053         clearProc();
21054         proc.el = el;
21055         proc.dir = dir;
21056         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21057     };
21058     
21059     var onFire = function(e, isDrop){
21060        
21061         if(isDrop || !ddm.dragCurrent){ return; }
21062         var dds = Roo.dd.ScrollManager;
21063         if(!dragEl || dragEl != ddm.dragCurrent){
21064             dragEl = ddm.dragCurrent;
21065             // refresh regions on drag start
21066             dds.refreshCache();
21067         }
21068         
21069         var xy = Roo.lib.Event.getXY(e);
21070         var pt = new Roo.lib.Point(xy[0], xy[1]);
21071         for(var id in els){
21072             var el = els[id], r = el._region;
21073             if(r && r.contains(pt) && el.isScrollable()){
21074                 if(r.bottom - pt.y <= dds.thresh){
21075                     if(proc.el != el){
21076                         startProc(el, "down");
21077                     }
21078                     return;
21079                 }else if(r.right - pt.x <= dds.thresh){
21080                     if(proc.el != el){
21081                         startProc(el, "left");
21082                     }
21083                     return;
21084                 }else if(pt.y - r.top <= dds.thresh){
21085                     if(proc.el != el){
21086                         startProc(el, "up");
21087                     }
21088                     return;
21089                 }else if(pt.x - r.left <= dds.thresh){
21090                     if(proc.el != el){
21091                         startProc(el, "right");
21092                     }
21093                     return;
21094                 }
21095             }
21096         }
21097         clearProc();
21098     };
21099     
21100     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21101     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21102     
21103     return {
21104         /**
21105          * Registers new overflow element(s) to auto scroll
21106          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21107          */
21108         register : function(el){
21109             if(el instanceof Array){
21110                 for(var i = 0, len = el.length; i < len; i++) {
21111                         this.register(el[i]);
21112                 }
21113             }else{
21114                 el = Roo.get(el);
21115                 els[el.id] = el;
21116             }
21117             Roo.dd.ScrollManager.els = els;
21118         },
21119         
21120         /**
21121          * Unregisters overflow element(s) so they are no longer scrolled
21122          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21123          */
21124         unregister : function(el){
21125             if(el instanceof Array){
21126                 for(var i = 0, len = el.length; i < len; i++) {
21127                         this.unregister(el[i]);
21128                 }
21129             }else{
21130                 el = Roo.get(el);
21131                 delete els[el.id];
21132             }
21133         },
21134         
21135         /**
21136          * The number of pixels from the edge of a container the pointer needs to be to 
21137          * trigger scrolling (defaults to 25)
21138          * @type Number
21139          */
21140         thresh : 25,
21141         
21142         /**
21143          * The number of pixels to scroll in each scroll increment (defaults to 50)
21144          * @type Number
21145          */
21146         increment : 100,
21147         
21148         /**
21149          * The frequency of scrolls in milliseconds (defaults to 500)
21150          * @type Number
21151          */
21152         frequency : 500,
21153         
21154         /**
21155          * True to animate the scroll (defaults to true)
21156          * @type Boolean
21157          */
21158         animate: true,
21159         
21160         /**
21161          * The animation duration in seconds - 
21162          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21163          * @type Number
21164          */
21165         animDuration: .4,
21166         
21167         /**
21168          * Manually trigger a cache refresh.
21169          */
21170         refreshCache : function(){
21171             for(var id in els){
21172                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21173                     els[id]._region = els[id].getRegion();
21174                 }
21175             }
21176         }
21177     };
21178 }();/*
21179  * Based on:
21180  * Ext JS Library 1.1.1
21181  * Copyright(c) 2006-2007, Ext JS, LLC.
21182  *
21183  * Originally Released Under LGPL - original licence link has changed is not relivant.
21184  *
21185  * Fork - LGPL
21186  * <script type="text/javascript">
21187  */
21188  
21189
21190 /**
21191  * @class Roo.dd.Registry
21192  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21193  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21194  * @singleton
21195  */
21196 Roo.dd.Registry = function(){
21197     var elements = {}; 
21198     var handles = {}; 
21199     var autoIdSeed = 0;
21200
21201     var getId = function(el, autogen){
21202         if(typeof el == "string"){
21203             return el;
21204         }
21205         var id = el.id;
21206         if(!id && autogen !== false){
21207             id = "roodd-" + (++autoIdSeed);
21208             el.id = id;
21209         }
21210         return id;
21211     };
21212     
21213     return {
21214     /**
21215      * Register a drag drop element
21216      * @param {String|HTMLElement} element The id or DOM node to register
21217      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21218      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21219      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21220      * populated in the data object (if applicable):
21221      * <pre>
21222 Value      Description<br />
21223 ---------  ------------------------------------------<br />
21224 handles    Array of DOM nodes that trigger dragging<br />
21225            for the element being registered<br />
21226 isHandle   True if the element passed in triggers<br />
21227            dragging itself, else false
21228 </pre>
21229      */
21230         register : function(el, data){
21231             data = data || {};
21232             if(typeof el == "string"){
21233                 el = document.getElementById(el);
21234             }
21235             data.ddel = el;
21236             elements[getId(el)] = data;
21237             if(data.isHandle !== false){
21238                 handles[data.ddel.id] = data;
21239             }
21240             if(data.handles){
21241                 var hs = data.handles;
21242                 for(var i = 0, len = hs.length; i < len; i++){
21243                         handles[getId(hs[i])] = data;
21244                 }
21245             }
21246         },
21247
21248     /**
21249      * Unregister a drag drop element
21250      * @param {String|HTMLElement}  element The id or DOM node to unregister
21251      */
21252         unregister : function(el){
21253             var id = getId(el, false);
21254             var data = elements[id];
21255             if(data){
21256                 delete elements[id];
21257                 if(data.handles){
21258                     var hs = data.handles;
21259                     for(var i = 0, len = hs.length; i < len; i++){
21260                         delete handles[getId(hs[i], false)];
21261                     }
21262                 }
21263             }
21264         },
21265
21266     /**
21267      * Returns the handle registered for a DOM Node by id
21268      * @param {String|HTMLElement} id The DOM node or id to look up
21269      * @return {Object} handle The custom handle data
21270      */
21271         getHandle : function(id){
21272             if(typeof id != "string"){ // must be element?
21273                 id = id.id;
21274             }
21275             return handles[id];
21276         },
21277
21278     /**
21279      * Returns the handle that is registered for the DOM node that is the target of the event
21280      * @param {Event} e The event
21281      * @return {Object} handle The custom handle data
21282      */
21283         getHandleFromEvent : function(e){
21284             var t = Roo.lib.Event.getTarget(e);
21285             return t ? handles[t.id] : null;
21286         },
21287
21288     /**
21289      * Returns a custom data object that is registered for a DOM node by id
21290      * @param {String|HTMLElement} id The DOM node or id to look up
21291      * @return {Object} data The custom data
21292      */
21293         getTarget : function(id){
21294             if(typeof id != "string"){ // must be element?
21295                 id = id.id;
21296             }
21297             return elements[id];
21298         },
21299
21300     /**
21301      * Returns a custom data object that is registered for the DOM node that is the target of the event
21302      * @param {Event} e The event
21303      * @return {Object} data The custom data
21304      */
21305         getTargetFromEvent : function(e){
21306             var t = Roo.lib.Event.getTarget(e);
21307             return t ? elements[t.id] || handles[t.id] : null;
21308         }
21309     };
21310 }();/*
21311  * Based on:
21312  * Ext JS Library 1.1.1
21313  * Copyright(c) 2006-2007, Ext JS, LLC.
21314  *
21315  * Originally Released Under LGPL - original licence link has changed is not relivant.
21316  *
21317  * Fork - LGPL
21318  * <script type="text/javascript">
21319  */
21320  
21321
21322 /**
21323  * @class Roo.dd.StatusProxy
21324  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21325  * default drag proxy used by all Roo.dd components.
21326  * @constructor
21327  * @param {Object} config
21328  */
21329 Roo.dd.StatusProxy = function(config){
21330     Roo.apply(this, config);
21331     this.id = this.id || Roo.id();
21332     this.el = new Roo.Layer({
21333         dh: {
21334             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21335                 {tag: "div", cls: "x-dd-drop-icon"},
21336                 {tag: "div", cls: "x-dd-drag-ghost"}
21337             ]
21338         }, 
21339         shadow: !config || config.shadow !== false
21340     });
21341     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21342     this.dropStatus = this.dropNotAllowed;
21343 };
21344
21345 Roo.dd.StatusProxy.prototype = {
21346     /**
21347      * @cfg {String} dropAllowed
21348      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21349      */
21350     dropAllowed : "x-dd-drop-ok",
21351     /**
21352      * @cfg {String} dropNotAllowed
21353      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21354      */
21355     dropNotAllowed : "x-dd-drop-nodrop",
21356
21357     /**
21358      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21359      * over the current target element.
21360      * @param {String} cssClass The css class for the new drop status indicator image
21361      */
21362     setStatus : function(cssClass){
21363         cssClass = cssClass || this.dropNotAllowed;
21364         if(this.dropStatus != cssClass){
21365             this.el.replaceClass(this.dropStatus, cssClass);
21366             this.dropStatus = cssClass;
21367         }
21368     },
21369
21370     /**
21371      * Resets the status indicator to the default dropNotAllowed value
21372      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21373      */
21374     reset : function(clearGhost){
21375         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21376         this.dropStatus = this.dropNotAllowed;
21377         if(clearGhost){
21378             this.ghost.update("");
21379         }
21380     },
21381
21382     /**
21383      * Updates the contents of the ghost element
21384      * @param {String} html The html that will replace the current innerHTML of the ghost element
21385      */
21386     update : function(html){
21387         if(typeof html == "string"){
21388             this.ghost.update(html);
21389         }else{
21390             this.ghost.update("");
21391             html.style.margin = "0";
21392             this.ghost.dom.appendChild(html);
21393         }
21394         // ensure float = none set?? cant remember why though.
21395         var el = this.ghost.dom.firstChild;
21396                 if(el){
21397                         Roo.fly(el).setStyle('float', 'none');
21398                 }
21399     },
21400     
21401     /**
21402      * Returns the underlying proxy {@link Roo.Layer}
21403      * @return {Roo.Layer} el
21404     */
21405     getEl : function(){
21406         return this.el;
21407     },
21408
21409     /**
21410      * Returns the ghost element
21411      * @return {Roo.Element} el
21412      */
21413     getGhost : function(){
21414         return this.ghost;
21415     },
21416
21417     /**
21418      * Hides the proxy
21419      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21420      */
21421     hide : function(clear){
21422         this.el.hide();
21423         if(clear){
21424             this.reset(true);
21425         }
21426     },
21427
21428     /**
21429      * Stops the repair animation if it's currently running
21430      */
21431     stop : function(){
21432         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21433             this.anim.stop();
21434         }
21435     },
21436
21437     /**
21438      * Displays this proxy
21439      */
21440     show : function(){
21441         this.el.show();
21442     },
21443
21444     /**
21445      * Force the Layer to sync its shadow and shim positions to the element
21446      */
21447     sync : function(){
21448         this.el.sync();
21449     },
21450
21451     /**
21452      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21453      * invalid drop operation by the item being dragged.
21454      * @param {Array} xy The XY position of the element ([x, y])
21455      * @param {Function} callback The function to call after the repair is complete
21456      * @param {Object} scope The scope in which to execute the callback
21457      */
21458     repair : function(xy, callback, scope){
21459         this.callback = callback;
21460         this.scope = scope;
21461         if(xy && this.animRepair !== false){
21462             this.el.addClass("x-dd-drag-repair");
21463             this.el.hideUnders(true);
21464             this.anim = this.el.shift({
21465                 duration: this.repairDuration || .5,
21466                 easing: 'easeOut',
21467                 xy: xy,
21468                 stopFx: true,
21469                 callback: this.afterRepair,
21470                 scope: this
21471             });
21472         }else{
21473             this.afterRepair();
21474         }
21475     },
21476
21477     // private
21478     afterRepair : function(){
21479         this.hide(true);
21480         if(typeof this.callback == "function"){
21481             this.callback.call(this.scope || this);
21482         }
21483         this.callback = null;
21484         this.scope = null;
21485     }
21486 };/*
21487  * Based on:
21488  * Ext JS Library 1.1.1
21489  * Copyright(c) 2006-2007, Ext JS, LLC.
21490  *
21491  * Originally Released Under LGPL - original licence link has changed is not relivant.
21492  *
21493  * Fork - LGPL
21494  * <script type="text/javascript">
21495  */
21496
21497 /**
21498  * @class Roo.dd.DragSource
21499  * @extends Roo.dd.DDProxy
21500  * A simple class that provides the basic implementation needed to make any element draggable.
21501  * @constructor
21502  * @param {String/HTMLElement/Element} el The container element
21503  * @param {Object} config
21504  */
21505 Roo.dd.DragSource = function(el, config){
21506     this.el = Roo.get(el);
21507     this.dragData = {};
21508     
21509     Roo.apply(this, config);
21510     
21511     if(!this.proxy){
21512         this.proxy = new Roo.dd.StatusProxy();
21513     }
21514
21515     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21516           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21517     
21518     this.dragging = false;
21519 };
21520
21521 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21522     /**
21523      * @cfg {String} dropAllowed
21524      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21525      */
21526     dropAllowed : "x-dd-drop-ok",
21527     /**
21528      * @cfg {String} dropNotAllowed
21529      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21530      */
21531     dropNotAllowed : "x-dd-drop-nodrop",
21532
21533     /**
21534      * Returns the data object associated with this drag source
21535      * @return {Object} data An object containing arbitrary data
21536      */
21537     getDragData : function(e){
21538         return this.dragData;
21539     },
21540
21541     // private
21542     onDragEnter : function(e, id){
21543         var target = Roo.dd.DragDropMgr.getDDById(id);
21544         this.cachedTarget = target;
21545         if(this.beforeDragEnter(target, e, id) !== false){
21546             if(target.isNotifyTarget){
21547                 var status = target.notifyEnter(this, e, this.dragData);
21548                 this.proxy.setStatus(status);
21549             }else{
21550                 this.proxy.setStatus(this.dropAllowed);
21551             }
21552             
21553             if(this.afterDragEnter){
21554                 /**
21555                  * An empty function by default, but provided so that you can perform a custom action
21556                  * when the dragged item enters the drop target by providing an implementation.
21557                  * @param {Roo.dd.DragDrop} target The drop target
21558                  * @param {Event} e The event object
21559                  * @param {String} id The id of the dragged element
21560                  * @method afterDragEnter
21561                  */
21562                 this.afterDragEnter(target, e, id);
21563             }
21564         }
21565     },
21566
21567     /**
21568      * An empty function by default, but provided so that you can perform a custom action
21569      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21570      * @param {Roo.dd.DragDrop} target The drop target
21571      * @param {Event} e The event object
21572      * @param {String} id The id of the dragged element
21573      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21574      */
21575     beforeDragEnter : function(target, e, id){
21576         return true;
21577     },
21578
21579     // private
21580     alignElWithMouse: function() {
21581         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21582         this.proxy.sync();
21583     },
21584
21585     // private
21586     onDragOver : function(e, id){
21587         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21588         if(this.beforeDragOver(target, e, id) !== false){
21589             if(target.isNotifyTarget){
21590                 var status = target.notifyOver(this, e, this.dragData);
21591                 this.proxy.setStatus(status);
21592             }
21593
21594             if(this.afterDragOver){
21595                 /**
21596                  * An empty function by default, but provided so that you can perform a custom action
21597                  * while the dragged item is over the drop target by providing an implementation.
21598                  * @param {Roo.dd.DragDrop} target The drop target
21599                  * @param {Event} e The event object
21600                  * @param {String} id The id of the dragged element
21601                  * @method afterDragOver
21602                  */
21603                 this.afterDragOver(target, e, id);
21604             }
21605         }
21606     },
21607
21608     /**
21609      * An empty function by default, but provided so that you can perform a custom action
21610      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21611      * @param {Roo.dd.DragDrop} target The drop target
21612      * @param {Event} e The event object
21613      * @param {String} id The id of the dragged element
21614      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21615      */
21616     beforeDragOver : function(target, e, id){
21617         return true;
21618     },
21619
21620     // private
21621     onDragOut : function(e, id){
21622         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21623         if(this.beforeDragOut(target, e, id) !== false){
21624             if(target.isNotifyTarget){
21625                 target.notifyOut(this, e, this.dragData);
21626             }
21627             this.proxy.reset();
21628             if(this.afterDragOut){
21629                 /**
21630                  * An empty function by default, but provided so that you can perform a custom action
21631                  * after the dragged item is dragged out of the target without dropping.
21632                  * @param {Roo.dd.DragDrop} target The drop target
21633                  * @param {Event} e The event object
21634                  * @param {String} id The id of the dragged element
21635                  * @method afterDragOut
21636                  */
21637                 this.afterDragOut(target, e, id);
21638             }
21639         }
21640         this.cachedTarget = null;
21641     },
21642
21643     /**
21644      * An empty function by default, but provided so that you can perform a custom action before the dragged
21645      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21646      * @param {Roo.dd.DragDrop} target The drop target
21647      * @param {Event} e The event object
21648      * @param {String} id The id of the dragged element
21649      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21650      */
21651     beforeDragOut : function(target, e, id){
21652         return true;
21653     },
21654     
21655     // private
21656     onDragDrop : function(e, id){
21657         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21658         if(this.beforeDragDrop(target, e, id) !== false){
21659             if(target.isNotifyTarget){
21660                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21661                     this.onValidDrop(target, e, id);
21662                 }else{
21663                     this.onInvalidDrop(target, e, id);
21664                 }
21665             }else{
21666                 this.onValidDrop(target, e, id);
21667             }
21668             
21669             if(this.afterDragDrop){
21670                 /**
21671                  * An empty function by default, but provided so that you can perform a custom action
21672                  * after a valid drag drop has occurred by providing an implementation.
21673                  * @param {Roo.dd.DragDrop} target The drop target
21674                  * @param {Event} e The event object
21675                  * @param {String} id The id of the dropped element
21676                  * @method afterDragDrop
21677                  */
21678                 this.afterDragDrop(target, e, id);
21679             }
21680         }
21681         delete this.cachedTarget;
21682     },
21683
21684     /**
21685      * An empty function by default, but provided so that you can perform a custom action before the dragged
21686      * item is dropped onto the target and optionally cancel the onDragDrop.
21687      * @param {Roo.dd.DragDrop} target The drop target
21688      * @param {Event} e The event object
21689      * @param {String} id The id of the dragged element
21690      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21691      */
21692     beforeDragDrop : function(target, e, id){
21693         return true;
21694     },
21695
21696     // private
21697     onValidDrop : function(target, e, id){
21698         this.hideProxy();
21699         if(this.afterValidDrop){
21700             /**
21701              * An empty function by default, but provided so that you can perform a custom action
21702              * after a valid drop has occurred by providing an implementation.
21703              * @param {Object} target The target DD 
21704              * @param {Event} e The event object
21705              * @param {String} id The id of the dropped element
21706              * @method afterInvalidDrop
21707              */
21708             this.afterValidDrop(target, e, id);
21709         }
21710     },
21711
21712     // private
21713     getRepairXY : function(e, data){
21714         return this.el.getXY();  
21715     },
21716
21717     // private
21718     onInvalidDrop : function(target, e, id){
21719         this.beforeInvalidDrop(target, e, id);
21720         if(this.cachedTarget){
21721             if(this.cachedTarget.isNotifyTarget){
21722                 this.cachedTarget.notifyOut(this, e, this.dragData);
21723             }
21724             this.cacheTarget = null;
21725         }
21726         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21727
21728         if(this.afterInvalidDrop){
21729             /**
21730              * An empty function by default, but provided so that you can perform a custom action
21731              * after an invalid drop has occurred by providing an implementation.
21732              * @param {Event} e The event object
21733              * @param {String} id The id of the dropped element
21734              * @method afterInvalidDrop
21735              */
21736             this.afterInvalidDrop(e, id);
21737         }
21738     },
21739
21740     // private
21741     afterRepair : function(){
21742         if(Roo.enableFx){
21743             this.el.highlight(this.hlColor || "c3daf9");
21744         }
21745         this.dragging = false;
21746     },
21747
21748     /**
21749      * An empty function by default, but provided so that you can perform a custom action after an invalid
21750      * drop has occurred.
21751      * @param {Roo.dd.DragDrop} target The drop target
21752      * @param {Event} e The event object
21753      * @param {String} id The id of the dragged element
21754      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21755      */
21756     beforeInvalidDrop : function(target, e, id){
21757         return true;
21758     },
21759
21760     // private
21761     handleMouseDown : function(e){
21762         if(this.dragging) {
21763             return;
21764         }
21765         var data = this.getDragData(e);
21766         if(data && this.onBeforeDrag(data, e) !== false){
21767             this.dragData = data;
21768             this.proxy.stop();
21769             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21770         } 
21771     },
21772
21773     /**
21774      * An empty function by default, but provided so that you can perform a custom action before the initial
21775      * drag event begins and optionally cancel it.
21776      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21777      * @param {Event} e The event object
21778      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21779      */
21780     onBeforeDrag : function(data, e){
21781         return true;
21782     },
21783
21784     /**
21785      * An empty function by default, but provided so that you can perform a custom action once the initial
21786      * drag event has begun.  The drag cannot be canceled from this function.
21787      * @param {Number} x The x position of the click on the dragged object
21788      * @param {Number} y The y position of the click on the dragged object
21789      */
21790     onStartDrag : Roo.emptyFn,
21791
21792     // private - YUI override
21793     startDrag : function(x, y){
21794         this.proxy.reset();
21795         this.dragging = true;
21796         this.proxy.update("");
21797         this.onInitDrag(x, y);
21798         this.proxy.show();
21799     },
21800
21801     // private
21802     onInitDrag : function(x, y){
21803         var clone = this.el.dom.cloneNode(true);
21804         clone.id = Roo.id(); // prevent duplicate ids
21805         this.proxy.update(clone);
21806         this.onStartDrag(x, y);
21807         return true;
21808     },
21809
21810     /**
21811      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21812      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21813      */
21814     getProxy : function(){
21815         return this.proxy;  
21816     },
21817
21818     /**
21819      * Hides the drag source's {@link Roo.dd.StatusProxy}
21820      */
21821     hideProxy : function(){
21822         this.proxy.hide();  
21823         this.proxy.reset(true);
21824         this.dragging = false;
21825     },
21826
21827     // private
21828     triggerCacheRefresh : function(){
21829         Roo.dd.DDM.refreshCache(this.groups);
21830     },
21831
21832     // private - override to prevent hiding
21833     b4EndDrag: function(e) {
21834     },
21835
21836     // private - override to prevent moving
21837     endDrag : function(e){
21838         this.onEndDrag(this.dragData, e);
21839     },
21840
21841     // private
21842     onEndDrag : function(data, e){
21843     },
21844     
21845     // private - pin to cursor
21846     autoOffset : function(x, y) {
21847         this.setDelta(-12, -20);
21848     }    
21849 });/*
21850  * Based on:
21851  * Ext JS Library 1.1.1
21852  * Copyright(c) 2006-2007, Ext JS, LLC.
21853  *
21854  * Originally Released Under LGPL - original licence link has changed is not relivant.
21855  *
21856  * Fork - LGPL
21857  * <script type="text/javascript">
21858  */
21859
21860
21861 /**
21862  * @class Roo.dd.DropTarget
21863  * @extends Roo.dd.DDTarget
21864  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21865  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21866  * @constructor
21867  * @param {String/HTMLElement/Element} el The container element
21868  * @param {Object} config
21869  */
21870 Roo.dd.DropTarget = function(el, config){
21871     this.el = Roo.get(el);
21872     
21873     var listeners = false; ;
21874     if (config && config.listeners) {
21875         listeners= config.listeners;
21876         delete config.listeners;
21877     }
21878     Roo.apply(this, config);
21879     
21880     if(this.containerScroll){
21881         Roo.dd.ScrollManager.register(this.el);
21882     }
21883     this.addEvents( {
21884          /**
21885          * @scope Roo.dd.DropTarget
21886          */
21887          
21888          /**
21889          * @event enter
21890          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21891          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21892          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21893          * 
21894          * IMPORTANT : it should set this.overClass and this.dropAllowed
21895          * 
21896          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21897          * @param {Event} e The event
21898          * @param {Object} data An object containing arbitrary data supplied by the drag source
21899          */
21900         "enter" : true,
21901         
21902          /**
21903          * @event over
21904          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21905          * This method will be called on every mouse movement while the drag source is over the drop target.
21906          * This default implementation simply returns the dropAllowed config value.
21907          * 
21908          * IMPORTANT : it should set this.dropAllowed
21909          * 
21910          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21911          * @param {Event} e The event
21912          * @param {Object} data An object containing arbitrary data supplied by the drag source
21913          
21914          */
21915         "over" : true,
21916         /**
21917          * @event out
21918          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21919          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21920          * overClass (if any) from the drop element.
21921          * 
21922          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21923          * @param {Event} e The event
21924          * @param {Object} data An object containing arbitrary data supplied by the drag source
21925          */
21926          "out" : true,
21927          
21928         /**
21929          * @event drop
21930          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21931          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21932          * implementation that does something to process the drop event and returns true so that the drag source's
21933          * repair action does not run.
21934          * 
21935          * IMPORTANT : it should set this.success
21936          * 
21937          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21938          * @param {Event} e The event
21939          * @param {Object} data An object containing arbitrary data supplied by the drag source
21940         */
21941          "drop" : true
21942     });
21943             
21944      
21945     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21946         this.el.dom, 
21947         this.ddGroup || this.group,
21948         {
21949             isTarget: true,
21950             listeners : listeners || {} 
21951            
21952         
21953         }
21954     );
21955
21956 };
21957
21958 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21959     /**
21960      * @cfg {String} overClass
21961      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21962      */
21963      /**
21964      * @cfg {String} ddGroup
21965      * The drag drop group to handle drop events for
21966      */
21967      
21968     /**
21969      * @cfg {String} dropAllowed
21970      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21971      */
21972     dropAllowed : "x-dd-drop-ok",
21973     /**
21974      * @cfg {String} dropNotAllowed
21975      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21976      */
21977     dropNotAllowed : "x-dd-drop-nodrop",
21978     /**
21979      * @cfg {boolean} success
21980      * set this after drop listener.. 
21981      */
21982     success : false,
21983     /**
21984      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21985      * if the drop point is valid for over/enter..
21986      */
21987     valid : false,
21988     // private
21989     isTarget : true,
21990
21991     // private
21992     isNotifyTarget : true,
21993     
21994     /**
21995      * @hide
21996      */
21997     notifyEnter : function(dd, e, data)
21998     {
21999         this.valid = true;
22000         this.fireEvent('enter', dd, e, data);
22001         if(this.overClass){
22002             this.el.addClass(this.overClass);
22003         }
22004         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22005             this.valid ? this.dropAllowed : this.dropNotAllowed
22006         );
22007     },
22008
22009     /**
22010      * @hide
22011      */
22012     notifyOver : function(dd, e, data)
22013     {
22014         this.valid = true;
22015         this.fireEvent('over', dd, e, data);
22016         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22017             this.valid ? this.dropAllowed : this.dropNotAllowed
22018         );
22019     },
22020
22021     /**
22022      * @hide
22023      */
22024     notifyOut : function(dd, e, data)
22025     {
22026         this.fireEvent('out', dd, e, data);
22027         if(this.overClass){
22028             this.el.removeClass(this.overClass);
22029         }
22030     },
22031
22032     /**
22033      * @hide
22034      */
22035     notifyDrop : function(dd, e, data)
22036     {
22037         this.success = false;
22038         this.fireEvent('drop', dd, e, data);
22039         return this.success;
22040     }
22041 });/*
22042  * Based on:
22043  * Ext JS Library 1.1.1
22044  * Copyright(c) 2006-2007, Ext JS, LLC.
22045  *
22046  * Originally Released Under LGPL - original licence link has changed is not relivant.
22047  *
22048  * Fork - LGPL
22049  * <script type="text/javascript">
22050  */
22051
22052
22053 /**
22054  * @class Roo.dd.DragZone
22055  * @extends Roo.dd.DragSource
22056  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22057  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22058  * @constructor
22059  * @param {String/HTMLElement/Element} el The container element
22060  * @param {Object} config
22061  */
22062 Roo.dd.DragZone = function(el, config){
22063     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22064     if(this.containerScroll){
22065         Roo.dd.ScrollManager.register(this.el);
22066     }
22067 };
22068
22069 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22070     /**
22071      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22072      * for auto scrolling during drag operations.
22073      */
22074     /**
22075      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22076      * method after a failed drop (defaults to "c3daf9" - light blue)
22077      */
22078
22079     /**
22080      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22081      * for a valid target to drag based on the mouse down. Override this method
22082      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22083      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22084      * @param {EventObject} e The mouse down event
22085      * @return {Object} The dragData
22086      */
22087     getDragData : function(e){
22088         return Roo.dd.Registry.getHandleFromEvent(e);
22089     },
22090     
22091     /**
22092      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22093      * this.dragData.ddel
22094      * @param {Number} x The x position of the click on the dragged object
22095      * @param {Number} y The y position of the click on the dragged object
22096      * @return {Boolean} true to continue the drag, false to cancel
22097      */
22098     onInitDrag : function(x, y){
22099         this.proxy.update(this.dragData.ddel.cloneNode(true));
22100         this.onStartDrag(x, y);
22101         return true;
22102     },
22103     
22104     /**
22105      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22106      */
22107     afterRepair : function(){
22108         if(Roo.enableFx){
22109             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22110         }
22111         this.dragging = false;
22112     },
22113
22114     /**
22115      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22116      * the XY of this.dragData.ddel
22117      * @param {EventObject} e The mouse up event
22118      * @return {Array} The xy location (e.g. [100, 200])
22119      */
22120     getRepairXY : function(e){
22121         return Roo.Element.fly(this.dragData.ddel).getXY();  
22122     }
22123 });/*
22124  * Based on:
22125  * Ext JS Library 1.1.1
22126  * Copyright(c) 2006-2007, Ext JS, LLC.
22127  *
22128  * Originally Released Under LGPL - original licence link has changed is not relivant.
22129  *
22130  * Fork - LGPL
22131  * <script type="text/javascript">
22132  */
22133 /**
22134  * @class Roo.dd.DropZone
22135  * @extends Roo.dd.DropTarget
22136  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22137  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22138  * @constructor
22139  * @param {String/HTMLElement/Element} el The container element
22140  * @param {Object} config
22141  */
22142 Roo.dd.DropZone = function(el, config){
22143     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22144 };
22145
22146 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22147     /**
22148      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22149      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22150      * provide your own custom lookup.
22151      * @param {Event} e The event
22152      * @return {Object} data The custom data
22153      */
22154     getTargetFromEvent : function(e){
22155         return Roo.dd.Registry.getTargetFromEvent(e);
22156     },
22157
22158     /**
22159      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22160      * that it has registered.  This method has no default implementation and should be overridden to provide
22161      * node-specific processing if necessary.
22162      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22163      * {@link #getTargetFromEvent} for this node)
22164      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22165      * @param {Event} e The event
22166      * @param {Object} data An object containing arbitrary data supplied by the drag source
22167      */
22168     onNodeEnter : function(n, dd, e, data){
22169         
22170     },
22171
22172     /**
22173      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22174      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22175      * overridden to provide the proper feedback.
22176      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22177      * {@link #getTargetFromEvent} for this node)
22178      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22179      * @param {Event} e The event
22180      * @param {Object} data An object containing arbitrary data supplied by the drag source
22181      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22182      * underlying {@link Roo.dd.StatusProxy} can be updated
22183      */
22184     onNodeOver : function(n, dd, e, data){
22185         return this.dropAllowed;
22186     },
22187
22188     /**
22189      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22190      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22191      * node-specific processing if necessary.
22192      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22193      * {@link #getTargetFromEvent} for this node)
22194      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22195      * @param {Event} e The event
22196      * @param {Object} data An object containing arbitrary data supplied by the drag source
22197      */
22198     onNodeOut : function(n, dd, e, data){
22199         
22200     },
22201
22202     /**
22203      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22204      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22205      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22206      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22207      * {@link #getTargetFromEvent} for this node)
22208      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22209      * @param {Event} e The event
22210      * @param {Object} data An object containing arbitrary data supplied by the drag source
22211      * @return {Boolean} True if the drop was valid, else false
22212      */
22213     onNodeDrop : function(n, dd, e, data){
22214         return false;
22215     },
22216
22217     /**
22218      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22219      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22220      * it should be overridden to provide the proper feedback if necessary.
22221      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22222      * @param {Event} e The event
22223      * @param {Object} data An object containing arbitrary data supplied by the drag source
22224      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22225      * underlying {@link Roo.dd.StatusProxy} can be updated
22226      */
22227     onContainerOver : function(dd, e, data){
22228         return this.dropNotAllowed;
22229     },
22230
22231     /**
22232      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22233      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22234      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22235      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22236      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22237      * @param {Event} e The event
22238      * @param {Object} data An object containing arbitrary data supplied by the drag source
22239      * @return {Boolean} True if the drop was valid, else false
22240      */
22241     onContainerDrop : function(dd, e, data){
22242         return false;
22243     },
22244
22245     /**
22246      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22247      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22248      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22249      * you should override this method and provide a custom implementation.
22250      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22251      * @param {Event} e The event
22252      * @param {Object} data An object containing arbitrary data supplied by the drag source
22253      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22254      * underlying {@link Roo.dd.StatusProxy} can be updated
22255      */
22256     notifyEnter : function(dd, e, data){
22257         return this.dropNotAllowed;
22258     },
22259
22260     /**
22261      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22262      * This method will be called on every mouse movement while the drag source is over the drop zone.
22263      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22264      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22265      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22266      * registered node, it will call {@link #onContainerOver}.
22267      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22268      * @param {Event} e The event
22269      * @param {Object} data An object containing arbitrary data supplied by the drag source
22270      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22271      * underlying {@link Roo.dd.StatusProxy} can be updated
22272      */
22273     notifyOver : function(dd, e, data){
22274         var n = this.getTargetFromEvent(e);
22275         if(!n){ // not over valid drop target
22276             if(this.lastOverNode){
22277                 this.onNodeOut(this.lastOverNode, dd, e, data);
22278                 this.lastOverNode = null;
22279             }
22280             return this.onContainerOver(dd, e, data);
22281         }
22282         if(this.lastOverNode != n){
22283             if(this.lastOverNode){
22284                 this.onNodeOut(this.lastOverNode, dd, e, data);
22285             }
22286             this.onNodeEnter(n, dd, e, data);
22287             this.lastOverNode = n;
22288         }
22289         return this.onNodeOver(n, dd, e, data);
22290     },
22291
22292     /**
22293      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22294      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22295      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22296      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22297      * @param {Event} e The event
22298      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22299      */
22300     notifyOut : function(dd, e, data){
22301         if(this.lastOverNode){
22302             this.onNodeOut(this.lastOverNode, dd, e, data);
22303             this.lastOverNode = null;
22304         }
22305     },
22306
22307     /**
22308      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22309      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22310      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22311      * otherwise it will call {@link #onContainerDrop}.
22312      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22313      * @param {Event} e The event
22314      * @param {Object} data An object containing arbitrary data supplied by the drag source
22315      * @return {Boolean} True if the drop was valid, else false
22316      */
22317     notifyDrop : function(dd, e, data){
22318         if(this.lastOverNode){
22319             this.onNodeOut(this.lastOverNode, dd, e, data);
22320             this.lastOverNode = null;
22321         }
22322         var n = this.getTargetFromEvent(e);
22323         return n ?
22324             this.onNodeDrop(n, dd, e, data) :
22325             this.onContainerDrop(dd, e, data);
22326     },
22327
22328     // private
22329     triggerCacheRefresh : function(){
22330         Roo.dd.DDM.refreshCache(this.groups);
22331     }  
22332 });