roojs-all.js
[roojs1] / roojs-all.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, A){
36     if(A){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, A);
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  B = 0;
51     var  ua = navigator.userAgent.toLowerCase();
52
53     var  C = document.compatMode == "CSS1Compat",
54         D = ua.indexOf("opera") > -1,
55         E = (/webkit|khtml/).test(ua),
56         F = ua.indexOf("msie") > -1,
57         G = ua.indexOf("msie 7") > -1,
58         H = !E && ua.indexOf("gecko") > -1,
59         I = F && !C,
60         J = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         K = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         L = (ua.indexOf("linux") != -1),
63         M = window.location.href.toLowerCase().indexOf("https") === 0;
64
65     // remove css image flicker
66         if(F && !G){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71
72
73     Roo.apply(Roo, {
74         /**
75          * True if the browser is in strict mode
76          * @type Boolean
77          */
78         isStrict : C,
79         /**
80          * True if the page is running over SSL
81          * @type Boolean
82          */
83         isSecure : M,
84         /**
85          * True when the document is fully initialized and ready for action
86          * @type Boolean
87          */
88         isReady : false,
89
90         /**
91          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
92          * @type Boolean
93          */
94         enableGarbageCollector : true,
95
96         /**
97          * True to automatically purge event listeners after uncaching an element (defaults to false).
98          * Note: this only happens if enableGarbageCollector is true.
99          * @type Boolean
100          */
101         enableListenerCollection:false,
102
103         /**
104          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
105          * the IE insecure content warning (defaults to javascript:false).
106          * @type String
107          */
108         SSL_SECURE_URL : "javascript:false",
109
110         /**
111          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
112          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
113          * @type String
114          */
115         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116
117         emptyFn : function(){},
118
119         /**
120          * Copies all the properties of config to obj if they don't already exist.
121          * @param {Object} obj The receiver of the properties
122          * @param {Object} config The source of the properties
123          * @return {Object} returns obj
124          */
125         applyIf : function(o, c){
126             if(o && c){
127                 for(var  p  in  c){
128                     if(typeof  o[p] == "undefined"){ o[p] = c[p]; }
129                 }
130             }
131             return  o;
132         },
133
134         /**
135          * Applies event listeners to elements by selectors when the document is ready.
136          * The event name is specified with an @ suffix.
137 <pre><code>
138 Roo.addBehaviors({
139    // add a listener for click on all anchors in element with id foo
140    '#foo a@click' : function(e, t){
141        // do something
142    },
143
144    // add the same listener to multiple selectors (separated by comma BEFORE the @)
145    '#foo a, #bar span.some-class@mouseover' : function(){
146        // do something
147    }
148 });
149 </code></pre>
150          * @param {Object} obj The list of behaviors to apply
151          */
152         addBehaviors : function(o){
153             if(!Roo.isReady){
154                 Roo.onReady(function(){
155                     Roo.addBehaviors(o);
156                 });
157                 return;
158             }
159             var  N = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160             for(var  b  in  o){
161                 var  parts = b.split('@');
162                 if(parts[1]){ // for Object prototype breakers
163                     var  s = parts[0];
164                     if(!N[s]){
165                         N[s] = Roo.select(s);
166                     }
167
168                     N[s].on(parts[1], o[b]);
169                 }
170             }
171
172             N = null;
173         },
174
175         /**
176          * Generates unique ids. If the element already has an id, it is unchanged
177          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
178          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
179          * @return {String} The generated Id.
180          */
181         id : function(el, O){
182             O = O || "roo-gen";
183             el = Roo.getDom(el);
184             var  id = O + (++B);
185             return  el ? (el.id ? el.id : (el.id = id)) : id;
186         },
187          
188        
189         /**
190          * Extends one class with another class and optionally overrides members with the passed literal. This class
191          * also adds the function "override()" to the class that can be used to override
192          * members on an instance.
193          * @param {Object} subclass The class inheriting the functionality
194          * @param {Object} superclass The class being extended
195          * @param {Object} overrides (optional) A literal with members
196          * @method extend
197          */
198         extend : function(){
199             // inline overrides
200             var  io = function(o){
201                 for(var  m  in  o){
202                     this[m] = o[m];
203                 }
204             };
205             return  function(sb, sp, P){
206                 if(typeof  sp == 'object'){ // eg. prototype, rather than function constructor..
207                     P = sp;
208                     sp = sb;
209                     sb = function(){sp.apply(this, arguments);};
210                 }
211                 var  F = function(){}, sbp, spp = sp.prototype;
212                 F.prototype = spp;
213                 sbp = sb.prototype = new  F();
214                 sbp.constructor=sb;
215                 sb.superclass=spp;
216                 
217                 if(spp.constructor == Object.prototype.constructor){
218                     spp.constructor=sp;
219                    
220                 }
221
222                 
223                 sb.override = function(o){
224                     Roo.override(sb, o);
225                 };
226                 sbp.override = io;
227                 Roo.override(sb, P);
228                 return  sb;
229             };
230         }(),
231
232         /**
233          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
234          * Usage:<pre><code>
235 Roo.override(MyClass, {
236     newMethod1: function(){
237         // etc.
238     },
239     newMethod2: function(foo){
240         // etc.
241     }
242 });
243  </code></pre>
244          * @param {Object} origclass The class to override
245          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
246          * containing one or more methods.
247          * @method override
248          */
249         override : function(P, Q){
250             if(Q){
251                 var  p = P.prototype;
252                 for(var  method  in  Q){
253                     p[method] = Q[method];
254                 }
255             }
256         },
257         /**
258          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
259          * <pre><code>
260 Roo.namespace('Company', 'Company.data');
261 Company.Widget = function() { ... }
262 Company.data.CustomStore = function(config) { ... }
263 </code></pre>
264          * @param {String} namespace1
265          * @param {String} namespace2
266          * @param {String} etc
267          * @method namespace
268          */
269         namespace : function(){
270             var  a=arguments, o=null, i, j, d, rt;
271             for (i=0; i<a.length; ++i) {
272                 d=a[i].split(".");
273                 rt = d[0];
274                 /** eval:var:o */
275                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
276                 for (j=1; j<d.length; ++j) {
277                     o[d[j]]=o[d[j]] || {};
278                     o=o[d[j]];
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.factory({ xns: Roo.data, xtype : 'Store', .....});
286 Roo.factory(conf, Roo.data);
287 </code></pre>
288          * @param {String} classname
289          * @param {String} namespace (optional)
290          * @method factory
291          */
292          
293         factory : function(c, ns)
294         {
295             // no xtype, no ns or c.xns - or forced off by c.xns
296             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
297                 return  c;
298             }
299
300             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
301             if (c.constructor == ns[c.xtype]) {// already created...
302                 return  c;
303             }
304             if (ns[c.xtype]) {
305                 console.log("Roo.Factory(" + c.xtype + ")");
306                 var  ret = new  ns[c.xtype](c);
307                 ret.xns = false;
308                 return  ret;
309             }
310
311             c.xns = false; // prevent recursion..
312             return  c;
313         },
314          
315         /**
316          * 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.
317          * @param {Object} o
318          * @return {String}
319          */
320         urlEncode : function(o){
321             if(!o){
322                 return  "";
323             }
324             var  R = [];
325             for(var  key  in  o){
326                 var  ov = o[key], k = encodeURIComponent(key);
327                 var  type = typeof  ov;
328                 if(type == 'undefined'){
329                     R.push(k, "=&");
330                 }else  if(type != "function" && type != "object"){
331                     R.push(k, "=", encodeURIComponent(ov), "&");
332                 }else  if(ov  instanceof  Array){
333                     if (ov.length) {
334                             for(var  i = 0, len = ov.length; i < len; i++) {
335                                 R.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
336                             }
337                         } else  {
338                             R.push(k, "=&");
339                         }
340                 }
341             }
342
343             R.pop();
344             return  R.join("");
345         },
346
347         /**
348          * 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]}.
349          * @param {String} string
350          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
351          * @return {Object} A literal with members
352          */
353         urlDecode : function(S, T){
354             if(!S || !S.length){
355                 return  {};
356             }
357             var  U = {};
358             var  V = S.split('&');
359             var  W, X, Y;
360             for(var  i = 0, len = V.length; i < len; i++){
361                 W = V[i].split('=');
362                 X = decodeURIComponent(W[0]);
363                 Y = decodeURIComponent(W[1]);
364                 if(T !== true){
365                     if(typeof  U[X] == "undefined"){
366                         U[X] = Y;
367                     }else  if(typeof  U[X] == "string"){
368                         U[X] = [U[X]];
369                         U[X].push(Y);
370                     }else {
371                         U[X].push(Y);
372                     }
373                 }else {
374                     U[X] = Y;
375                 }
376             }
377             return  U;
378         },
379
380         /**
381          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
382          * passed array is not really an array, your function is called once with it.
383          * The supplied function is called with (Object item, Number index, Array allItems).
384          * @param {Array/NodeList/Mixed} array
385          * @param {Function} fn
386          * @param {Object} scope
387          */
388         each : function(Z, fn, f){
389             if(typeof  Z.length == "undefined" || typeof  Z == "string"){
390                 Z = [Z];
391             }
392             for(var  i = 0, len = Z.length; i < len; i++){
393                 if(fn.call(f || Z[i], Z[i], i, Z) === false){ return  i; };
394             }
395         },
396
397         // deprecated
398         combine : function(){
399             var  as = arguments, l = as.length, r = [];
400             for(var  i = 0; i < l; i++){
401                 var  a = as[i];
402                 if(a  instanceof  Array){
403                     r = r.concat(a);
404                 }else  if(a.length !== undefined && !a.substr){
405                     r = r.concat(Array.prototype.slice.call(a, 0));
406                 }else {
407                     r.push(a);
408                 }
409             }
410             return  r;
411         },
412
413         /**
414          * Escapes the passed string for use in a regular expression
415          * @param {String} str
416          * @return {String}
417          */
418         escapeRe : function(s) {
419             return  s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
420         },
421
422         // internal
423         callback : function(cb, g, h, n){
424             if(typeof  cb == "function"){
425                 if(n){
426                     cb.defer(n, g, h || []);
427                 }else {
428                     cb.apply(g, h || []);
429                 }
430             }
431         },
432
433         /**
434          * Return the dom node for the passed string (id), dom node, or Roo.Element
435          * @param {String/HTMLElement/Roo.Element} el
436          * @return HTMLElement
437          */
438         getDom : function(el){
439             if(!el){
440                 return  null;
441             }
442             return  el.dom ? el.dom : (typeof  el == 'string' ? document.getElementById(el) : el);
443         },
444
445         /**
446         * Shorthand for {@link Roo.ComponentMgr#get}
447         * @param {String} id
448         * @return Roo.Component
449         */
450         getCmp : function(id){
451             return  Roo.ComponentMgr.get(id);
452         },
453          
454         num : function(v, q){
455             if(typeof  v != 'number'){
456                 return  q;
457             }
458             return  v;
459         },
460
461         destroy : function(){
462             for(var  i = 0, a = arguments, len = a.length; i < len; i++) {
463                 var  as = a[i];
464                 if(as){
465                     if(as.dom){
466                         as.removeAllListeners();
467                         as.remove();
468                         continue;
469                     }
470                     if(typeof  as.purgeListeners == 'function'){
471                         as.purgeListeners();
472                     }
473                     if(typeof  as.destroy == 'function'){
474                         as.destroy();
475                     }
476                 }
477             }
478         },
479
480         // inpired by a similar function in mootools library
481         /**
482          * Returns the type of object that is passed in. If the object passed in is null or undefined it
483          * return false otherwise it returns one of the following values:<ul>
484          * <li><b>string</b>: If the object passed is a string</li>
485          * <li><b>number</b>: If the object passed is a number</li>
486          * <li><b>boolean</b>: If the object passed is a boolean value</li>
487          * <li><b>function</b>: If the object passed is a function reference</li>
488          * <li><b>object</b>: If the object passed is an object</li>
489          * <li><b>array</b>: If the object passed is an array</li>
490          * <li><b>regexp</b>: If the object passed is a regular expression</li>
491          * <li><b>element</b>: If the object passed is a DOM Element</li>
492          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
493          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
494          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
495          * @param {Mixed} object
496          * @return {String}
497          */
498         type : function(o){
499             if(o === undefined || o === null){
500                 return  false;
501             }
502             if(o.htmlElement){
503                 return  'element';
504             }
505             var  t = typeof  o;
506             if(t == 'object' && o.nodeName) {
507                 switch(o.nodeType) {
508                     case  1: return  'element';
509                     case  3: return  (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
510                 }
511             }
512             if(t == 'object' || t == 'function') {
513                 switch(o.constructor) {
514                     case  Array: return  'array';
515                     case  RegExp: return  'regexp';
516                 }
517                 if(typeof  o.length == 'number' && typeof  o.item == 'function') {
518                     return  'nodelist';
519                 }
520             }
521             return  t;
522         },
523
524         /**
525          * Returns true if the passed value is null, undefined or an empty string (optional).
526          * @param {Mixed} value The value to test
527          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
528          * @return {Boolean}
529          */
530         isEmpty : function(v, u){
531             return  v === null || v === undefined || (!u ? v === '' : false);
532         },
533         
534         /** @type Boolean */
535         isOpera : D,
536         /** @type Boolean */
537         isSafari : E,
538         /** @type Boolean */
539         isIE : F,
540         /** @type Boolean */
541         isIE7 : G,
542         /** @type Boolean */
543         isGecko : H,
544         /** @type Boolean */
545         isBorderBox : I,
546         /** @type Boolean */
547         isWindows : J,
548         /** @type Boolean */
549         isLinux : L,
550         /** @type Boolean */
551         isMac : K,
552
553         /**
554          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
555          * you may want to set this to true.
556          * @type Boolean
557          */
558         useShims : ((F && !G) || (H && K))
559     });
560
561
562 })();
563
564 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
565                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
566
567 /*
568  * Based on:
569  * Ext JS Library 1.1.1
570  * Copyright(c) 2006-2007, Ext JS, LLC.
571  *
572  * Originally Released Under LGPL - original licence link has changed is not relivant.
573  *
574  * Fork - LGPL
575  * <script type="text/javascript">
576  */
577
578 (function() {    
579     // wrappedn so fnCleanup is not in global scope...
580     if(Roo.isIE) {
581         function  A() {
582             var  p = Function.prototype;
583             delete  p.createSequence;
584             delete  p.defer;
585             delete  p.createDelegate;
586             delete  p.createCallback;
587             delete  p.createInterceptor;
588
589             window.detachEvent("onunload", A);
590         }
591
592         window.attachEvent("onunload", A);
593     }
594 })();
595
596
597 /**
598  * @class Function
599  * These functions are available on every Function object (any JavaScript function).
600  */
601 Roo.apply(Function.prototype, {
602      /**
603      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
604      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
605      * Will create a function that is bound to those 2 args.
606      * @return {Function} The new function
607     */
608     createCallback : function(/*args...*/){
609         // make args available, in function below
610         var  B = arguments;
611         var  C = this;
612         return  function() {
613             return  C.apply(window, B);
614         };
615     },
616
617     /**
618      * Creates a delegate (callback) that sets the scope to obj.
619      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
620      * Will create a function that is automatically scoped to this.
621      * @param {Object} obj (optional) The object for which the scope is set
622      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
623      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
624      *                                             if a number the args are inserted at the specified position
625      * @return {Function} The new function
626      */
627     createDelegate : function(D, E, F){
628         var  G = this;
629         return  function() {
630             var  H = E || arguments;
631             if(F === true){
632                 H = Array.prototype.slice.call(arguments, 0);
633                 H = H.concat(E);
634             }else  if(typeof  F == "number"){
635                 H = Array.prototype.slice.call(arguments, 0); // copy arguments first
636                 var  applyArgs = [F, 0].concat(E); // create method call params
637                 Array.prototype.splice.apply(H, applyArgs); // splice them in
638             }
639             return  G.apply(D || window, H);
640         };
641     },
642
643     /**
644      * Calls this function after the number of millseconds specified.
645      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
646      * @param {Object} obj (optional) The object for which the scope is set
647      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
648      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
649      *                                             if a number the args are inserted at the specified position
650      * @return {Number} The timeout id that can be used with clearTimeout
651      */
652     defer : function(H, I, J, K){
653         var  fn = this.createDelegate(I, J, K);
654         if(H){
655             return  setTimeout(fn, H);
656         }
657
658         fn();
659         return  0;
660     },
661     /**
662      * Create a combined function call sequence of the original function + the passed function.
663      * The resulting function returns the results of the original function.
664      * The passed fcn is called with the parameters of the original function
665      * @param {Function} fcn The function to sequence
666      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
667      * @return {Function} The new function
668      */
669     createSequence : function(L, M){
670         if(typeof  L != "function"){
671             return  this;
672         }
673         var  N = this;
674         return  function() {
675             var  O = N.apply(this || window, arguments);
676             L.apply(M || this || window, arguments);
677             return  O;
678         };
679     },
680
681     /**
682      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
683      * The resulting function returns the results of the original function.
684      * The passed fcn is called with the parameters of the original function.
685      * @addon
686      * @param {Function} fcn The function to call before the original
687      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
688      * @return {Function} The new function
689      */
690     createInterceptor : function(O, P){
691         if(typeof  O != "function"){
692             return  this;
693         }
694         var  Q = this;
695         return  function() {
696             O.target = this;
697             O.method = Q;
698             if(O.apply(P || this || window, arguments) === false){
699                 return;
700             }
701             return  Q.apply(this || window, arguments);
702         };
703     }
704 });
705
706 /*
707  * Based on:
708  * Ext JS Library 1.1.1
709  * Copyright(c) 2006-2007, Ext JS, LLC.
710  *
711  * Originally Released Under LGPL - original licence link has changed is not relivant.
712  *
713  * Fork - LGPL
714  * <script type="text/javascript">
715  */
716
717 Roo.applyIf(String, {
718     
719     /** @scope String */
720     
721     /**
722      * Escapes the passed string for ' and \
723      * @param {String} string The string to escape
724      * @return {String} The escaped string
725      * @static
726      */
727     escape : function(A) {
728         return  A.replace(/('|\\)/g, "\\$1");
729     },
730
731     /**
732      * Pads the left side of a string with a specified character.  This is especially useful
733      * for normalizing number and date strings.  Example usage:
734      * <pre><code>
735 var s = String.leftPad('123', 5, '0');
736 // s now contains the string: '00123'
737 </code></pre>
738      * @param {String} string The original string
739      * @param {Number} size The total length of the output string
740      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
741      * @return {String} The padded string
742      * @static
743      */
744     leftPad : function (B, C, ch) {
745         var  D = new  String(B);
746         if(ch === null || ch === undefined || ch === '') {
747             ch = " ";
748         }
749         while (D.length < C) {
750             D = ch + D;
751         }
752         return  D;
753     },
754
755     /**
756      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
757      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
758      * <pre><code>
759 var cls = 'my-class', text = 'Some text';
760 var s = String.format('<div class="{0}">{1}</div>', cls, text);
761 // s now contains the string: '<div class="my-class">Some text</div>'
762 </code></pre>
763      * @param {String} string The tokenized string to be formatted
764      * @param {String} value1 The value to replace token {0}
765      * @param {String} value2 Etc...
766      * @return {String} The formatted string
767      * @static
768      */
769     format : function(E){
770         var  F = Array.prototype.slice.call(arguments, 1);
771         return  E.replace(/\{(\d+)\}/g, function(m, i){
772             return  Roo.util.Format.htmlEncode(F[i]);
773         });
774     }
775 });
776
777 /**
778  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
779  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
780  * they are already different, the first value passed in is returned.  Note that this method returns the new value
781  * but does not change the current string.
782  * <pre><code>
783 // alternate sort directions
784 sort = sort.toggle('ASC', 'DESC');
785
786 // instead of conditional logic:
787 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
788 </code></pre>
789  * @param {String} value The value to compare to the current string
790  * @param {String} other The new value to use if the string already equals the first value passed in
791  * @return {String} The new value
792  */
793  
794 String.prototype.toggle = function(G, H){
795     return  this == G ? H : G;
796 };
797 /*
798  * Based on:
799  * Ext JS Library 1.1.1
800  * Copyright(c) 2006-2007, Ext JS, LLC.
801  *
802  * Originally Released Under LGPL - original licence link has changed is not relivant.
803  *
804  * Fork - LGPL
805  * <script type="text/javascript">
806  */
807
808  /**
809  * @class Number
810  */
811 Roo.applyIf(Number.prototype, {
812     /**
813      * Checks whether or not the current number is within a desired range.  If the number is already within the
814      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
815      * exceeded.  Note that this method returns the constrained value but does not change the current number.
816      * @param {Number} min The minimum number in the range
817      * @param {Number} max The maximum number in the range
818      * @return {Number} The constrained value if outside the range, otherwise the current value
819      */
820     constrain : function(A, B){
821         return  Math.min(Math.max(this, A), B);
822     }
823 });
824 /*
825  * Based on:
826  * Ext JS Library 1.1.1
827  * Copyright(c) 2006-2007, Ext JS, LLC.
828  *
829  * Originally Released Under LGPL - original licence link has changed is not relivant.
830  *
831  * Fork - LGPL
832  * <script type="text/javascript">
833  */
834  /**
835  * @class Array
836  */
837 Roo.applyIf(Array.prototype, {
838     /**
839      * Checks whether or not the specified object exists in the array.
840      * @param {Object} o The object to check for
841      * @return {Number} The index of o in the array (or -1 if it is not found)
842      */
843     indexOf : function(o){
844        for (var  i = 0, len = this.length; i < len; i++){
845               if(this[i] == o) return  i;
846        }
847            return  -1;
848     },
849
850     /**
851      * Removes the specified object from the array.  If the object is not found nothing happens.
852      * @param {Object} o The object to remove
853      */
854     remove : function(o){
855        var  A = this.indexOf(o);
856        if(A != -1){
857            this.splice(A, 1);
858        }
859     }
860 });
861 /*
862  * Based on:
863  * Ext JS Library 1.1.1
864  * Copyright(c) 2006-2007, Ext JS, LLC.
865  *
866  * Originally Released Under LGPL - original licence link has changed is not relivant.
867  *
868  * Fork - LGPL
869  * <script type="text/javascript">
870  */
871
872 /**
873  * @class Date
874  *
875  * The date parsing and format syntax is a subset of
876  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
877  * supported will provide results equivalent to their PHP versions.
878  *
879  * Following is the list of all currently supported formats:
880  *<pre>
881 Sample date:
882 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
883
884 Format  Output      Description
885 ------  ----------  --------------------------------------------------------------
886   d      10         Day of the month, 2 digits with leading zeros
887   D      Wed        A textual representation of a day, three letters
888   j      10         Day of the month without leading zeros
889   l      Wednesday  A full textual representation of the day of the week
890   S      th         English ordinal day of month suffix, 2 chars (use with j)
891   w      3          Numeric representation of the day of the week
892   z      9          The julian date, or day of the year (0-365)
893   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
894   F      January    A full textual representation of the month
895   m      01         Numeric representation of a month, with leading zeros
896   M      Jan        Month name abbreviation, three letters
897   n      1          Numeric representation of a month, without leading zeros
898   t      31         Number of days in the given month
899   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
900   Y      2007       A full numeric representation of a year, 4 digits
901   y      07         A two digit representation of a year
902   a      pm         Lowercase Ante meridiem and Post meridiem
903   A      PM         Uppercase Ante meridiem and Post meridiem
904   g      3          12-hour format of an hour without leading zeros
905   G      15         24-hour format of an hour without leading zeros
906   h      03         12-hour format of an hour with leading zeros
907   H      15         24-hour format of an hour with leading zeros
908   i      05         Minutes with leading zeros
909   s      01         Seconds, with leading zeros
910   O      -0600      Difference to Greenwich time (GMT) in hours
911   T      CST        Timezone setting of the machine running the code
912   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
913 </pre>
914  *
915  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
916  * <pre><code>
917 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
918 document.write(dt.format('Y-m-d'));                         //2007-01-10
919 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
920 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
921  </code></pre>
922  *
923  * Here are some standard date/time patterns that you might find helpful.  They
924  * are not part of the source of Date.js, but to use them you can simply copy this
925  * block of code into any script that is included after Date.js and they will also become
926  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
927  * <pre><code>
928 Date.patterns = {
929     ISO8601Long:"Y-m-d H:i:s",
930     ISO8601Short:"Y-m-d",
931     ShortDate: "n/j/Y",
932     LongDate: "l, F d, Y",
933     FullDateTime: "l, F d, Y g:i:s A",
934     MonthDay: "F d",
935     ShortTime: "g:i A",
936     LongTime: "g:i:s A",
937     SortableDateTime: "Y-m-d\\TH:i:s",
938     UniversalSortableDateTime: "Y-m-d H:i:sO",
939     YearMonth: "F, Y"
940 };
941 </code></pre>
942  *
943  * Example usage:
944  * <pre><code>
945 var dt = new Date();
946 document.write(dt.format(Date.patterns.ShortDate));
947  </code></pre>
948  */
949
950 /*
951  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
952  * They generate precompiled functions from date formats instead of parsing and
953  * processing the pattern every time you format a date.  These functions are available
954  * on every Date object (any javascript function).
955  *
956  * The original article and download are here:
957  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
958  *
959  */
960  
961  
962  // was in core
963 /**
964  Returns the number of milliseconds between this date and date
965  @param {Date} date (optional) Defaults to now
966  @return {Number} The diff in milliseconds
967  @member Date getElapsed
968  */
969 Date.prototype.getElapsed = function(A) {
970         return  Math.abs((A || new  Date()).getTime()-this.getTime());
971 };
972 // was in date file..
973
974
975 // private
976 Date.parseFunctions = {count:0};
977 // private
978 Date.parseRegexes = [];
979 // private
980 Date.formatFunctions = {count:0};
981
982 // private
983 Date.prototype.dateFormat = function(B) {
984     if (Date.formatFunctions[B] == null) {
985         Date.createNewFormat(B);
986     }
987     var  C = Date.formatFunctions[B];
988     return  this[C]();
989 };
990
991
992 /**
993  * Formats a date given the supplied format string
994  * @param {String} format The format string
995  * @return {String} The formatted date
996  * @method
997  */
998 Date.prototype.format = Date.prototype.dateFormat;
999
1000 // private
1001 Date.createNewFormat = function(D) {
1002     var  E = "format" + Date.formatFunctions.count++;
1003     Date.formatFunctions[D] = E;
1004     var  F = "Date.prototype." + E + " = function(){return ";
1005     var  G = false;
1006     var  ch = '';
1007     for (var  i = 0; i < D.length; ++i) {
1008         ch = D.charAt(i);
1009         if (!G && ch == "\\") {
1010             G = true;
1011         }
1012         else  if (G) {
1013             G = false;
1014             F += "'" + String.escape(ch) + "' + ";
1015         }
1016         else  {
1017             F += Date.getFormatCode(ch);
1018         }
1019     }
1020
1021     /** eval:var:zzzzzzzzzzzzz */
1022     eval(F.substring(0, F.length - 3) + ";}");
1023 };
1024
1025 // private
1026 Date.getFormatCode = function(H) {
1027     switch (H) {
1028     case  "d":
1029         return  "String.leftPad(this.getDate(), 2, '0') + ";
1030     case  "D":
1031         return  "Date.dayNames[this.getDay()].substring(0, 3) + ";
1032     case  "j":
1033         return  "this.getDate() + ";
1034     case  "l":
1035         return  "Date.dayNames[this.getDay()] + ";
1036     case  "S":
1037         return  "this.getSuffix() + ";
1038     case  "w":
1039         return  "this.getDay() + ";
1040     case  "z":
1041         return  "this.getDayOfYear() + ";
1042     case  "W":
1043         return  "this.getWeekOfYear() + ";
1044     case  "F":
1045         return  "Date.monthNames[this.getMonth()] + ";
1046     case  "m":
1047         return  "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1048     case  "M":
1049         return  "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1050     case  "n":
1051         return  "(this.getMonth() + 1) + ";
1052     case  "t":
1053         return  "this.getDaysInMonth() + ";
1054     case  "L":
1055         return  "(this.isLeapYear() ? 1 : 0) + ";
1056     case  "Y":
1057         return  "this.getFullYear() + ";
1058     case  "y":
1059         return  "('' + this.getFullYear()).substring(2, 4) + ";
1060     case  "a":
1061         return  "(this.getHours() < 12 ? 'am' : 'pm') + ";
1062     case  "A":
1063         return  "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1064     case  "g":
1065         return  "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1066     case  "G":
1067         return  "this.getHours() + ";
1068     case  "h":
1069         return  "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1070     case  "H":
1071         return  "String.leftPad(this.getHours(), 2, '0') + ";
1072     case  "i":
1073         return  "String.leftPad(this.getMinutes(), 2, '0') + ";
1074     case  "s":
1075         return  "String.leftPad(this.getSeconds(), 2, '0') + ";
1076     case  "O":
1077         return  "this.getGMTOffset() + ";
1078     case  "T":
1079         return  "this.getTimezone() + ";
1080     case  "Z":
1081         return  "(this.getTimezoneOffset() * -60) + ";
1082     default:
1083         return  "'" + String.escape(H) + "' + ";
1084     }
1085 };
1086
1087 /**
1088  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1089  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1090  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1091  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1092  * string or the parse operation will fail.
1093  * Example Usage:
1094 <pre><code>
1095 //dt = Fri May 25 2007 (current date)
1096 var dt = new Date();
1097
1098 //dt = Thu May 25 2006 (today's month/day in 2006)
1099 dt = Date.parseDate("2006", "Y");
1100
1101 //dt = Sun Jan 15 2006 (all date parts specified)
1102 dt = Date.parseDate("2006-1-15", "Y-m-d");
1103
1104 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1105 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1106 </code></pre>
1107  * @param {String} input The unparsed date as a string
1108  * @param {String} format The format the date is in
1109  * @return {Date} The parsed date
1110  * @static
1111  */
1112 Date.parseDate = function(I, J) {
1113     if (Date.parseFunctions[J] == null) {
1114         Date.createParser(J);
1115     }
1116     var  K = Date.parseFunctions[J];
1117     return  Date[K](I);
1118 };
1119
1120 // private
1121 Date.createParser = function(L) {
1122     var  M = "parse" + Date.parseFunctions.count++;
1123     var  N = Date.parseRegexes.length;
1124     var  O = 1;
1125     Date.parseFunctions[L] = M;
1126
1127     var  P = "Date." + M + " = function(input){\n"
1128         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1129         + "var d = new Date();\n"
1130         + "y = d.getFullYear();\n"
1131         + "m = d.getMonth();\n"
1132         + "d = d.getDate();\n"
1133         + "var results = input.match(Date.parseRegexes[" + N + "]);\n"
1134         + "if (results && results.length > 0) {";
1135     var  Q = "";
1136
1137     var  R = false;
1138     var  ch = '';
1139     for (var  i = 0; i < L.length; ++i) {
1140         ch = L.charAt(i);
1141         if (!R && ch == "\\") {
1142             R = true;
1143         }
1144         else  if (R) {
1145             R = false;
1146             Q += String.escape(ch);
1147         }
1148         else  {
1149             var  obj = Date.formatCodeToRegex(ch, O);
1150             O += obj.g;
1151             Q += obj.s;
1152             if (obj.g && obj.c) {
1153                 P += obj.c;
1154             }
1155         }
1156     }
1157
1158
1159     P += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1160         + "{v = new Date(y, m, d, h, i, s);}\n"
1161         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1162         + "{v = new Date(y, m, d, h, i);}\n"
1163         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1164         + "{v = new Date(y, m, d, h);}\n"
1165         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1166         + "{v = new Date(y, m, d);}\n"
1167         + "else if (y >= 0 && m >= 0)\n"
1168         + "{v = new Date(y, m);}\n"
1169         + "else if (y >= 0)\n"
1170         + "{v = new Date(y);}\n"
1171         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1172         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1173         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1174         + ";}";
1175
1176     Date.parseRegexes[N] = new  RegExp("^" + Q + "$");
1177      /** eval:var:zzzzzzzzzzzzz */
1178     eval(P);
1179 };
1180
1181 // private
1182 Date.formatCodeToRegex = function(S, T) {
1183     switch (S) {
1184     case  "D":
1185         return  {g:0,
1186         c:null,
1187         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1188     case  "j":
1189         return  {g:1,
1190             c:"d = parseInt(results[" + T + "], 10);\n",
1191             s:"(\\d{1,2})"}; // day of month without leading zeroes
1192     case  "d":
1193         return  {g:1,
1194             c:"d = parseInt(results[" + T + "], 10);\n",
1195             s:"(\\d{2})"}; // day of month with leading zeroes
1196     case  "l":
1197         return  {g:0,
1198             c:null,
1199             s:"(?:" + Date.dayNames.join("|") + ")"};
1200     case  "S":
1201         return  {g:0,
1202             c:null,
1203             s:"(?:st|nd|rd|th)"};
1204     case  "w":
1205         return  {g:0,
1206             c:null,
1207             s:"\\d"};
1208     case  "z":
1209         return  {g:0,
1210             c:null,
1211             s:"(?:\\d{1,3})"};
1212     case  "W":
1213         return  {g:0,
1214             c:null,
1215             s:"(?:\\d{2})"};
1216     case  "F":
1217         return  {g:1,
1218             c:"m = parseInt(Date.monthNumbers[results[" + T + "].substring(0, 3)], 10);\n",
1219             s:"(" + Date.monthNames.join("|") + ")"};
1220     case  "M":
1221         return  {g:1,
1222             c:"m = parseInt(Date.monthNumbers[results[" + T + "]], 10);\n",
1223             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1224     case  "n":
1225         return  {g:1,
1226             c:"m = parseInt(results[" + T + "], 10) - 1;\n",
1227             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1228     case  "m":
1229         return  {g:1,
1230             c:"m = parseInt(results[" + T + "], 10) - 1;\n",
1231             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1232     case  "t":
1233         return  {g:0,
1234             c:null,
1235             s:"\\d{1,2}"};
1236     case  "L":
1237         return  {g:0,
1238             c:null,
1239             s:"(?:1|0)"};
1240     case  "Y":
1241         return  {g:1,
1242             c:"y = parseInt(results[" + T + "], 10);\n",
1243             s:"(\\d{4})"};
1244     case  "y":
1245         return  {g:1,
1246             c:"var ty = parseInt(results[" + T + "], 10);\n"
1247                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1248             s:"(\\d{1,2})"};
1249     case  "a":
1250         return  {g:1,
1251             c:"if (results[" + T + "] == 'am') {\n"
1252                 + "if (h == 12) { h = 0; }\n"
1253                 + "} else { if (h < 12) { h += 12; }}",
1254             s:"(am|pm)"};
1255     case  "A":
1256         return  {g:1,
1257             c:"if (results[" + T + "] == 'AM') {\n"
1258                 + "if (h == 12) { h = 0; }\n"
1259                 + "} else { if (h < 12) { h += 12; }}",
1260             s:"(AM|PM)"};
1261     case  "g":
1262     case  "G":
1263         return  {g:1,
1264             c:"h = parseInt(results[" + T + "], 10);\n",
1265             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1266     case  "h":
1267     case  "H":
1268         return  {g:1,
1269             c:"h = parseInt(results[" + T + "], 10);\n",
1270             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1271     case  "i":
1272         return  {g:1,
1273             c:"i = parseInt(results[" + T + "], 10);\n",
1274             s:"(\\d{2})"};
1275     case  "s":
1276         return  {g:1,
1277             c:"s = parseInt(results[" + T + "], 10);\n",
1278             s:"(\\d{2})"};
1279     case  "O":
1280         return  {g:1,
1281             c:[
1282                 "o = results[", T, "];\n",
1283                 "var sn = o.substring(0,1);\n", // get + / - sign
1284                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1285                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1286                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1287                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1288             ].join(""),
1289             s:"([+\-]\\d{4})"};
1290     case  "T":
1291         return  {g:0,
1292             c:null,
1293             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1294     case  "Z":
1295         return  {g:1,
1296             c:"z = results[" + T + "];\n" // -43200 <= UTC offset <= 50400
1297                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1298             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1299     default:
1300         return  {g:0,
1301             c:null,
1302             s:String.escape(S)};
1303     }
1304 };
1305
1306 /**
1307  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1308  * @return {String} The abbreviated timezone name (e.g. 'CST')
1309  */
1310 Date.prototype.getTimezone = function() {
1311     return  this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1312 };
1313
1314 /**
1315  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1316  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1317  */
1318 Date.prototype.getGMTOffset = function() {
1319     return  (this.getTimezoneOffset() > 0 ? "-" : "+")
1320         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1321         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1322 };
1323
1324 /**
1325  * Get the numeric day number of the year, adjusted for leap year.
1326  * @return {Number} 0 through 364 (365 in leap years)
1327  */
1328 Date.prototype.getDayOfYear = function() {
1329     var  U = 0;
1330     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1331     for (var  i = 0; i < this.getMonth(); ++i) {
1332         U += Date.daysInMonth[i];
1333     }
1334     return  U + this.getDate() - 1;
1335 };
1336
1337 /**
1338  * Get the string representation of the numeric week number of the year
1339  * (equivalent to the format specifier 'W').
1340  * @return {String} '00' through '52'
1341  */
1342 Date.prototype.getWeekOfYear = function() {
1343     // Skip to Thursday of this week
1344     var  V = this.getDayOfYear() + (4 - this.getDay());
1345     // Find the first Thursday of the year
1346     var  W = new  Date(this.getFullYear(), 0, 1);
1347     var  X = (7 - W.getDay() + 4);
1348     return  String.leftPad(((V - X) / 7) + 1, 2, "0");
1349 };
1350
1351 /**
1352  * Whether or not the current date is in a leap year.
1353  * @return {Boolean} True if the current date is in a leap year, else false
1354  */
1355 Date.prototype.isLeapYear = function() {
1356     var  Y = this.getFullYear();
1357     return  ((Y & 3) == 0 && (Y % 100 || (Y % 400 == 0 && Y)));
1358 };
1359
1360 /**
1361  * Get the first day of the current month, adjusted for leap year.  The returned value
1362  * is the numeric day index within the week (0-6) which can be used in conjunction with
1363  * the {@link #monthNames} array to retrieve the textual day name.
1364  * Example:
1365  *<pre><code>
1366 var dt = new Date('1/10/2007');
1367 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1368 </code></pre>
1369  * @return {Number} The day number (0-6)
1370  */
1371 Date.prototype.getFirstDayOfMonth = function() {
1372     var  Z = (this.getDay() - (this.getDate() - 1)) % 7;
1373     return  (Z < 0) ? (Z + 7) : Z;
1374 };
1375
1376 /**
1377  * Get the last day of the current month, adjusted for leap year.  The returned value
1378  * is the numeric day index within the week (0-6) which can be used in conjunction with
1379  * the {@link #monthNames} array to retrieve the textual day name.
1380  * Example:
1381  *<pre><code>
1382 var dt = new Date('1/10/2007');
1383 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1384 </code></pre>
1385  * @return {Number} The day number (0-6)
1386  */
1387 Date.prototype.getLastDayOfMonth = function() {
1388     var  a = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1389     return  (a < 0) ? (a + 7) : a;
1390 };
1391
1392
1393 /**
1394  * Get the first date of this date's month
1395  * @return {Date}
1396  */
1397 Date.prototype.getFirstDateOfMonth = function() {
1398     return  new  Date(this.getFullYear(), this.getMonth(), 1);
1399 };
1400
1401 /**
1402  * Get the last date of this date's month
1403  * @return {Date}
1404  */
1405 Date.prototype.getLastDateOfMonth = function() {
1406     return  new  Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1407 };
1408 /**
1409  * Get the number of days in the current month, adjusted for leap year.
1410  * @return {Number} The number of days in the month
1411  */
1412 Date.prototype.getDaysInMonth = function() {
1413     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1414     return  Date.daysInMonth[this.getMonth()];
1415 };
1416
1417 /**
1418  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1419  * @return {String} 'st, 'nd', 'rd' or 'th'
1420  */
1421 Date.prototype.getSuffix = function() {
1422     switch (this.getDate()) {
1423         case  1:
1424         case  21:
1425         case  31:
1426             return  "st";
1427         case  2:
1428         case  22:
1429             return  "nd";
1430         case  3:
1431         case  23:
1432             return  "rd";
1433         default:
1434             return  "th";
1435     }
1436 };
1437
1438 // private
1439 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1440
1441 /**
1442  * An array of textual month names.
1443  * Override these values for international dates, for example...
1444  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1445  * @type Array
1446  * @static
1447  */
1448 Date.monthNames =
1449    ["January",
1450     "February",
1451     "March",
1452     "April",
1453     "May",
1454     "June",
1455     "July",
1456     "August",
1457     "September",
1458     "October",
1459     "November",
1460     "December"];
1461
1462 /**
1463  * An array of textual day names.
1464  * Override these values for international dates, for example...
1465  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1466  * @type Array
1467  * @static
1468  */
1469 Date.dayNames =
1470    ["Sunday",
1471     "Monday",
1472     "Tuesday",
1473     "Wednesday",
1474     "Thursday",
1475     "Friday",
1476     "Saturday"];
1477
1478 // private
1479 Date.y2kYear = 50;
1480 // private
1481 Date.monthNumbers = {
1482     Jan:0,
1483     Feb:1,
1484     Mar:2,
1485     Apr:3,
1486     May:4,
1487     Jun:5,
1488     Jul:6,
1489     Aug:7,
1490     Sep:8,
1491     Oct:9,
1492     Nov:10,
1493     Dec:11};
1494
1495 /**
1496  * Creates and returns a new Date instance with the exact same date value as the called instance.
1497  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1498  * variable will also be changed.  When the intention is to create a new variable that will not
1499  * modify the original instance, you should create a clone.
1500  *
1501  * Example of correctly cloning a date:
1502  * <pre><code>
1503 //wrong way:
1504 var orig = new Date('10/1/2006');
1505 var copy = orig;
1506 copy.setDate(5);
1507 document.write(orig);  //returns 'Thu Oct 05 2006'!
1508
1509 //correct way:
1510 var orig = new Date('10/1/2006');
1511 var copy = orig.clone();
1512 copy.setDate(5);
1513 document.write(orig);  //returns 'Thu Oct 01 2006'
1514 </code></pre>
1515  * @return {Date} The new Date instance
1516  */
1517 Date.prototype.clone = function() {
1518         return  new  Date(this.getTime());
1519 };
1520
1521 /**
1522  * Clears any time information from this date
1523  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1524  @return {Date} this or the clone
1525  */
1526 Date.prototype.clearTime = function(b){
1527     if(b){
1528         return  this.clone().clearTime();
1529     }
1530
1531     this.setHours(0);
1532     this.setMinutes(0);
1533     this.setSeconds(0);
1534     this.setMilliseconds(0);
1535     return  this;
1536 };
1537
1538 // private
1539 // safari setMonth is broken
1540 if(Roo.isSafari){
1541     Date.brokenSetMonth = Date.prototype.setMonth;
1542         Date.prototype.setMonth = function(c){
1543                 if(c <= -1){
1544                         var  n = Math.ceil(-c);
1545                         var  back_year = Math.ceil(n/12);
1546                         var  month = (n % 12) ? 12 - n % 12 : 0 ;
1547                         this.setFullYear(this.getFullYear() - back_year);
1548                         return  Date.brokenSetMonth.call(this, month);
1549                 } else  {
1550                         return  Date.brokenSetMonth.apply(this, arguments);
1551                 }
1552         };
1553 }
1554
1555
1556 /** Date interval constant 
1557 * @static 
1558 * @type String */
1559 Date.MILLI = "ms";
1560 /** Date interval constant 
1561 * @static 
1562 * @type String */
1563 Date.SECOND = "s";
1564 /** Date interval constant 
1565 * @static 
1566 * @type String */
1567 Date.MINUTE = "mi";
1568 /** Date interval constant 
1569 * @static 
1570 * @type String */
1571 Date.HOUR = "h";
1572 /** Date interval constant 
1573 * @static 
1574 * @type String */
1575 Date.DAY = "d";
1576 /** Date interval constant 
1577 * @static 
1578 * @type String */
1579 Date.MONTH = "mo";
1580 /** Date interval constant 
1581 * @static 
1582 * @type String */
1583 Date.YEAR = "y";
1584
1585 /**
1586  * Provides a convenient method of performing basic date arithmetic.  This method
1587  * does not modify the Date instance being called - it creates and returns
1588  * a new Date instance containing the resulting date value.
1589  *
1590  * Examples:
1591  * <pre><code>
1592 //Basic usage:
1593 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1594 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1595
1596 //Negative values will subtract correctly:
1597 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1598 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1599
1600 //You can even chain several calls together in one line!
1601 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1602 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1603  </code></pre>
1604  *
1605  * @param {String} interval   A valid date interval enum value
1606  * @param {Number} value      The amount to add to the current date
1607  * @return {Date} The new Date instance
1608  */
1609 Date.prototype.add = function(e, f){
1610   var  d = this.clone();
1611   if (!e || f === 0) return  d;
1612   switch(e.toLowerCase()){
1613     case  Date.MILLI:
1614       d.setMilliseconds(this.getMilliseconds() + f);
1615       break;
1616     case  Date.SECOND:
1617       d.setSeconds(this.getSeconds() + f);
1618       break;
1619     case  Date.MINUTE:
1620       d.setMinutes(this.getMinutes() + f);
1621       break;
1622     case  Date.HOUR:
1623       d.setHours(this.getHours() + f);
1624       break;
1625     case  Date.DAY:
1626       d.setDate(this.getDate() + f);
1627       break;
1628     case  Date.MONTH:
1629       var  a = this.getDate();
1630       if(a > 28){
1631           a = Math.min(a, this.getFirstDateOfMonth().add('mo', f).getLastDateOfMonth().getDate());
1632       }
1633
1634       d.setDate(a);
1635       d.setMonth(this.getMonth() + f);
1636       break;
1637     case  Date.YEAR:
1638       d.setFullYear(this.getFullYear() + f);
1639       break;
1640   }
1641   return  d;
1642 };
1643 /*
1644  * Based on:
1645  * Ext JS Library 1.1.1
1646  * Copyright(c) 2006-2007, Ext JS, LLC.
1647  *
1648  * Originally Released Under LGPL - original licence link has changed is not relivant.
1649  *
1650  * Fork - LGPL
1651  * <script type="text/javascript">
1652  */
1653
1654 Roo.lib.Dom = {
1655     getViewWidth : function(A) {
1656         return  A ? this.getDocumentWidth() : this.getViewportWidth();
1657     },
1658
1659     getViewHeight : function(B) {
1660         return  B ? this.getDocumentHeight() : this.getViewportHeight();
1661     },
1662
1663     getDocumentHeight: function() {
1664         var  C = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1665         return  Math.max(C, this.getViewportHeight());
1666     },
1667
1668     getDocumentWidth: function() {
1669         var  D = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1670         return  Math.max(D, this.getViewportWidth());
1671     },
1672
1673     getViewportHeight: function() {
1674         var  E = self.innerHeight;
1675         var  F = document.compatMode;
1676
1677         if ((F || Roo.isIE) && !Roo.isOpera) {
1678             E = (F == "CSS1Compat") ?
1679                      document.documentElement.clientHeight :
1680                      document.body.clientHeight;
1681         }
1682
1683         return  E;
1684     },
1685
1686     getViewportWidth: function() {
1687         var  G = self.innerWidth;
1688         var  H = document.compatMode;
1689
1690         if (H || Roo.isIE) {
1691             G = (H == "CSS1Compat") ?
1692                     document.documentElement.clientWidth :
1693                     document.body.clientWidth;
1694         }
1695         return  G;
1696     },
1697
1698     isAncestor : function(p, c) {
1699         p = Roo.getDom(p);
1700         c = Roo.getDom(c);
1701         if (!p || !c) {
1702             return  false;
1703         }
1704
1705         if (p.contains && !Roo.isSafari) {
1706             return  p.contains(c);
1707         } else  if (p.compareDocumentPosition) {
1708             return  !!(p.compareDocumentPosition(c) & 16);
1709         } else  {
1710             var  parent = c.parentNode;
1711             while (parent) {
1712                 if (parent == p) {
1713                     return  true;
1714                 }
1715                 else  if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1716                     return  false;
1717                 }
1718
1719                 parent = parent.parentNode;
1720             }
1721             return  false;
1722         }
1723     },
1724
1725     getRegion : function(el) {
1726         return  Roo.lib.Region.getRegion(el);
1727     },
1728
1729     getY : function(el) {
1730         return  this.getXY(el)[1];
1731     },
1732
1733     getX : function(el) {
1734         return  this.getXY(el)[0];
1735     },
1736
1737     getXY : function(el) {
1738         var  p, pe, b, I, bd = document.body;
1739         el = Roo.getDom(el);
1740         var  J = Roo.lib.AnimBase.fly;
1741         if (el.getBoundingClientRect) {
1742             b = el.getBoundingClientRect();
1743             I = J(document).getScroll();
1744             return  [b.left + I.left, b.top + I.top];
1745         }
1746         var  x = 0, y = 0;
1747
1748         p = el;
1749
1750         var  K = J(el).getStyle("position") == "absolute";
1751
1752         while (p) {
1753
1754             x += p.offsetLeft;
1755             y += p.offsetTop;
1756
1757             if (!K && J(p).getStyle("position") == "absolute") {
1758                 K = true;
1759             }
1760
1761             if (Roo.isGecko) {
1762                 pe = J(p);
1763
1764                 var  bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1765                 var  bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1766
1767
1768                 x += bl;
1769                 y += bt;
1770
1771
1772                 if (p != el && pe.getStyle('overflow') != 'visible') {
1773                     x += bl;
1774                     y += bt;
1775                 }
1776             }
1777
1778             p = p.offsetParent;
1779         }
1780
1781         if (Roo.isSafari && K) {
1782             x -= bd.offsetLeft;
1783             y -= bd.offsetTop;
1784         }
1785
1786         if (Roo.isGecko && !K) {
1787             var  dbd = J(bd);
1788             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1789             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1790         }
1791
1792
1793         p = el.parentNode;
1794         while (p && p != bd) {
1795             if (!Roo.isOpera || (p.tagName != 'TR' && J(p).getStyle("display") != "inline")) {
1796                 x -= p.scrollLeft;
1797                 y -= p.scrollTop;
1798             }
1799
1800             p = p.parentNode;
1801         }
1802         return  [x, y];
1803     },
1804  
1805   
1806
1807
1808     setXY : function(el, xy) {
1809         el = Roo.fly(el, '_setXY');
1810         el.position();
1811         var  L = el.translatePoints(xy);
1812         if (xy[0] !== false) {
1813             el.dom.style.left = L.left + "px";
1814         }
1815         if (xy[1] !== false) {
1816             el.dom.style.top = L.top + "px";
1817         }
1818     },
1819
1820     setX : function(el, x) {
1821         this.setXY(el, [x, false]);
1822     },
1823
1824     setY : function(el, y) {
1825         this.setXY(el, [false, y]);
1826     }
1827 };
1828
1829 /*
1830  * Portions of this file are based on pieces of Yahoo User Interface Library
1831  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1832  * YUI licensed under the BSD License:
1833  * http://developer.yahoo.net/yui/license.txt
1834  * <script type="text/javascript">
1835  *
1836  */
1837
1838 Roo.lib.Event = function() {
1839     var  A = false;
1840     var  B = [];
1841     var  C = [];
1842     var  D = 0;
1843     var  E = [];
1844     var  F = 0;
1845     var  G = null;
1846
1847     return  {
1848         POLL_RETRYS: 200,
1849         POLL_INTERVAL: 20,
1850         EL: 0,
1851         TYPE: 1,
1852         FN: 2,
1853         WFN: 3,
1854         OBJ: 3,
1855         ADJ_SCOPE: 4,
1856         _interval: null,
1857
1858         startInterval: function() {
1859             if (!this._interval) {
1860                 var  self = this;
1861                 var  callback = function() {
1862                     self._tryPreloadAttach();
1863                 };
1864                 this._interval = setInterval(callback, this.POLL_INTERVAL);
1865
1866             }
1867         },
1868
1869         onAvailable: function(h, k, m, n) {
1870             E.push({ id:         h,
1871                 fn:         k,
1872                 obj:        m,
1873                 override:   n,
1874                 checkReady: false    });
1875
1876             D = this.POLL_RETRYS;
1877             this.startInterval();
1878         },
1879
1880
1881         addListener: function(el, o, fn) {
1882             el = Roo.getDom(el);
1883             if (!el || !fn) {
1884                 return  false;
1885             }
1886
1887             if ("unload" == o) {
1888                 C[C.length] =
1889                 [el, o, fn];
1890                 return  true;
1891             }
1892
1893             var  p = function(e) {
1894                 return  fn(Roo.lib.Event.getEvent(e));
1895             };
1896
1897             var  li = [el, o, fn, p];
1898
1899             var  q = B.length;
1900             B[q] = li;
1901
1902             this.doAdd(el, o, p, false);
1903             return  true;
1904
1905         },
1906
1907
1908         removeListener: function(el, r, fn) {
1909             var  i, s;
1910
1911             el = Roo.getDom(el);
1912
1913             if(!fn) {
1914                 return  this.purgeElement(el, false, r);
1915             }
1916
1917
1918             if ("unload" == r) {
1919
1920                 for (i = 0,s = C.length; i < s; i++) {
1921                     var  li = C[i];
1922                     if (li &&
1923                         li[0] == el &&
1924                         li[1] == r &&
1925                         li[2] == fn) {
1926                         C.splice(i, 1);
1927                         return  true;
1928                     }
1929                 }
1930
1931                 return  false;
1932             }
1933
1934             var  u = null;
1935
1936
1937             var  v = arguments[3];
1938
1939             if ("undefined" == typeof  v) {
1940                 v = this._getCacheIndex(el, r, fn);
1941             }
1942
1943             if (v >= 0) {
1944                 u = B[v];
1945             }
1946
1947             if (!el || !u) {
1948                 return  false;
1949             }
1950
1951
1952             this.doRemove(el, r, u[this.WFN], false);
1953
1954             delete  B[v][this.WFN];
1955             delete  B[v][this.FN];
1956             B.splice(v, 1);
1957
1958             return  true;
1959
1960         },
1961
1962
1963         getTarget: function(ev, w) {
1964             ev = ev.browserEvent || ev;
1965             var  t = ev.target || ev.srcElement;
1966             return  this.resolveTextNode(t);
1967         },
1968
1969
1970         resolveTextNode: function(z) {
1971             if (Roo.isSafari && z && 3 == z.nodeType) {
1972                 return  z.parentNode;
1973             } else  {
1974                 return  z;
1975             }
1976         },
1977
1978
1979         getPageX: function(ev) {
1980             ev = ev.browserEvent || ev;
1981             var  x = ev.pageX;
1982             if (!x && 0 !== x) {
1983                 x = ev.clientX || 0;
1984
1985                 if (Roo.isIE) {
1986                     x += this.getScroll()[1];
1987                 }
1988             }
1989
1990             return  x;
1991         },
1992
1993
1994         getPageY: function(ev) {
1995             ev = ev.browserEvent || ev;
1996             var  y = ev.pageY;
1997             if (!y && 0 !== y) {
1998                 y = ev.clientY || 0;
1999
2000                 if (Roo.isIE) {
2001                     y += this.getScroll()[0];
2002                 }
2003             }
2004
2005
2006             return  y;
2007         },
2008
2009
2010         getXY: function(ev) {
2011             ev = ev.browserEvent || ev;
2012             return  [this.getPageX(ev), this.getPageY(ev)];
2013         },
2014
2015
2016         getRelatedTarget: function(ev) {
2017             ev = ev.browserEvent || ev;
2018             var  t = ev.relatedTarget;
2019             if (!t) {
2020                 if (ev.type == "mouseout") {
2021                     t = ev.toElement;
2022                 } else  if (ev.type == "mouseover") {
2023                     t = ev.fromElement;
2024                 }
2025             }
2026
2027             return  this.resolveTextNode(t);
2028         },
2029
2030
2031         getTime: function(ev) {
2032             ev = ev.browserEvent || ev;
2033             if (!ev.time) {
2034                 var  t = new  Date().getTime();
2035                 try {
2036                     ev.time = t;
2037                 } catch(ex) {
2038                     this.lastError = ex;
2039                     return  t;
2040                 }
2041             }
2042
2043             return  ev.time;
2044         },
2045
2046
2047         stopEvent: function(ev) {
2048             this.stopPropagation(ev);
2049             this.preventDefault(ev);
2050         },
2051
2052
2053         stopPropagation: function(ev) {
2054             ev = ev.browserEvent || ev;
2055             if (ev.stopPropagation) {
2056                 ev.stopPropagation();
2057             } else  {
2058                 ev.cancelBubble = true;
2059             }
2060         },
2061
2062
2063         preventDefault: function(ev) {
2064             ev = ev.browserEvent || ev;
2065             if(ev.preventDefault) {
2066                 ev.preventDefault();
2067             } else  {
2068                 ev.returnValue = false;
2069             }
2070         },
2071
2072
2073         getEvent: function(e) {
2074             var  ev = e || window.event;
2075             if (!ev) {
2076                 var  c = this.getEvent.caller;
2077                 while (c) {
2078                     ev = c.arguments[0];
2079                     if (ev && Event == ev.constructor) {
2080                         break;
2081                     }
2082
2083                     c = c.caller;
2084                 }
2085             }
2086             return  ev;
2087         },
2088
2089
2090         getCharCode: function(ev) {
2091             ev = ev.browserEvent || ev;
2092             return  ev.charCode || ev.keyCode || 0;
2093         },
2094
2095
2096         _getCacheIndex: function(el, AA, fn) {
2097             for (var  i = 0,s = B.length; i < s; ++i) {
2098                 var  li = B[i];
2099                 if (li &&
2100                     li[this.FN] == fn &&
2101                     li[this.EL] == el &&
2102                     li[this.TYPE] == AA) {
2103                     return  i;
2104                 }
2105             }
2106
2107             return  -1;
2108         },
2109
2110
2111         elCache: {},
2112
2113
2114         getEl: function(id) {
2115             return  document.getElementById(id);
2116         },
2117
2118
2119         clearCache: function() {
2120         },
2121
2122
2123         _load: function(e) {
2124             A = true;
2125             var  EU = Roo.lib.Event;
2126
2127
2128             if (Roo.isIE) {
2129                 EU.doRemove(window, "load", EU._load);
2130             }
2131         },
2132
2133
2134         _tryPreloadAttach: function() {
2135
2136             if (this.locked) {
2137                 return  false;
2138             }
2139
2140
2141             this.locked = true;
2142
2143
2144             var  AB = !A;
2145             if (!AB) {
2146                 AB = (D > 0);
2147             }
2148
2149
2150             var  AC = [];
2151             for (var  i = 0,s = E.length; i < s; ++i) {
2152                 var  item = E[i];
2153                 if (item) {
2154                     var  el = this.getEl(item.id);
2155
2156                     if (el) {
2157                         if (!item.checkReady ||
2158                             A ||
2159                             el.nextSibling ||
2160                             (document && document.body)) {
2161
2162                             var  scope = el;
2163                             if (item.override) {
2164                                 if (item.override === true) {
2165                                     scope = item.obj;
2166                                 } else  {
2167                                     scope = item.override;
2168                                 }
2169                             }
2170
2171                             item.fn.call(scope, item.obj);
2172                             E[i] = null;
2173                         }
2174                     } else  {
2175                         AC.push(item);
2176                     }
2177                 }
2178             }
2179
2180
2181             D = (AC.length === 0) ? 0 : D - 1;
2182
2183             if (AB) {
2184
2185                 this.startInterval();
2186             } else  {
2187                 clearInterval(this._interval);
2188                 this._interval = null;
2189             }
2190
2191
2192             this.locked = false;
2193
2194             return  true;
2195
2196         },
2197
2198
2199         purgeElement: function(el, AD, AE) {
2200             var  AF = this.getListeners(el, AE);
2201             if (AF) {
2202                 for (var  i = 0,s = AF.length; i < s; ++i) {
2203                     var  l = AF[i];
2204                     this.removeListener(el, l.type, l.fn);
2205                 }
2206             }
2207
2208             if (AD && el && el.childNodes) {
2209                 for (i = 0,s = el.childNodes.length; i < s; ++i) {
2210                     this.purgeElement(el.childNodes[i], AD, AE);
2211                 }
2212             }
2213         },
2214
2215
2216         getListeners: function(el, AG) {
2217             var  AH = [], AI;
2218             if (!AG) {
2219                 AI = [B, C];
2220             } else  if (AG == "unload") {
2221                 AI = [C];
2222             } else  {
2223                 AI = [B];
2224             }
2225
2226             for (var  j = 0; j < AI.length; ++j) {
2227                 var  searchList = AI[j];
2228                 if (searchList && searchList.length > 0) {
2229                     for (var  i = 0,s = searchList.length; i < s; ++i) {
2230                         var  l = searchList[i];
2231                         if (l && l[this.EL] === el &&
2232                             (!AG || AG === l[this.TYPE])) {
2233                             AH.push({
2234                                 type:   l[this.TYPE],
2235                                 fn:     l[this.FN],
2236                                 obj:    l[this.OBJ],
2237                                 adjust: l[this.ADJ_SCOPE],
2238                                 index:  i
2239                             });
2240                         }
2241                     }
2242                 }
2243             }
2244
2245             return  (AH.length) ? AH : null;
2246         },
2247
2248
2249         _unload: function(e) {
2250
2251             var  EU = Roo.lib.Event, i, j, l, AJ, AK;
2252
2253             for (i = 0,AJ = C.length; i < AJ; ++i) {
2254                 l = C[i];
2255                 if (l) {
2256                     var  scope = window;
2257                     if (l[EU.ADJ_SCOPE]) {
2258                         if (l[EU.ADJ_SCOPE] === true) {
2259                             scope = l[EU.OBJ];
2260                         } else  {
2261                             scope = l[EU.ADJ_SCOPE];
2262                         }
2263                     }
2264
2265                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2266                     C[i] = null;
2267                     l = null;
2268                     scope = null;
2269                 }
2270             }
2271
2272
2273             C = null;
2274
2275             if (B && B.length > 0) {
2276                 j = B.length;
2277                 while (j) {
2278                     AK = j - 1;
2279                     l = B[AK];
2280                     if (l) {
2281                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2282                                 l[EU.FN], AK);
2283                     }
2284
2285                     j = j - 1;
2286                 }
2287
2288                 l = null;
2289
2290                 EU.clearCache();
2291             }
2292
2293
2294             EU.doRemove(window, "unload", EU._unload);
2295
2296         },
2297
2298
2299         getScroll: function() {
2300             var  dd = document.documentElement, db = document.body;
2301             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2302                 return  [dd.scrollTop, dd.scrollLeft];
2303             } else  if (db) {
2304                 return  [db.scrollTop, db.scrollLeft];
2305             } else  {
2306                 return  [0, 0];
2307             }
2308         },
2309
2310
2311         doAdd: function () {
2312             if (window.addEventListener) {
2313                 return  function(el, AL, fn, AM) {
2314                     el.addEventListener(AL, fn, (AM));
2315                 };
2316             } else  if (window.attachEvent) {
2317                 return  function(el, AL, fn, AM) {
2318                     el.attachEvent("on" + AL, fn);
2319                 };
2320             } else  {
2321                 return  function() {
2322                 };
2323             }
2324         }(),
2325
2326
2327         doRemove: function() {
2328             if (window.removeEventListener) {
2329                 return  function (el, AL, fn, AM) {
2330                     el.removeEventListener(AL, fn, (AM));
2331                 };
2332             } else  if (window.detachEvent) {
2333                 return  function (el, AL, fn) {
2334                     el.detachEvent("on" + AL, fn);
2335                 };
2336             } else  {
2337                 return  function() {
2338                 };
2339             }
2340         }()
2341     };
2342     
2343 }();
2344 (function() {     
2345    
2346     var  E = Roo.lib.Event;
2347     E.on = E.addListener;
2348     E.un = E.removeListener;
2349
2350     if (document && document.body) {
2351         E._load();
2352     } else  {
2353         E.doAdd(window, "load", E._load);
2354     }
2355
2356     E.doAdd(window, "unload", E._unload);
2357     E._tryPreloadAttach();
2358 })();
2359
2360
2361 /*
2362  * Portions of this file are based on pieces of Yahoo User Interface Library
2363  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2364  * YUI licensed under the BSD License:
2365  * http://developer.yahoo.net/yui/license.txt
2366  * <script type="text/javascript">
2367  *
2368  */
2369
2370 (function() {
2371     
2372     Roo.lib.Ajax = {
2373         request : function(A, B, cb, C, D) {
2374             if(D){
2375                 var  hs = D.headers;
2376                 if(hs){
2377                     for(var  h  in  hs){
2378                         if(hs.hasOwnProperty(h)){
2379                             this.initHeader(h, hs[h], false);
2380                         }
2381                     }
2382                 }
2383                 if(D.xmlData){
2384                     this.initHeader('Content-Type', 'text/xml', false);
2385                     A = 'POST';
2386                     C = D.xmlData;
2387                 }
2388             }
2389
2390             return  this.asyncRequest(A, B, cb, C);
2391         },
2392
2393         serializeForm : function(E) {
2394             if(typeof  E == 'string') {
2395                 E = (document.getElementById(E) || document.forms[E]);
2396             }
2397
2398             var  el, F, G, H, I = '', J = false;
2399             for (var  i = 0; i < E.elements.length; i++) {
2400                 el = E.elements[i];
2401                 H = E.elements[i].disabled;
2402                 F = E.elements[i].name;
2403                 G = E.elements[i].value;
2404
2405                 if (!H && F){
2406                     switch (el.type)
2407                             {
2408                         case  'select-one':
2409                         case  'select-multiple':
2410                             for (var  j = 0; j < el.options.length; j++) {
2411                                 if (el.options[j].selected) {
2412                                     if (Roo.isIE) {
2413                                         I += encodeURIComponent(F) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2414                                     }
2415                                     else  {
2416                                         I += encodeURIComponent(F) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2417                                     }
2418                                 }
2419                             }
2420                             break;
2421                         case  'radio':
2422                         case  'checkbox':
2423                             if (el.checked) {
2424                                 I += encodeURIComponent(F) + '=' + encodeURIComponent(G) + '&';
2425                             }
2426                             break;
2427                         case  'file':
2428
2429                         case  undefined:
2430
2431                         case  'reset':
2432
2433                         case  'button':
2434
2435                             break;
2436                         case  'submit':
2437                             if(J == false) {
2438                                 I += encodeURIComponent(F) + '=' + encodeURIComponent(G) + '&';
2439                                 J = true;
2440                             }
2441                             break;
2442                         default:
2443                             I += encodeURIComponent(F) + '=' + encodeURIComponent(G) + '&';
2444                             break;
2445                     }
2446                 }
2447             }
2448
2449             I = I.substr(0, I.length - 1);
2450             return  I;
2451         },
2452
2453         headers:{},
2454
2455         hasHeaders:false,
2456
2457         useDefaultHeader:true,
2458
2459         defaultPostHeader:'application/x-www-form-urlencoded',
2460
2461         useDefaultXhrHeader:true,
2462
2463         defaultXhrHeader:'XMLHttpRequest',
2464
2465         hasDefaultHeaders:true,
2466
2467         defaultHeaders:{},
2468
2469         poll:{},
2470
2471         timeout:{},
2472
2473         pollInterval:50,
2474
2475         transactionId:0,
2476
2477         setProgId:function(id)
2478         {
2479             this.activeX.unshift(id);
2480         },
2481
2482         setDefaultPostHeader:function(b)
2483         {
2484             this.useDefaultHeader = b;
2485         },
2486
2487         setDefaultXhrHeader:function(b)
2488         {
2489             this.useDefaultXhrHeader = b;
2490         },
2491
2492         setPollingInterval:function(i)
2493         {
2494             if (typeof  i == 'number' && isFinite(i)) {
2495                 this.pollInterval = i;
2496             }
2497         },
2498
2499         createXhrObject:function(K)
2500         {
2501             var  L,M;
2502             try
2503             {
2504
2505                 M = new  XMLHttpRequest();
2506
2507                 L = { conn:M, tId:K };
2508             }
2509             catch(e)
2510             {
2511                 for (var  i = 0; i < this.activeX.length; ++i) {
2512                     try
2513                     {
2514
2515                         http = new  ActiveXObject(this.activeX[i]);
2516
2517                         obj = { conn:http, tId:transactionId };
2518                         break;
2519                     }
2520                     catch(e) {
2521                     }
2522                 }
2523             }
2524             finally
2525             {
2526                 return  L;
2527             }
2528         },
2529
2530         getConnectionObject:function()
2531         {
2532             var  o;
2533             var  N = this.transactionId;
2534
2535             try
2536             {
2537                 o = this.createXhrObject(N);
2538                 if (o) {
2539                     this.transactionId++;
2540                 }
2541             }
2542             catch(e) {
2543             }
2544             finally
2545             {
2546                 return  o;
2547             }
2548         },
2549
2550         asyncRequest:function(O, P, Q, R)
2551         {
2552             var  o = this.getConnectionObject();
2553
2554             if (!o) {
2555                 return  null;
2556             }
2557             else  {
2558                 o.conn.open(O, P, true);
2559
2560                 if (this.useDefaultXhrHeader) {
2561                     if (!this.defaultHeaders['X-Requested-With']) {
2562                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2563                     }
2564                 }
2565
2566                 if(R && this.useDefaultHeader){
2567                     this.initHeader('Content-Type', this.defaultPostHeader);
2568                 }
2569
2570                  if (this.hasDefaultHeaders || this.hasHeaders) {
2571                     this.setHeader(o);
2572                 }
2573
2574
2575                 this.handleReadyState(o, Q);
2576                 o.conn.send(R || null);
2577
2578                 return  o;
2579             }
2580         },
2581
2582         handleReadyState:function(o, S)
2583         {
2584             var  T = this;
2585
2586             if (S && S.timeout) {
2587                 this.timeout[o.tId] = window.setTimeout(function() {
2588                     T.abort(o, S, true);
2589                 }, S.timeout);
2590             }
2591
2592
2593             this.poll[o.tId] = window.setInterval(
2594                     function() {
2595                         if (o.conn && o.conn.readyState == 4) {
2596                             window.clearInterval(T.poll[o.tId]);
2597                             delete  T.poll[o.tId];
2598
2599                             if(S && S.timeout) {
2600                                 window.clearTimeout(T.timeout[o.tId]);
2601                                 delete  T.timeout[o.tId];
2602                             }
2603
2604
2605                             T.handleTransactionResponse(o, S);
2606                         }
2607                     }
2608                     , this.pollInterval);
2609         },
2610
2611         handleTransactionResponse:function(o, U, V)
2612         {
2613
2614             if (!U) {
2615                 this.releaseObject(o);
2616                 return;
2617             }
2618
2619             var  W, X;
2620
2621             try
2622             {
2623                 if (o.conn.status !== undefined && o.conn.status != 0) {
2624                     W = o.conn.status;
2625                 }
2626                 else  {
2627                     W = 13030;
2628                 }
2629             }
2630             catch(e) {
2631
2632
2633                 httpStatus = 13030;
2634             }
2635
2636             if (W >= 200 && W < 300) {
2637                 X = this.createResponseObject(o, U.argument);
2638                 if (U.success) {
2639                     if (!U.scope) {
2640                         U.success(X);
2641                     }
2642                     else  {
2643
2644
2645                         U.success.apply(U.scope, [X]);
2646                     }
2647                 }
2648             }
2649             else  {
2650                 switch (W) {
2651
2652                     case  12002:
2653                     case  12029:
2654                     case  12030:
2655                     case  12031:
2656                     case  12152:
2657                     case  13030:
2658                         X = this.createExceptionObject(o.tId, U.argument, (V ? V : false));
2659                         if (U.failure) {
2660                             if (!U.scope) {
2661                                 U.failure(X);
2662                             }
2663                             else  {
2664                                 U.failure.apply(U.scope, [X]);
2665                             }
2666                         }
2667                         break;
2668                     default:
2669                         X = this.createResponseObject(o, U.argument);
2670                         if (U.failure) {
2671                             if (!U.scope) {
2672                                 U.failure(X);
2673                             }
2674                             else  {
2675                                 U.failure.apply(U.scope, [X]);
2676                             }
2677                         }
2678                 }
2679             }
2680
2681
2682             this.releaseObject(o);
2683             X = null;
2684         },
2685
2686         createResponseObject:function(o, Y)
2687         {
2688             var  Z = {};
2689             var  a = {};
2690
2691             try
2692             {
2693                 var  headerStr = o.conn.getAllResponseHeaders();
2694                 var  header = headerStr.split('\n');
2695                 for (var  i = 0; i < header.length; i++) {
2696                     var  delimitPos = header[i].indexOf(':');
2697                     if (delimitPos != -1) {
2698                         a[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2699                     }
2700                 }
2701             }
2702             catch(e) {
2703             }
2704
2705
2706             Z.tId = o.tId;
2707             Z.status = o.conn.status;
2708             Z.statusText = o.conn.statusText;
2709             Z.getResponseHeader = a;
2710             Z.getAllResponseHeaders = headerStr;
2711             Z.responseText = o.conn.responseText;
2712             Z.responseXML = o.conn.responseXML;
2713
2714             if (typeof  Y !== undefined) {
2715                 Z.argument = Y;
2716             }
2717
2718             return  Z;
2719         },
2720
2721         createExceptionObject:function(c, d, f)
2722         {
2723             var  g = 0;
2724             var  k = 'communication failure';
2725             var  l = -1;
2726             var  m = 'transaction aborted';
2727
2728             var  n = {};
2729
2730             n.tId = c;
2731             if (f) {
2732                 n.status = l;
2733                 n.statusText = m;
2734             }
2735             else  {
2736                 n.status = g;
2737                 n.statusText = k;
2738             }
2739
2740             if (d) {
2741                 n.argument = d;
2742             }
2743
2744             return  n;
2745         },
2746
2747         initHeader:function(p, q, r)
2748         {
2749             var  s = (r) ? this.defaultHeaders : this.headers;
2750
2751             if (s[p] === undefined) {
2752                 s[p] = q;
2753             }
2754             else  {
2755
2756
2757                 s[p] = q + "," + s[p];
2758             }
2759
2760             if (r) {
2761                 this.hasDefaultHeaders = true;
2762             }
2763             else  {
2764                 this.hasHeaders = true;
2765             }
2766         },
2767
2768
2769         setHeader:function(o)
2770         {
2771             if (this.hasDefaultHeaders) {
2772                 for (var  prop  in  this.defaultHeaders) {
2773                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2774                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2775                     }
2776                 }
2777             }
2778
2779             if (this.hasHeaders) {
2780                 for (var  prop  in  this.headers) {
2781                     if (this.headers.hasOwnProperty(prop)) {
2782                         o.conn.setRequestHeader(prop, this.headers[prop]);
2783                     }
2784                 }
2785
2786                 this.headers = {};
2787                 this.hasHeaders = false;
2788             }
2789         },
2790
2791         resetDefaultHeaders:function() {
2792             delete  this.defaultHeaders;
2793             this.defaultHeaders = {};
2794             this.hasDefaultHeaders = false;
2795         },
2796
2797         abort:function(o, t, u)
2798         {
2799             if(this.isCallInProgress(o)) {
2800                 o.conn.abort();
2801                 window.clearInterval(this.poll[o.tId]);
2802                 delete  this.poll[o.tId];
2803                 if (u) {
2804                     delete  this.timeout[o.tId];
2805                 }
2806
2807
2808                 this.handleTransactionResponse(o, t, true);
2809
2810                 return  true;
2811             }
2812             else  {
2813                 return  false;
2814             }
2815         },
2816
2817
2818         isCallInProgress:function(o)
2819         {
2820             if (o && o.conn) {
2821                 return  o.conn.readyState != 4 && o.conn.readyState != 0;
2822             }
2823             else  {
2824
2825                 return  false;
2826             }
2827         },
2828
2829
2830         releaseObject:function(o)
2831         {
2832
2833             o.conn = null;
2834
2835             o = null;
2836         },
2837
2838         activeX:[
2839         'MSXML2.XMLHTTP.3.0',
2840         'MSXML2.XMLHTTP',
2841         'Microsoft.XMLHTTP'
2842         ]
2843
2844
2845     };
2846 })();
2847 /*
2848  * Portions of this file are based on pieces of Yahoo User Interface Library
2849  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2850  * YUI licensed under the BSD License:
2851  * http://developer.yahoo.net/yui/license.txt
2852  * <script type="text/javascript">
2853  *
2854  */
2855
2856 Roo.lib.Region = function(t, r, b, l) {
2857     this.top = t;
2858     this[1] = t;
2859     this.right = r;
2860     this.bottom = b;
2861     this.left = l;
2862     this[0] = l;
2863 };
2864
2865
2866 Roo.lib.Region.prototype = {
2867     contains : function(A) {
2868         return  ( A.left >= this.left &&
2869                  A.right <= this.right &&
2870                  A.top >= this.top &&
2871                  A.bottom <= this.bottom    );
2872
2873     },
2874
2875     getArea : function() {
2876         return  ( (this.bottom - this.top) * (this.right - this.left) );
2877     },
2878
2879     intersect : function(B) {
2880         var  t = Math.max(this.top, B.top);
2881         var  r = Math.min(this.right, B.right);
2882         var  b = Math.min(this.bottom, B.bottom);
2883         var  l = Math.max(this.left, B.left);
2884
2885         if (b >= t && r >= l) {
2886             return  new  Roo.lib.Region(t, r, b, l);
2887         } else  {
2888             return  null;
2889         }
2890     },
2891     union : function(C) {
2892         var  t = Math.min(this.top, C.top);
2893         var  r = Math.max(this.right, C.right);
2894         var  b = Math.max(this.bottom, C.bottom);
2895         var  l = Math.min(this.left, C.left);
2896
2897         return  new  Roo.lib.Region(t, r, b, l);
2898     },
2899
2900     adjust : function(t, l, b, r) {
2901         this.top += t;
2902         this.left += l;
2903         this.right += r;
2904         this.bottom += b;
2905         return  this;
2906     }
2907 };
2908
2909 Roo.lib.Region.getRegion = function(el) {
2910     var  p = Roo.lib.Dom.getXY(el);
2911
2912     var  t = p[1];
2913     var  r = p[0] + el.offsetWidth;
2914     var  b = p[1] + el.offsetHeight;
2915     var  l = p[0];
2916
2917     return  new  Roo.lib.Region(t, r, b, l);
2918 };
2919
2920 /*
2921  * Portions of this file are based on pieces of Yahoo User Interface Library
2922  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2923  * YUI licensed under the BSD License:
2924  * http://developer.yahoo.net/yui/license.txt
2925  * <script type="text/javascript">
2926  *
2927  */
2928 //@@dep Roo.lib.Region
2929
2930
2931 Roo.lib.Point = function(x, y) {
2932     if (x  instanceof  Array) {
2933         y = x[1];
2934         x = x[0];
2935     }
2936
2937     this.x = this.right = this.left = this[0] = x;
2938     this.y = this.top = this.bottom = this[1] = y;
2939 };
2940
2941 Roo.lib.Point.prototype = new  Roo.lib.Region();
2942
2943 /*
2944  * Portions of this file are based on pieces of Yahoo User Interface Library
2945  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2946  * YUI licensed under the BSD License:
2947  * http://developer.yahoo.net/yui/license.txt
2948  * <script type="text/javascript">
2949  *
2950  */
2951  
2952 (function() {   
2953
2954     Roo.lib.Anim = {
2955         scroll : function(el, A, B, C, cb, D) {
2956             this.run(el, A, B, C, cb, D, Roo.lib.Scroll);
2957         },
2958
2959         motion : function(el, E, F, G, cb, H) {
2960             this.run(el, E, F, G, cb, H, Roo.lib.Motion);
2961         },
2962
2963         color : function(el, I, J, K, cb, L) {
2964             this.run(el, I, J, K, cb, L, Roo.lib.ColorAnim);
2965         },
2966
2967         run : function(el, M, N, O, cb, P, Q) {
2968             Q = Q || Roo.lib.AnimBase;
2969             if (typeof  O == "string") {
2970                 O = Roo.lib.Easing[O];
2971             }
2972             var  R = new  Q(el, M, N, O);
2973             R.animateX(function() {
2974                 Roo.callback(cb, P);
2975             });
2976             return  R;
2977         }
2978     };
2979 })();
2980 /*
2981  * Portions of this file are based on pieces of Yahoo User Interface Library
2982  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2983  * YUI licensed under the BSD License:
2984  * http://developer.yahoo.net/yui/license.txt
2985  * <script type="text/javascript">
2986  *
2987  */
2988
2989 (function() {    
2990     var  A;
2991     
2992     function  B(el) {
2993         if (!A) {
2994             A = new  Roo.Element.Flyweight();
2995         }
2996
2997         A.dom = el;
2998         return  A;
2999     }
3000
3001
3002     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3003     
3004    
3005     
3006     Roo.lib.AnimBase = function(el, C, D, E) {
3007         if (el) {
3008             this.init(el, C, D, E);
3009         }
3010     };
3011
3012     Roo.lib.AnimBase.fly = B;
3013     
3014     
3015     
3016     Roo.lib.AnimBase.prototype = {
3017
3018         toString: function() {
3019             var  el = this.getEl();
3020             var  id = el.id || el.tagName;
3021             return  ("Anim " + id);
3022         },
3023
3024         patterns: {
3025             noNegatives:        /width|height|opacity|padding/i,
3026             offsetAttribute:  /^((width|height)|(top|left))$/,
3027             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3028             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3029         },
3030
3031
3032         doMethod: function(C, D, E) {
3033             return  this.method(this.currentFrame, D, E - D, this.totalFrames);
3034         },
3035
3036
3037         setAttribute: function(F, G, H) {
3038             if (this.patterns.noNegatives.test(F)) {
3039                 G = (G > 0) ? G : 0;
3040             }
3041
3042
3043             Roo.fly(this.getEl(), '_anim').setStyle(F, G + H);
3044         },
3045
3046
3047         getAttribute: function(I) {
3048             var  el = this.getEl();
3049             var  J = B(el).getStyle(I);
3050
3051             if (J !== 'auto' && !this.patterns.offsetUnit.test(J)) {
3052                 return  parseFloat(J);
3053             }
3054
3055             var  a = this.patterns.offsetAttribute.exec(I) || [];
3056             var  K = !!( a[3] );
3057             var  L = !!( a[2] );
3058
3059
3060             if (L || (B(el).getStyle('position') == 'absolute' && K)) {
3061                 J = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3062             } else  {
3063                 J = 0;
3064             }
3065
3066             return  J;
3067         },
3068
3069
3070         getDefaultUnit: function(M) {
3071             if (this.patterns.defaultUnit.test(M)) {
3072                 return  'px';
3073             }
3074
3075             return  '';
3076         },
3077
3078         animateX : function(N, O) {
3079             var  f = function() {
3080                 this.onComplete.removeListener(f);
3081                 if (typeof  N == "function") {
3082                     N.call(O || this, this);
3083                 }
3084             };
3085             this.onComplete.addListener(f, this);
3086             this.animate();
3087         },
3088
3089
3090         setRuntimeAttribute: function(P) {
3091             var  Q;
3092             var  R;
3093             var  S = this.attributes;
3094
3095             this.runtimeAttributes[P] = {};
3096
3097             var  T = function(U) {
3098                 return  (typeof  U !== 'undefined');
3099             };
3100
3101             if (!T(S[P]['to']) && !T(S[P]['by'])) {
3102                 return  false;
3103             }
3104
3105
3106             Q = ( T(S[P]['from']) ) ? S[P]['from'] : this.getAttribute(P);
3107
3108
3109             if (T(S[P]['to'])) {
3110                 R = S[P]['to'];
3111             } else  if (T(S[P]['by'])) {
3112                 if (Q.constructor == Array) {
3113                     R = [];
3114                     for (var  i = 0, len = Q.length; i < len; ++i) {
3115                         R[i] = Q[i] + S[P]['by'][i];
3116                     }
3117                 } else  {
3118                     R = Q + S[P]['by'];
3119                 }
3120             }
3121
3122
3123             this.runtimeAttributes[P].start = Q;
3124             this.runtimeAttributes[P].end = R;
3125
3126
3127             this.runtimeAttributes[P].unit = ( T(S[P].unit) ) ? S[P]['unit'] : this.getDefaultUnit(P);
3128         },
3129
3130
3131         init: function(el, U, V, W) {
3132
3133             var  X = false;
3134
3135
3136             var  Y = null;
3137
3138
3139             var  Z = 0;
3140
3141
3142             el = Roo.getDom(el);
3143
3144
3145             this.attributes = U || {};
3146
3147
3148             this.duration = V || 1;
3149
3150
3151             this.method = W || Roo.lib.Easing.easeNone;
3152
3153
3154             this.useSeconds = true;
3155
3156
3157             this.currentFrame = 0;
3158
3159
3160             this.totalFrames = Roo.lib.AnimMgr.fps;
3161
3162
3163             this.getEl = function() {
3164                 return  el;
3165             };
3166
3167
3168             this.isAnimated = function() {
3169                 return  X;
3170             };
3171
3172
3173             this.getStartTime = function() {
3174                 return  Y;
3175             };
3176
3177             this.runtimeAttributes = {};
3178
3179
3180             this.animate = function() {
3181                 if (this.isAnimated()) {
3182                     return  false;
3183                 }
3184
3185
3186                 this.currentFrame = 0;
3187
3188                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3189
3190                 Roo.lib.AnimMgr.registerElement(this);
3191             };
3192
3193
3194             this.stop = function(e) {
3195                 if (e) {
3196                     this.currentFrame = this.totalFrames;
3197                     this._onTween.fire();
3198                 }
3199
3200                 Roo.lib.AnimMgr.stop(this);
3201             };
3202
3203             var  b = function() {
3204                 this.onStart.fire();
3205
3206                 this.runtimeAttributes = {};
3207                 for (var  P  in  this.attributes) {
3208                     this.setRuntimeAttribute(P);
3209                 }
3210
3211
3212                 X = true;
3213                 Z = 0;
3214                 Y = new  Date();
3215             };
3216
3217
3218             var  c = function() {
3219                 var  e = {
3220                     duration: new  Date() - this.getStartTime(),
3221                     currentFrame: this.currentFrame
3222                 };
3223
3224                 e.toString = function() {
3225                     return  (
3226                             'duration: ' + e.duration +
3227                             ', currentFrame: ' + e.currentFrame
3228                             );
3229                 };
3230
3231                 this.onTween.fire(e);
3232
3233                 var  g = this.runtimeAttributes;
3234
3235                 for (var  P  in  g) {
3236                     this.setAttribute(P, this.doMethod(P, g[P].start, g[P].end), g[P].unit);
3237                 }
3238
3239
3240                 Z += 1;
3241             };
3242
3243             var  d = function() {
3244                 var  e = (new  Date() - Y) / 1000 ;
3245
3246                 var  g = {
3247                     duration: e,
3248                     frames: Z,
3249                     fps: Z / e
3250                 };
3251
3252                 g.toString = function() {
3253                     return  (
3254                             'duration: ' + g.duration +
3255                             ', frames: ' + g.frames +
3256                             ', fps: ' + g.fps
3257                             );
3258                 };
3259
3260                 X = false;
3261                 Z = 0;
3262                 this.onComplete.fire(g);
3263             };
3264
3265
3266             this._onStart = new  Roo.util.Event(this);
3267             this.onStart = new  Roo.util.Event(this);
3268             this.onTween = new  Roo.util.Event(this);
3269             this._onTween = new  Roo.util.Event(this);
3270             this.onComplete = new  Roo.util.Event(this);
3271             this._onComplete = new  Roo.util.Event(this);
3272             this._onStart.addListener(b);
3273             this._onTween.addListener(c);
3274             this._onComplete.addListener(d);
3275         }
3276     };
3277 })();
3278
3279 /*
3280  * Portions of this file are based on pieces of Yahoo User Interface Library
3281  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3282  * YUI licensed under the BSD License:
3283  * http://developer.yahoo.net/yui/license.txt
3284  * <script type="text/javascript">
3285  *
3286  */
3287
3288 Roo.lib.AnimMgr = new  function() {
3289
3290         var  A = null;
3291
3292
3293         var  B = [];
3294
3295
3296         var  C = 0;
3297
3298
3299         this.fps = 1000;
3300
3301
3302         this.delay = 1;
3303
3304
3305         this.registerElement = function(F) {
3306             B[B.length] = F;
3307             C += 1;
3308             F._onStart.fire();
3309             this.start();
3310         };
3311
3312
3313         this.unRegister = function(F, G) {
3314             F._onComplete.fire();
3315             G = G || D(F);
3316             if (G != -1) {
3317                 B.splice(G, 1);
3318             }
3319
3320
3321             C -= 1;
3322             if (C <= 0) {
3323                 this.stop();
3324             }
3325         };
3326
3327
3328         this.start = function() {
3329             if (A === null) {
3330                 A = setInterval(this.run, this.delay);
3331             }
3332         };
3333
3334
3335         this.stop = function(F) {
3336             if (!F) {
3337                 clearInterval(A);
3338
3339                 for (var  i = 0, len = B.length; i < len; ++i) {
3340                     if (B[0].isAnimated()) {
3341                         this.unRegister(B[0], 0);
3342                     }
3343                 }
3344
3345
3346                 B = [];
3347                 A = null;
3348                 C = 0;
3349             }
3350             else  {
3351                 this.unRegister(F);
3352             }
3353         };
3354
3355
3356         this.run = function() {
3357             for (var  i = 0, len = B.length; i < len; ++i) {
3358                 var  tween = B[i];
3359                 if (!tween || !tween.isAnimated()) {
3360                     continue;
3361                 }
3362
3363                 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3364                 {
3365                     tween.currentFrame += 1;
3366
3367                     if (tween.useSeconds) {
3368                         E(tween);
3369                     }
3370
3371                     tween._onTween.fire();
3372                 }
3373                 else  {
3374                     Roo.lib.AnimMgr.stop(tween, i);
3375                 }
3376             }
3377         };
3378
3379         var  D = function(F) {
3380             for (var  i = 0, len = B.length; i < len; ++i) {
3381                 if (B[i] == F) {
3382                     return  i;
3383                 }
3384             }
3385             return  -1;
3386         };
3387
3388
3389         var  E = function(F) {
3390             var  G = F.totalFrames;
3391             var  H = F.currentFrame;
3392             var  I = (F.currentFrame * F.duration * 1000 / F.totalFrames);
3393             var  J = (new  Date() - F.getStartTime());
3394             var  K = 0;
3395
3396             if (J < F.duration * 1000) {
3397                 K = Math.round((J / I - 1) * F.currentFrame);
3398             } else  {
3399                 K = G - (H + 1);
3400             }
3401             if (K > 0 && isFinite(K)) {
3402                 if (F.currentFrame + K >= G) {
3403                     K = G - (H + 1);
3404                 }
3405
3406
3407                 F.currentFrame += K;
3408             }
3409         };
3410     };
3411 /*
3412  * Portions of this file are based on pieces of Yahoo User Interface Library
3413  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3414  * YUI licensed under the BSD License:
3415  * http://developer.yahoo.net/yui/license.txt
3416  * <script type="text/javascript">
3417  *
3418  */
3419 Roo.lib.Bezier = new  function() {
3420
3421         this.getPosition = function(A, t) {
3422             var  n = A.length;
3423             var  B = [];
3424
3425             for (var  i = 0; i < n; ++i) {
3426                 B[i] = [A[i][0], A[i][1]];
3427             }
3428
3429             for (var  j = 1; j < n; ++j) {
3430                 for (i = 0; i < n - j; ++i) {
3431                     B[i][0] = (1 - t) * B[i][0] + t * B[parseInt(i + 1, 10)][0];
3432                     B[i][1] = (1 - t) * B[i][1] + t * B[parseInt(i + 1, 10)][1];
3433                 }
3434             }
3435
3436             return  [ B[0][0], B[0][1] ];
3437
3438         };
3439     };
3440 /*
3441  * Portions of this file are based on pieces of Yahoo User Interface Library
3442  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3443  * YUI licensed under the BSD License:
3444  * http://developer.yahoo.net/yui/license.txt
3445  * <script type="text/javascript">
3446  *
3447  */
3448 (function() {
3449
3450     Roo.lib.ColorAnim = function(el, D, E, F) {
3451         Roo.lib.ColorAnim.superclass.constructor.call(this, el, D, E, F);
3452     };
3453
3454     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3455
3456     var  A = Roo.lib.AnimBase.fly;
3457     var  Y = Roo.lib;
3458     var  B = Y.ColorAnim.superclass;
3459     var  C = Y.ColorAnim.prototype;
3460
3461     C.toString = function() {
3462         var  el = this.getEl();
3463         var  id = el.id || el.tagName;
3464         return  ("ColorAnim " + id);
3465     };
3466
3467     C.patterns.color = /color$/i;
3468     C.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3469     C.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3470     C.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3471     C.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3472
3473
3474     C.parseColor = function(s) {
3475         if (s.length == 3) {
3476             return  s;
3477         }
3478
3479         var  c = this.patterns.hex.exec(s);
3480         if (c && c.length == 4) {
3481             return  [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3482         }
3483
3484
3485         c = this.patterns.rgb.exec(s);
3486         if (c && c.length == 4) {
3487             return  [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3488         }
3489
3490
3491         c = this.patterns.hex3.exec(s);
3492         if (c && c.length == 4) {
3493             return  [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3494         }
3495
3496         return  null;
3497     };
3498     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3499     C.getAttribute = function(D) {
3500         var  el = this.getEl();
3501         if (this.patterns.color.test(D)) {
3502             var  val = A(el).getStyle(D);
3503
3504             if (this.patterns.transparent.test(val)) {
3505                 var  parent = el.parentNode;
3506                 val = A(parent).getStyle(D);
3507
3508                 while (parent && this.patterns.transparent.test(val)) {
3509                     parent = parent.parentNode;
3510                     val = A(parent).getStyle(D);
3511                     if (parent.tagName.toUpperCase() == 'HTML') {
3512                         val = '#fff';
3513                     }
3514                 }
3515             }
3516         } else  {
3517             val = B.getAttribute.call(this, D);
3518         }
3519
3520         return  val;
3521     };
3522     C.getAttribute = function(D) {
3523         var  el = this.getEl();
3524         if (this.patterns.color.test(D)) {
3525             var  val = A(el).getStyle(D);
3526
3527             if (this.patterns.transparent.test(val)) {
3528                 var  parent = el.parentNode;
3529                 val = A(parent).getStyle(D);
3530
3531                 while (parent && this.patterns.transparent.test(val)) {
3532                     parent = parent.parentNode;
3533                     val = A(parent).getStyle(D);
3534                     if (parent.tagName.toUpperCase() == 'HTML') {
3535                         val = '#fff';
3536                     }
3537                 }
3538             }
3539         } else  {
3540             val = B.getAttribute.call(this, D);
3541         }
3542
3543         return  val;
3544     };
3545
3546     C.doMethod = function(D, E, F) {
3547         var  G;
3548
3549         if (this.patterns.color.test(D)) {
3550             G = [];
3551             for (var  i = 0, len = E.length; i < len; ++i) {
3552                 G[i] = B.doMethod.call(this, D, E[i], F[i]);
3553             }
3554
3555
3556             G = 'rgb(' + Math.floor(G[0]) + ',' + Math.floor(G[1]) + ',' + Math.floor(G[2]) + ')';
3557         }
3558         else  {
3559             G = B.doMethod.call(this, D, E, F);
3560         }
3561
3562         return  G;
3563     };
3564
3565     C.setRuntimeAttribute = function(D) {
3566         B.setRuntimeAttribute.call(this, D);
3567
3568         if (this.patterns.color.test(D)) {
3569             var  attributes = this.attributes;
3570             var  start = this.parseColor(this.runtimeAttributes[D].start);
3571             var  end = this.parseColor(this.runtimeAttributes[D].end);
3572
3573             if (typeof  attributes[D]['to'] === 'undefined' && typeof  attributes[D]['by'] !== 'undefined') {
3574                 end = this.parseColor(attributes[D].by);
3575
3576                 for (var  i = 0, len = start.length; i < len; ++i) {
3577                     end[i] = start[i] + end[i];
3578                 }
3579             }
3580
3581
3582             this.runtimeAttributes[D].start = start;
3583             this.runtimeAttributes[D].end = end;
3584         }
3585     };
3586 })();
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 Roo.lib.Easing = {
3598
3599
3600     easeNone: function (t, b, c, d) {
3601         return  c * t / d + b;
3602     },
3603
3604
3605     easeIn: function (t, b, c, d) {
3606         return  c * (t /= d) * t + b;
3607     },
3608
3609
3610     easeOut: function (t, b, c, d) {
3611         return  -c * (t /= d) * (t - 2) + b;
3612     },
3613
3614
3615     easeBoth: function (t, b, c, d) {
3616         if ((t /= d / 2) < 1) {
3617             return  c / 2 * t * t + b;
3618         }
3619
3620         return  -c / 2 * ((--t) * (t - 2) - 1) + b;
3621     },
3622
3623
3624     easeInStrong: function (t, b, c, d) {
3625         return  c * (t /= d) * t * t * t + b;
3626     },
3627
3628
3629     easeOutStrong: function (t, b, c, d) {
3630         return  -c * ((t = t / d - 1) * t * t * t - 1) + b;
3631     },
3632
3633
3634     easeBothStrong: function (t, b, c, d) {
3635         if ((t /= d / 2) < 1) {
3636             return  c / 2 * t * t * t * t + b;
3637         }
3638
3639         return  -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3640     },
3641
3642
3643
3644     elasticIn: function (t, b, c, d, a, p) {
3645         if (t == 0) {
3646             return  b;
3647         }
3648         if ((t /= d) == 1) {
3649             return  b + c;
3650         }
3651         if (!p) {
3652             p = d * .3;
3653         }
3654
3655         if (!a || a < Math.abs(c)) {
3656             a = c;
3657             var  s = p / 4;
3658         }
3659         else  {
3660             var  s = p / (2 * Math.PI) * Math.asin(c / a);
3661         }
3662
3663         return  -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3664     },
3665
3666
3667     elasticOut: function (t, b, c, d, a, p) {
3668         if (t == 0) {
3669             return  b;
3670         }
3671         if ((t /= d) == 1) {
3672             return  b + c;
3673         }
3674         if (!p) {
3675             p = d * .3;
3676         }
3677
3678         if (!a || a < Math.abs(c)) {
3679             a = c;
3680             var  s = p / 4;
3681         }
3682         else  {
3683             var  s = p / (2 * Math.PI) * Math.asin(c / a);
3684         }
3685
3686         return  a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3687     },
3688
3689
3690     elasticBoth: function (t, b, c, d, a, p) {
3691         if (t == 0) {
3692             return  b;
3693         }
3694
3695         if ((t /= d / 2) == 2) {
3696             return  b + c;
3697         }
3698
3699         if (!p) {
3700             p = d * (.3 * 1.5);
3701         }
3702
3703         if (!a || a < Math.abs(c)) {
3704             a = c;
3705             var  s = p / 4;
3706         }
3707         else  {
3708             var  s = p / (2 * Math.PI) * Math.asin(c / a);
3709         }
3710
3711         if (t < 1) {
3712             return  -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3713                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3714         }
3715         return  a * Math.pow(2, -10 * (t -= 1)) *
3716                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3717     },
3718
3719
3720
3721     backIn: function (t, b, c, d, s) {
3722         if (typeof  s == 'undefined') {
3723             s = 1.70158;
3724         }
3725         return  c * (t /= d) * t * ((s + 1) * t - s) + b;
3726     },
3727
3728
3729     backOut: function (t, b, c, d, s) {
3730         if (typeof  s == 'undefined') {
3731             s = 1.70158;
3732         }
3733         return  c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3734     },
3735
3736
3737     backBoth: function (t, b, c, d, s) {
3738         if (typeof  s == 'undefined') {
3739             s = 1.70158;
3740         }
3741
3742         if ((t /= d / 2 ) < 1) {
3743             return  c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3744         }
3745         return  c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3746     },
3747
3748
3749     bounceIn: function (t, b, c, d) {
3750         return  c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3751     },
3752
3753
3754     bounceOut: function (t, b, c, d) {
3755         if ((t /= d) < (1 / 2.75)) {
3756             return  c * (7.5625 * t * t) + b;
3757         } else  if (t < (2 / 2.75)) {
3758             return  c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3759         } else  if (t < (2.5 / 2.75)) {
3760             return  c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3761         }
3762         return  c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3763     },
3764
3765
3766     bounceBoth: function (t, b, c, d) {
3767         if (t < d / 2) {
3768             return  Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3769         }
3770         return  Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3771     }
3772 };
3773 /*
3774  * Portions of this file are based on pieces of Yahoo User Interface Library
3775  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3776  * YUI licensed under the BSD License:
3777  * http://developer.yahoo.net/yui/license.txt
3778  * <script type="text/javascript">
3779  *
3780  */
3781     (function() {
3782         Roo.lib.Motion = function(el, E, F, G) {
3783             if (el) {
3784                 Roo.lib.Motion.superclass.constructor.call(this, el, E, F, G);
3785             }
3786         };
3787
3788         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3789
3790
3791         var  Y = Roo.lib;
3792         var  A = Y.Motion.superclass;
3793         var  B = Y.Motion.prototype;
3794
3795         B.toString = function() {
3796             var  el = this.getEl();
3797             var  id = el.id || el.tagName;
3798             return  ("Motion " + id);
3799         };
3800
3801         B.patterns.points = /^points$/i;
3802
3803         B.setAttribute = function(E, F, G) {
3804             if (this.patterns.points.test(E)) {
3805                 G = G || 'px';
3806                 A.setAttribute.call(this, 'left', F[0], G);
3807                 A.setAttribute.call(this, 'top', F[1], G);
3808             } else  {
3809                 A.setAttribute.call(this, E, F, G);
3810             }
3811         };
3812
3813         B.getAttribute = function(E) {
3814             if (this.patterns.points.test(E)) {
3815                 var  val = [
3816                         A.getAttribute.call(this, 'left'),
3817                         A.getAttribute.call(this, 'top')
3818                         ];
3819             } else  {
3820                 val = A.getAttribute.call(this, E);
3821             }
3822
3823             return  val;
3824         };
3825
3826         B.doMethod = function(E, F, G) {
3827             var  H = null;
3828
3829             if (this.patterns.points.test(E)) {
3830                 var  t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3831                 H = Y.Bezier.getPosition(this.runtimeAttributes[E], t);
3832             } else  {
3833                 H = A.doMethod.call(this, E, F, G);
3834             }
3835             return  H;
3836         };
3837
3838         B.setRuntimeAttribute = function(E) {
3839             if (this.patterns.points.test(E)) {
3840                 var  el = this.getEl();
3841                 var  attributes = this.attributes;
3842                 var  start;
3843                 var  control = attributes['points']['control'] || [];
3844                 var  end;
3845                 var  i, len;
3846
3847                 if (control.length > 0 && !(control[0]  instanceof  Array)) {
3848                     control = [control];
3849                 } else  {
3850                     var  tmp = [];
3851                     for (i = 0,len = control.length; i < len; ++i) {
3852                         tmp[i] = control[i];
3853                     }
3854
3855                     control = tmp;
3856                 }
3857
3858
3859                 Roo.fly(el).position();
3860
3861                 if (D(attributes['points']['from'])) {
3862                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3863                 }
3864                 else  {
3865                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3866                 }
3867
3868
3869                 start = this.getAttribute('points');
3870
3871
3872                 if (D(attributes['points']['to'])) {
3873                     end = C.call(this, attributes['points']['to'], start);
3874
3875                     var  pageXY = Roo.lib.Dom.getXY(this.getEl());
3876                     for (i = 0,len = control.length; i < len; ++i) {
3877                         control[i] = C.call(this, control[i], start);
3878                     }
3879
3880
3881                 } else  if (D(attributes['points']['by'])) {
3882                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3883
3884                     for (i = 0,len = control.length; i < len; ++i) {
3885                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3886                     }
3887                 }
3888
3889
3890                 this.runtimeAttributes[E] = [start];
3891
3892                 if (control.length > 0) {
3893                     this.runtimeAttributes[E] = this.runtimeAttributes[E].concat(control);
3894                 }
3895
3896
3897                 this.runtimeAttributes[E][this.runtimeAttributes[E].length] = end;
3898             }
3899             else  {
3900                 A.setRuntimeAttribute.call(this, E);
3901             }
3902         };
3903
3904         var  C = function(E, F) {
3905             var  G = Roo.lib.Dom.getXY(this.getEl());
3906             E = [ E[0] - G[0] + F[0], E[1] - G[1] + F[1] ];
3907
3908             return  E;
3909         };
3910
3911         var  D = function(E) {
3912             return  (typeof  E !== 'undefined');
3913         };
3914     })();
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.Scroll = function(el, C, D, E) {
3926             if (el) {
3927                 Roo.lib.Scroll.superclass.constructor.call(this, el, C, D, E);
3928             }
3929         };
3930
3931         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3932
3933
3934         var  Y = Roo.lib;
3935         var  A = Y.Scroll.superclass;
3936         var  B = Y.Scroll.prototype;
3937
3938         B.toString = function() {
3939             var  el = this.getEl();
3940             var  id = el.id || el.tagName;
3941             return  ("Scroll " + id);
3942         };
3943
3944         B.doMethod = function(C, D, E) {
3945             var  F = null;
3946
3947             if (C == 'scroll') {
3948                 F = [
3949                         this.method(this.currentFrame, D[0], E[0] - D[0], this.totalFrames),
3950                         this.method(this.currentFrame, D[1], E[1] - D[1], this.totalFrames)
3951                         ];
3952
3953             } else  {
3954                 F = A.doMethod.call(this, C, D, E);
3955             }
3956             return  F;
3957         };
3958
3959         B.getAttribute = function(C) {
3960             var  D = null;
3961             var  el = this.getEl();
3962
3963             if (C == 'scroll') {
3964                 D = [ el.scrollLeft, el.scrollTop ];
3965             } else  {
3966                 D = A.getAttribute.call(this, C);
3967             }
3968
3969             return  D;
3970         };
3971
3972         B.setAttribute = function(C, D, E) {
3973             var  el = this.getEl();
3974
3975             if (C == 'scroll') {
3976                 el.scrollLeft = D[0];
3977                 el.scrollTop = D[1];
3978             } else  {
3979                 A.setAttribute.call(this, C, D, E);
3980             }
3981         };
3982     })();
3983
3984 /*
3985  * Based on:
3986  * Ext JS Library 1.1.1
3987  * Copyright(c) 2006-2007, Ext JS, LLC.
3988  *
3989  * Originally Released Under LGPL - original licence link has changed is not relivant.
3990  *
3991  * Fork - LGPL
3992  * <script type="text/javascript">
3993  */
3994  
3995
3996 /**
3997  * @class Roo.DomHelper
3998  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3999  * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4000  * @singleton
4001  */
4002 Roo.DomHelper = function(){
4003     var  A = null;
4004     var  B = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4005     var  C = /^table|tbody|tr|td$/i;
4006     var  D = {};
4007     // build as innerHTML where available
4008     /** @ignore */
4009     var  E = function(o){
4010         if(typeof  o == 'string'){
4011             return  o;
4012         }
4013         var  b = "";
4014         if(!o.tag){
4015             o.tag = "div";
4016         }
4017
4018         b += "<" + o.tag;
4019         for(var  attr  in  o){
4020             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof  o[attr] == "function") continue;
4021             if(attr == "style"){
4022                 var  s = o["style"];
4023                 if(typeof  s == "function"){
4024                     s = s.call();
4025                 }
4026                 if(typeof  s == "string"){
4027                     b += ' style="' + s + '"';
4028                 }else  if(typeof  s == "object"){
4029                     b += ' style="';
4030                     for(var  key  in  s){
4031                         if(typeof  s[key] != "function"){
4032                             b += key + ":" + s[key] + ";";
4033                         }
4034                     }
4035
4036                     b += '"';
4037                 }
4038             }else {
4039                 if(attr == "cls"){
4040                     b += ' class="' + o["cls"] + '"';
4041                 }else  if(attr == "htmlFor"){
4042                     b += ' for="' + o["htmlFor"] + '"';
4043                 }else {
4044                     b += " " + attr + '="' + o[attr] + '"';
4045                 }
4046             }
4047         }
4048         if(B.test(o.tag)){
4049             b += "/>";
4050         }else {
4051             b += ">";
4052             var  cn = o.children || o.cn;
4053             if(cn){
4054                 //http://bugs.kde.org/show_bug.cgi?id=71506
4055                 if((cn  instanceof  Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4056                     for(var  i = 0, len = cn.length; i < len; i++) {
4057                         b += E(cn[i], b);
4058                     }
4059                 }else {
4060                     b += E(cn, b);
4061                 }
4062             }
4063             if(o.html){
4064                 b += o.html;
4065             }
4066
4067             b += "</" + o.tag + ">";
4068         }
4069         return  b;
4070     };
4071
4072     // build as dom
4073     /** @ignore */
4074     var  F = function(o, M){
4075          
4076         // defininition craeted..
4077         var  ns = false;
4078         if (o.ns && o.ns != 'html') {
4079                
4080             if (o.xmlns && typeof(D[o.ns]) == 'undefined') {
4081                 D[o.ns] = o.xmlns;
4082                 ns = o.xmlns;
4083             }
4084             if (typeof(D[o.ns]) == 'undefined') {
4085                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4086             }
4087
4088             ns = D[o.ns];
4089         }
4090         
4091         
4092         if (typeof(o) == 'string') {
4093             return  M.appendChild(document.createTextNode(o));
4094         }
4095
4096         o.tag = o.tag || div;
4097         if (o.ns && Roo.isIE) {
4098             ns = false;
4099             o.tag = o.ns + ':' + o.tag;
4100             
4101         }
4102         var  el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4103         var  N = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4104         for(var  attr  in  o){
4105             
4106             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4107                     attr == "style" || typeof  o[attr] == "function") continue;
4108                     
4109             if(attr=="cls" && Roo.isIE){
4110                 el.className = o["cls"];
4111             }else {
4112                 if(N) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4113                 else  el[attr] = o[attr];
4114             }
4115         }
4116
4117         Roo.DomHelper.applyStyles(el, o.style);
4118         var  cn = o.children || o.cn;
4119         if(cn){
4120             //http://bugs.kde.org/show_bug.cgi?id=71506
4121              if((cn  instanceof  Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4122                 for(var  i = 0, len = cn.length; i < len; i++) {
4123                     F(cn[i], el);
4124                 }
4125             }else {
4126                 F(cn, el);
4127             }
4128         }
4129         if(o.html){
4130             el.innerHTML = o.html;
4131         }
4132         if(M){
4133            M.appendChild(el);
4134         }
4135         return  el;
4136     };
4137
4138     var  G = function(M, s, h, e){
4139         A.innerHTML = [s, h, e].join('');
4140         var  i = -1, el = A;
4141         while(++i < M){
4142             el = el.firstChild;
4143         }
4144         return  el;
4145     };
4146
4147     // kill repeat to save bytes
4148     var  ts = '<table>',
4149         te = '</table>',
4150         H = ts+'<tbody>',
4151         I = '</tbody>'+te,
4152         J = H + '<tr>',
4153         K = '</tr>'+I;
4154
4155     /**
4156      * @ignore
4157      * Nasty code for IE's broken table implementation
4158      */
4159     var  L = function(M, N, el, O){
4160         if(!A){
4161             A = document.createElement('div');
4162         }
4163         var  P;
4164         var  Q = null;
4165         if(M == 'td'){
4166             if(N == 'afterbegin' || N == 'beforeend'){ // INTO a TD
4167                 return;
4168             }
4169             if(N == 'beforebegin'){
4170                 Q = el;
4171                 el = el.parentNode;
4172             } else {
4173                 Q = el.nextSibling;
4174                 el = el.parentNode;
4175             }
4176
4177             P = G(4, J, O, K);
4178         }
4179         else  if(M == 'tr'){
4180             if(N == 'beforebegin'){
4181                 Q = el;
4182                 el = el.parentNode;
4183                 P = G(3, H, O, I);
4184             } else  if(N == 'afterend'){
4185                 Q = el.nextSibling;
4186                 el = el.parentNode;
4187                 P = G(3, H, O, I);
4188             } else { // INTO a TR
4189                 if(N == 'afterbegin'){
4190                     Q = el.firstChild;
4191                 }
4192
4193                 P = G(4, J, O, K);
4194             }
4195         } else  if(M == 'tbody'){
4196             if(N == 'beforebegin'){
4197                 Q = el;
4198                 el = el.parentNode;
4199                 P = G(2, ts, O, te);
4200             } else  if(N == 'afterend'){
4201                 Q = el.nextSibling;
4202                 el = el.parentNode;
4203                 P = G(2, ts, O, te);
4204             } else {
4205                 if(N == 'afterbegin'){
4206                     Q = el.firstChild;
4207                 }
4208
4209                 P = G(3, H, O, I);
4210             }
4211         } else { // TABLE
4212             if(N == 'beforebegin' || N == 'afterend'){ // OUTSIDE the table
4213                 return;
4214             }
4215             if(N == 'afterbegin'){
4216                 Q = el.firstChild;
4217             }
4218
4219             P = G(2, ts, O, te);
4220         }
4221
4222         el.insertBefore(P, Q);
4223         return  P;
4224     };
4225
4226     return  {
4227     /** True to force the use of DOM instead of html fragments @type Boolean */
4228     useDom : false,
4229
4230     /**
4231      * Returns the markup for the passed Element(s) config
4232      * @param {Object} o The Dom object spec (and children)
4233      * @return {String}
4234      */
4235     markup : function(o){
4236         return  E(o);
4237     },
4238
4239     /**
4240      * Applies a style specification to an element
4241      * @param {String/HTMLElement} el The element to apply styles to
4242      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4243      * a function which returns such a specification.
4244      */
4245     applyStyles : function(el, c){
4246         if(c){
4247            el = Roo.fly(el);
4248            if(typeof  c == "string"){
4249                var  re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4250                var  matches;
4251                while ((matches = re.exec(c)) != null){
4252                    el.setStyle(matches[1], matches[2]);
4253                }
4254            }else  if (typeof  c == "object"){
4255                for (var  style  in  c){
4256                   el.setStyle(style, c[style]);
4257                }
4258            }else  if (typeof  c == "function"){
4259                 Roo.DomHelper.applyStyles(el, c.call());
4260            }
4261         }
4262     },
4263
4264     /**
4265      * Inserts an HTML fragment into the Dom
4266      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4267      * @param {HTMLElement} el The context element
4268      * @param {String} html The HTML fragmenet
4269      * @return {HTMLElement} The new node
4270      */
4271     insertHtml : function(d, el, e){
4272         d = d.toLowerCase();
4273         if(el.insertAdjacentHTML){
4274             if(C.test(el.tagName)){
4275                 var  rs;
4276                 if(rs = L(el.tagName.toLowerCase(), d, el, e)){
4277                     return  rs;
4278                 }
4279             }
4280             switch(d){
4281                 case  "beforebegin":
4282                     el.insertAdjacentHTML('BeforeBegin', e);
4283                     return  el.previousSibling;
4284                 case  "afterbegin":
4285                     el.insertAdjacentHTML('AfterBegin', e);
4286                     return  el.firstChild;
4287                 case  "beforeend":
4288                     el.insertAdjacentHTML('BeforeEnd', e);
4289                     return  el.lastChild;
4290                 case  "afterend":
4291                     el.insertAdjacentHTML('AfterEnd', e);
4292                     return  el.nextSibling;
4293             }
4294             throw  'Illegal insertion point -> "' + d + '"';
4295         }
4296         var  f = el.ownerDocument.createRange();
4297         var  g;
4298         switch(d){
4299              case  "beforebegin":
4300                 f.setStartBefore(el);
4301                 g = f.createContextualFragment(e);
4302                 el.parentNode.insertBefore(g, el);
4303                 return  el.previousSibling;
4304              case  "afterbegin":
4305                 if(el.firstChild){
4306                     f.setStartBefore(el.firstChild);
4307                     g = f.createContextualFragment(e);
4308                     el.insertBefore(g, el.firstChild);
4309                     return  el.firstChild;
4310                 }else {
4311                     el.innerHTML = e;
4312                     return  el.firstChild;
4313                 }
4314             case  "beforeend":
4315                 if(el.lastChild){
4316                     f.setStartAfter(el.lastChild);
4317                     g = f.createContextualFragment(e);
4318                     el.appendChild(g);
4319                     return  el.lastChild;
4320                 }else {
4321                     el.innerHTML = e;
4322                     return  el.lastChild;
4323                 }
4324             case  "afterend":
4325                 f.setStartAfter(el);
4326                 g = f.createContextualFragment(e);
4327                 el.parentNode.insertBefore(g, el.nextSibling);
4328                 return  el.nextSibling;
4329             }
4330             throw  'Illegal insertion point -> "' + d + '"';
4331     },
4332
4333     /**
4334      * Creates new Dom element(s) and inserts them before el
4335      * @param {String/HTMLElement/Element} el The context element
4336      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4337      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4338      * @return {HTMLElement/Roo.Element} The new node
4339      */
4340     insertBefore : function(el, o, h){
4341         return  this.doInsert(el, o, h, "beforeBegin");
4342     },
4343
4344     /**
4345      * Creates new Dom element(s) and inserts them after el
4346      * @param {String/HTMLElement/Element} el The context element
4347      * @param {Object} o The Dom object spec (and children)
4348      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4349      * @return {HTMLElement/Roo.Element} The new node
4350      */
4351     insertAfter : function(el, o, j){
4352         return  this.doInsert(el, o, j, "afterEnd", "nextSibling");
4353     },
4354
4355     /**
4356      * Creates new Dom element(s) and inserts them as the first child of el
4357      * @param {String/HTMLElement/Element} el The context element
4358      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4359      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4360      * @return {HTMLElement/Roo.Element} The new node
4361      */
4362     insertFirst : function(el, o, k){
4363         return  this.doInsert(el, o, k, "afterBegin");
4364     },
4365
4366     // private
4367     doInsert : function(el, o, l, m, n){
4368         el = Roo.getDom(el);
4369         var  p;
4370         if(this.useDom || o.ns){
4371             p = F(o, null);
4372             el.parentNode.insertBefore(p, n ? el[n] : el);
4373         }else {
4374             var  e = E(o);
4375             p = this.insertHtml(m, el, e);
4376         }
4377         return  l ? Roo.get(p, true) : p;
4378     },
4379
4380     /**
4381      * Creates new Dom element(s) and appends them to el
4382      * @param {String/HTMLElement/Element} el The context element
4383      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4384      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4385      * @return {HTMLElement/Roo.Element} The new node
4386      */
4387     append : function(el, o, q){
4388         el = Roo.getDom(el);
4389         var  r;
4390         if(this.useDom || o.ns){
4391             r = F(o, null);
4392             el.appendChild(r);
4393         }else {
4394             var  e = E(o);
4395             r = this.insertHtml("beforeEnd", el, e);
4396         }
4397         return  q ? Roo.get(r, true) : r;
4398     },
4399
4400     /**
4401      * Creates new Dom element(s) and overwrites the contents of el with them
4402      * @param {String/HTMLElement/Element} el The context element
4403      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4404      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4405      * @return {HTMLElement/Roo.Element} The new node
4406      */
4407     overwrite : function(el, o, t){
4408         el = Roo.getDom(el);
4409         if (o.ns) {
4410           
4411             while (el.childNodes.length) {
4412                 el.removeChild(el.firstChild);
4413             }
4414
4415             F(o, el);
4416         } else  {
4417             el.innerHTML = E(o);   
4418         }
4419         
4420         return  t ? Roo.get(el.firstChild, true) : el.firstChild;
4421     },
4422
4423     /**
4424      * Creates a new Roo.DomHelper.Template from the Dom object spec
4425      * @param {Object} o The Dom object spec (and children)
4426      * @return {Roo.DomHelper.Template} The new template
4427      */
4428     createTemplate : function(o){
4429         var  u = E(o);
4430         return  new  Roo.Template(u);
4431     }
4432     };
4433 }();
4434
4435 /*
4436  * Based on:
4437  * Ext JS Library 1.1.1
4438  * Copyright(c) 2006-2007, Ext JS, LLC.
4439  *
4440  * Originally Released Under LGPL - original licence link has changed is not relivant.
4441  *
4442  * Fork - LGPL
4443  * <script type="text/javascript">
4444  */
4445  
4446 /**
4447 * @class Roo.Template
4448 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4449 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4450 * Usage:
4451 <pre><code>
4452 var t = new Roo.Template(
4453     '&lt;div name="{id}"&gt;',
4454         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
4455     '&lt;/div&gt;'
4456 );
4457 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4458 </code></pre>
4459 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
4460 * @constructor
4461 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4462 */
4463 Roo.Template = function(A){
4464     if(A  instanceof  Array){
4465         A = A.join("");
4466     }else  if(arguments.length > 1){
4467         A = Array.prototype.join.call(arguments, "");
4468     }
4469
4470     /**@private*/
4471     this.html = A;
4472     
4473 };
4474 Roo.Template.prototype = {
4475     /**
4476      * Returns an HTML fragment of this template with the specified values applied.
4477      * @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'})
4478      * @return {String} The HTML fragment
4479      */
4480     applyTemplate : function(B){
4481         if(this.compiled){
4482             return  this.compiled(B);
4483         }
4484         var  C = this.disableFormats !== true;
4485         var  fm = Roo.util.Format, D = this;
4486         var  fn = function(m, E, F, G){
4487             if(F && C){
4488                 if(F.substr(0, 5) == "this."){
4489                     return  D.call(F.substr(5), B[E], B);
4490                 }else {
4491                     if(G){
4492                         // quoted values are required for strings in compiled templates, 
4493                         // but for non compiled we need to strip them
4494                         // quoted reversed for jsmin
4495                         var  re = /^\s*['"](.*)["']\s*$/;
4496                         G = G.split(',');
4497                         for(var  i = 0, len = G.length; i < len; i++){
4498                             G[i] = G[i].replace(re, "$1");
4499                         }
4500
4501                         G = [B[E]].concat(G);
4502                     }else {
4503                         G = [B[E]];
4504                     }
4505                     return  fm[F].apply(fm, G);
4506                 }
4507             }else {
4508                 return  B[E] !== undefined ? B[E] : "";
4509             }
4510         };
4511         return  this.html.replace(this.re, fn);
4512     },
4513     
4514     /**
4515      * Sets the HTML used as the template and optionally compiles it.
4516      * @param {String} html
4517      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4518      * @return {Roo.Template} this
4519      */
4520     set : function(E, F){
4521         this.html = E;
4522         this.compiled = null;
4523         if(F){
4524             this.compile();
4525         }
4526         return  this;
4527     },
4528     
4529     /**
4530      * True to disable format functions (defaults to false)
4531      * @type Boolean
4532      */
4533     disableFormats : false,
4534     
4535     /**
4536     * The regular expression used to match template variables 
4537     * @type RegExp
4538     * @property 
4539     */
4540     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4541     
4542     /**
4543      * Compiles the template into an internal function, eliminating the RegEx overhead.
4544      * @return {Roo.Template} this
4545      */
4546     compile : function(){
4547         var  fm = Roo.util.Format;
4548         var  G = this.disableFormats !== true;
4549         var  H = Roo.isGecko ? "+" : ",";
4550         var  fn = function(m, J, K, L){
4551             if(K && G){
4552                 L = L ? ',' + L : "";
4553                 if(K.substr(0, 5) != "this."){
4554                     K = "fm." + K + '(';
4555                 }else {
4556                     K = 'this.call("'+ K.substr(5) + '", ';
4557                     L = ", values";
4558                 }
4559             }else {
4560                 L= ''; K = "(values['" + J + "'] == undefined ? '' : ";
4561             }
4562             return  "'"+ H + K + "values['" + J + "']" + L + ")"+H+"'";
4563         };
4564         var  I;
4565         // branched to use + in gecko and [].join() in others
4566         if(Roo.isGecko){
4567             I = "this.compiled = function(values){ return '" +
4568                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4569                     "';};";
4570         }else {
4571             I = ["this.compiled = function(values){ return ['"];
4572             I.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4573             I.push("'].join('');};");
4574             I = I.join('');
4575         }
4576
4577         /**
4578          * eval:var:values
4579          * eval:var:fm
4580          */
4581         eval(I);
4582         return  this;
4583     },
4584     
4585     // private function used to call members
4586     call : function(J, K, L){
4587         return  this[J](K, L);
4588     },
4589     
4590     /**
4591      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4592      * @param {String/HTMLElement/Roo.Element} el The context element
4593      * @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'})
4594      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4595      * @return {HTMLElement/Roo.Element} The new node or Element
4596      */
4597     insertFirst: function(el, M, N){
4598         return  this.doInsert('afterBegin', el, M, N);
4599     },
4600
4601     /**
4602      * Applies the supplied values to the template and inserts the new node(s) before el.
4603      * @param {String/HTMLElement/Roo.Element} el The context element
4604      * @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'})
4605      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4606      * @return {HTMLElement/Roo.Element} The new node or Element
4607      */
4608     insertBefore: function(el, O, P){
4609         return  this.doInsert('beforeBegin', el, O, P);
4610     },
4611
4612     /**
4613      * Applies the supplied values to the template and inserts the new node(s) after el.
4614      * @param {String/HTMLElement/Roo.Element} el The context element
4615      * @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'})
4616      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4617      * @return {HTMLElement/Roo.Element} The new node or Element
4618      */
4619     insertAfter : function(el, Q, R){
4620         return  this.doInsert('afterEnd', el, Q, R);
4621     },
4622     
4623     /**
4624      * Applies the supplied values to the template and appends the new node(s) to el.
4625      * @param {String/HTMLElement/Roo.Element} el The context element
4626      * @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'})
4627      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4628      * @return {HTMLElement/Roo.Element} The new node or Element
4629      */
4630     append : function(el, S, T){
4631         return  this.doInsert('beforeEnd', el, S, T);
4632     },
4633
4634     doInsert : function(U, el, V, W){
4635         el = Roo.getDom(el);
4636         var  X = Roo.DomHelper.insertHtml(U, el, this.applyTemplate(V));
4637         return  W ? Roo.get(X, true) : X;
4638     },
4639
4640     /**
4641      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4642      * @param {String/HTMLElement/Roo.Element} el The context element
4643      * @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'})
4644      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4645      * @return {HTMLElement/Roo.Element} The new node or Element
4646      */
4647     overwrite : function(el, Y, Z){
4648         el = Roo.getDom(el);
4649         el.innerHTML = this.applyTemplate(Y);
4650         return  Z ? Roo.get(el.firstChild, true) : el.firstChild;
4651     }
4652 };
4653 /**
4654  * Alias for {@link #applyTemplate}
4655  * @method
4656  */
4657 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4658
4659 // backwards compat
4660 Roo.DomHelper.Template = Roo.Template;
4661
4662 /**
4663  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4664  * @param {String/HTMLElement} el A DOM element or its id
4665  * @returns {Roo.Template} The created template
4666  * @static
4667  */
4668 Roo.Template.from = function(el){
4669     el = Roo.getDom(el);
4670     return  new  Roo.Template(el.value || el.innerHTML);
4671 };
4672 /*
4673  * Based on:
4674  * Ext JS Library 1.1.1
4675  * Copyright(c) 2006-2007, Ext JS, LLC.
4676  *
4677  * Originally Released Under LGPL - original licence link has changed is not relivant.
4678  *
4679  * Fork - LGPL
4680  * <script type="text/javascript">
4681  */
4682  
4683
4684 /*
4685  * This is code is also distributed under MIT license for use
4686  * with jQuery and prototype JavaScript libraries.
4687  */
4688 /**
4689  * @class Roo.DomQuery
4690 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).
4691 <p>
4692 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>
4693
4694 <p>
4695 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.
4696 </p>
4697 <h4>Element Selectors:</h4>
4698 <ul class="list">
4699     <li> <b>*</b> any element</li>
4700     <li> <b>E</b> an element with the tag E</li>
4701     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4702     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4703     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4704     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4705 </ul>
4706 <h4>Attribute Selectors:</h4>
4707 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4708 <ul class="list">
4709     <li> <b>E[foo]</b> has an attribute "foo"</li>
4710     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4711     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4712     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4713     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4714     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4715     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4716 </ul>
4717 <h4>Pseudo Classes:</h4>
4718 <ul class="list">
4719     <li> <b>E:first-child</b> E is the first child of its parent</li>
4720     <li> <b>E:last-child</b> E is the last child of its parent</li>
4721     <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>
4722     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4723     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4724     <li> <b>E:only-child</b> E is the only child of its parent</li>
4725     <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>
4726     <li> <b>E:first</b> the first E in the resultset</li>
4727     <li> <b>E:last</b> the last E in the resultset</li>
4728     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4729     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4730     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4731     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4732     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4733     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4734     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4735     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4736     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4737 </ul>
4738 <h4>CSS Value Selectors:</h4>
4739 <ul class="list">
4740     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4741     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4742     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4743     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4744     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4745     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4746 </ul>
4747  * @singleton
4748  */
4749 Roo.DomQuery = function(){
4750     var  A = {}, simpleCache = {}, valueCache = {};
4751     var  B = /\S/;
4752     var  C = /^\s+|\s+$/g;
4753     var  D = /\{(\d+)\}/g;
4754     var  E = /^(\s?[\/>+~]\s?|\s|$)/;
4755     var  F = /^(#)?([\w-\*]+)/;
4756     var  G = /(\d*)n\+?(\d*)/, H = /\D/;
4757
4758     function  I(p, f){
4759         var  i = 0;
4760         var  n = p.firstChild;
4761         while(n){
4762             if(n.nodeType == 1){
4763                if(++i == f){
4764                    return  n;
4765                }
4766             }
4767
4768             n = n.nextSibling;
4769         }
4770         return  null;
4771     };
4772
4773     function  J(n){
4774         while((n = n.nextSibling) && n.nodeType != 1);
4775         return  n;
4776     };
4777
4778     function  K(n){
4779         while((n = n.previousSibling) && n.nodeType != 1);
4780         return  n;
4781     };
4782
4783     function  L(d){
4784         var  n = d.firstChild, ni = -1;
4785             while(n){
4786                 var  nx = n.nextSibling;
4787                 if(n.nodeType == 3 && !B.test(n.nodeValue)){
4788                     d.removeChild(n);
4789                 }else {
4790                     n.nodeIndex = ++ni;
4791                 }
4792
4793                 n = nx;
4794             }
4795             return  this;
4796         };
4797
4798     function  M(c, a, v){
4799         if(!v){
4800             return  c;
4801         }
4802         var  r = [], ri = -1, cn;
4803         for(var  i = 0, ci; ci = c[i]; i++){
4804             if((' '+ci.className+' ').indexOf(v) != -1){
4805                 r[++ri] = ci;
4806             }
4807         }
4808         return  r;
4809     };
4810
4811     function  N(n, f){
4812         if(!n.tagName && typeof  n.length != "undefined"){
4813             n = n[0];
4814         }
4815         if(!n){
4816             return  null;
4817         }
4818         if(f == "for"){
4819             return  n.htmlFor;
4820         }
4821         if(f == "class" || f == "className"){
4822             return  n.className;
4823         }
4824         return  n.getAttribute(f) || n[f];
4825
4826     };
4827
4828     function  O(ns, f, g){
4829         var  h = [], ri = -1, cs;
4830         if(!ns){
4831             return  h;
4832         }
4833
4834         g = g || "*";
4835         if(typeof  ns.getElementsByTagName != "undefined"){
4836             ns = [ns];
4837         }
4838         if(!f){
4839             for(var  i = 0, ni; ni = ns[i]; i++){
4840                 cs = ni.getElementsByTagName(g);
4841                 for(var  j = 0, ci; ci = cs[j]; j++){
4842                     h[++ri] = ci;
4843                 }
4844             }
4845         }else  if(f == "/" || f == ">"){
4846             var  utag = g.toUpperCase();
4847             for(var  i = 0, ni, cn; ni = ns[i]; i++){
4848                 cn = ni.children || ni.childNodes;
4849                 for(var  j = 0, cj; cj = cn[j]; j++){
4850                     if(cj.nodeName == utag || cj.nodeName == g  || g == '*'){
4851                         h[++ri] = cj;
4852                     }
4853                 }
4854             }
4855         }else  if(f == "+"){
4856             var  utag = g.toUpperCase();
4857             for(var  i = 0, n; n = ns[i]; i++){
4858                 while((n = n.nextSibling) && n.nodeType != 1);
4859                 if(n && (n.nodeName == utag || n.nodeName == g || g == '*')){
4860                     h[++ri] = n;
4861                 }
4862             }
4863         }else  if(f == "~"){
4864             for(var  i = 0, n; n = ns[i]; i++){
4865                 while((n = n.nextSibling) && (n.nodeType != 1 || (g == '*' || n.tagName.toLowerCase()!=g)));
4866                 if(n){
4867                     h[++ri] = n;
4868                 }
4869             }
4870         }
4871         return  h;
4872     };
4873
4874     function  P(a, b){
4875         if(b.slice){
4876             return  a.concat(b);
4877         }
4878         for(var  i = 0, l = b.length; i < l; i++){
4879             a[a.length] = b[i];
4880         }
4881         return  a;
4882     }
4883
4884     function  Q(cs, f){
4885         if(cs.tagName || cs == document){
4886             cs = [cs];
4887         }
4888         if(!f){
4889             return  cs;
4890         }
4891         var  r = [], ri = -1;
4892         f = f.toLowerCase();
4893         for(var  i = 0, ci; ci = cs[i]; i++){
4894             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==f){
4895                 r[++ri] = ci;
4896             }
4897         }
4898         return  r;
4899     };
4900
4901     function  R(cs, f, id){
4902         if(cs.tagName || cs == document){
4903             cs = [cs];
4904         }
4905         if(!id){
4906             return  cs;
4907         }
4908         var  r = [], ri = -1;
4909         for(var  i = 0,ci; ci = cs[i]; i++){
4910             if(ci && ci.id == id){
4911                 r[++ri] = ci;
4912                 return  r;
4913             }
4914         }
4915         return  r;
4916     };
4917
4918     function  S(cs, g, h, op, k){
4919         var  r = [], ri = -1, st = k=="{";
4920         var  f = Roo.DomQuery.operators[op];
4921         for(var  i = 0, ci; ci = cs[i]; i++){
4922             var  a;
4923             if(st){
4924                 a = Roo.DomQuery.getStyle(ci, g);
4925             }
4926             else  if(g == "class" || g == "className"){
4927                 a = ci.className;
4928             }else  if(g == "for"){
4929                 a = ci.htmlFor;
4930             }else  if(g == "href"){
4931                 a = ci.getAttribute("href", 2);
4932             }else {
4933                 a = ci.getAttribute(g);
4934             }
4935             if((f && f(a, h)) || (!f && a)){
4936                 r[++ri] = ci;
4937             }
4938         }
4939         return  r;
4940     };
4941
4942     function  T(cs, f, g){
4943         return  Roo.DomQuery.pseudos[f](cs, g);
4944     };
4945
4946     // This is for IE MSXML which does not support expandos.
4947     // IE runs the same speed using setAttribute, however FF slows way down
4948     // and Safari completely fails so they need to continue to use expandos.
4949     var  U = window.ActiveXObject ? true : false;
4950
4951     // this eval is stop the compressor from
4952     // renaming the variable to something shorter
4953     
4954     /** eval:var:batch */
4955     var  V = 30803; 
4956
4957     var  W = 30803;
4958
4959     function  X(cs){
4960         var  d = ++W;
4961         cs[0].setAttribute("_nodup", d);
4962         var  r = [cs[0]];
4963         for(var  i = 1, len = cs.length; i < len; i++){
4964             var  c = cs[i];
4965             if(!c.getAttribute("_nodup") != d){
4966                 c.setAttribute("_nodup", d);
4967                 r[r.length] = c;
4968             }
4969         }
4970         for(var  i = 0, len = cs.length; i < len; i++){
4971             cs[i].removeAttribute("_nodup");
4972         }
4973         return  r;
4974     }
4975
4976     function  Y(cs){
4977         if(!cs){
4978             return  [];
4979         }
4980         var  f = cs.length, c, i, r = cs, cj, ri = -1;
4981         if(!f || typeof  cs.nodeType != "undefined" || f == 1){
4982             return  cs;
4983         }
4984         if(U && typeof  cs[0].selectSingleNode != "undefined"){
4985             return  X(cs);
4986         }
4987         var  d = ++W;
4988         cs[0]._nodup = d;
4989         for(i = 1; c = cs[i]; i++){
4990             if(c._nodup != d){
4991                 c._nodup = d;
4992             }else {
4993                 r = [];
4994                 for(var  j = 0; j < i; j++){
4995                     r[++ri] = cs[j];
4996                 }
4997                 for(j = i+1; cj = cs[j]; j++){
4998                     if(cj._nodup != d){
4999                         cj._nodup = d;
5000                         r[++ri] = cj;
5001                     }
5002                 }
5003                 return  r;
5004             }
5005         }
5006         return  r;
5007     }
5008
5009     function  Z(c1, c2){
5010         var  d = ++W;
5011         for(var  i = 0, len = c1.length; i < len; i++){
5012             c1[i].setAttribute("_qdiff", d);
5013         }
5014         var  r = [];
5015         for(var  i = 0, len = c2.length; i < len; i++){
5016             if(c2[i].getAttribute("_qdiff") != d){
5017                 r[r.length] = c2[i];
5018             }
5019         }
5020         for(var  i = 0, len = c1.length; i < len; i++){
5021            c1[i].removeAttribute("_qdiff");
5022         }
5023         return  r;
5024     }
5025
5026     function  b(c1, c2){
5027         var  f = c1.length;
5028         if(!f){
5029             return  c2;
5030         }
5031         if(U && c1[0].selectSingleNode){
5032             return  Z(c1, c2);
5033         }
5034         var  d = ++W;
5035         for(var  i = 0; i < f; i++){
5036             c1[i]._qdiff = d;
5037         }
5038         var  r = [];
5039         for(var  i = 0, len = c2.length; i < len; i++){
5040             if(c2[i]._qdiff != d){
5041                 r[r.length] = c2[i];
5042             }
5043         }
5044         return  r;
5045     }
5046
5047     function  e(ns, f, g, id){
5048         if(ns == g){
5049            var  d = g.ownerDocument || g;
5050            return  d.getElementById(id);
5051         }
5052
5053         ns = O(ns, f, "*");
5054         return  R(ns, null, id);
5055     }
5056
5057     return  {
5058         getStyle : function(el, AK){
5059             return  Roo.fly(el).getStyle(AK);
5060         },
5061         /**
5062          * Compiles a selector/xpath query into a reusable function. The returned function
5063          * takes one parameter "root" (optional), which is the context node from where the query should start.
5064          * @param {String} selector The selector/xpath query
5065          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5066          * @return {Function}
5067          */
5068         compile : function(AL, AM){
5069             AM = AM || "select";
5070             
5071             var  fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5072             var  q = AL, AN, lq;
5073             var  tk = Roo.DomQuery.matchers;
5074             var  AO = tk.length;
5075             var  mm;
5076
5077             // accept leading mode switch
5078             var  AP = q.match(E);
5079             if(AP && AP[1]){
5080                 fn[fn.length] = 'mode="'+AP[1].replace(C, "")+'";';
5081                 q = q.replace(AP[1], "");
5082             }
5083             // strip leading slashes
5084             while(AL.substr(0, 1)=="/"){
5085                 AL = AL.substr(1);
5086             }
5087
5088             while(q && lq != q){
5089                 lq = q;
5090                 var  tm = q.match(F);
5091                 if(AM == "select"){
5092                     if(tm){
5093                         if(tm[1] == "#"){
5094                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5095                         }else {
5096                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5097                         }
5098
5099                         q = q.replace(tm[0], "");
5100                     }else  if(q.substr(0, 1) != '@'){
5101                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5102                     }
5103                 }else {
5104                     if(tm){
5105                         if(tm[1] == "#"){
5106                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5107                         }else {
5108                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5109                         }
5110
5111                         q = q.replace(tm[0], "");
5112                     }
5113                 }
5114                 while(!(mm = q.match(E))){
5115                     var  matched = false;
5116                     for(var  j = 0; j < AO; j++){
5117                         var  t = tk[j];
5118                         var  m = q.match(t.re);
5119                         if(m){
5120                             fn[fn.length] = t.select.replace(D, function(x, i){
5121                                                     return  m[i];
5122                                                 });
5123                             q = q.replace(m[0], "");
5124                             matched = true;
5125                             break;
5126                         }
5127                     }
5128                     // prevent infinite loop on bad selector
5129                     if(!matched){
5130                         throw  'Error parsing selector, parsing failed at "' + q + '"';
5131                     }
5132                 }
5133                 if(mm[1]){
5134                     fn[fn.length] = 'mode="'+mm[1].replace(C, "")+'";';
5135                     q = q.replace(mm[1], "");
5136                 }
5137             }
5138
5139             fn[fn.length] = "return nodup(n);\n}";
5140             
5141              /** 
5142               * list of variables that need from compression as they are used by eval.
5143              *  eval:var:batch 
5144              *  eval:var:nodup
5145              *  eval:var:byTag
5146              *  eval:var:ById
5147              *  eval:var:getNodes
5148              *  eval:var:quickId
5149              *  eval:var:mode
5150              *  eval:var:root
5151              *  eval:var:n
5152              *  eval:var:byClassName
5153              *  eval:var:byPseudo
5154              *  eval:var:byAttribute
5155              *  eval:var:attrValue
5156              * 
5157              **/ 
5158             eval(fn.join(""));
5159             return  f;
5160         },
5161
5162         /**
5163          * Selects a group of elements.
5164          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5165          * @param {Node} root (optional) The start of the query (defaults to document).
5166          * @return {Array}
5167          */
5168         select : function(AQ, AR, AS){
5169             if(!AR || AR == document){
5170                 AR = document;
5171             }
5172             if(typeof  AR == "string"){
5173                 AR = document.getElementById(AR);
5174             }
5175             var  AT = AQ.split(",");
5176             var  AU = [];
5177             for(var  i = 0, len = AT.length; i < len; i++){
5178                 var  p = AT[i].replace(C, "");
5179                 if(!A[p]){
5180                     A[p] = Roo.DomQuery.compile(p);
5181                     if(!A[p]){
5182                         throw  p + " is not a valid selector";
5183                     }
5184                 }
5185                 var  AJ = A[p](AR);
5186                 if(AJ && AJ != document){
5187                     AU = AU.concat(AJ);
5188                 }
5189             }
5190             if(AT.length > 1){
5191                 return  Y(AU);
5192             }
5193             return  AU;
5194         },
5195
5196         /**
5197          * Selects a single element.
5198          * @param {String} selector The selector/xpath query
5199          * @param {Node} root (optional) The start of the query (defaults to document).
5200          * @return {Element}
5201          */
5202         selectNode : function(AV, AW){
5203             return  Roo.DomQuery.select(AV, AW)[0];
5204         },
5205
5206         /**
5207          * Selects the value of a node, optionally replacing null with the defaultValue.
5208          * @param {String} selector The selector/xpath query
5209          * @param {Node} root (optional) The start of the query (defaults to document).
5210          * @param {String} defaultValue
5211          */
5212         selectValue : function(AX, AY, AZ){
5213             AX = AX.replace(C, "");
5214             if(!valueCache[AX]){
5215                 valueCache[AX] = Roo.DomQuery.compile(AX, "select");
5216             }
5217             var  n = valueCache[AX](AY);
5218             n = n[0] ? n[0] : n;
5219             var  v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5220             return  ((v === null||v === undefined||v==='') ? AZ : v);
5221         },
5222
5223         /**
5224          * Selects the value of a node, parsing integers and floats.
5225          * @param {String} selector The selector/xpath query
5226          * @param {Node} root (optional) The start of the query (defaults to document).
5227          * @param {Number} defaultValue
5228          * @return {Number}
5229          */
5230         selectNumber : function(Aa, Ab, Ac){
5231             var  v = Roo.DomQuery.selectValue(Aa, Ab, Ac || 0);
5232             return  parseFloat(v);
5233         },
5234
5235         /**
5236          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5237          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5238          * @param {String} selector The simple selector to test
5239          * @return {Boolean}
5240          */
5241         is : function(el, ss){
5242             if(typeof  el == "string"){
5243                 el = document.getElementById(el);
5244             }
5245             var  Ad = (el  instanceof  Array);
5246             var  Ae = Roo.DomQuery.filter(Ad ? el : [el], ss);
5247             return  Ad ? (Ae.length == el.length) : (Ae.length > 0);
5248         },
5249
5250         /**
5251          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5252          * @param {Array} el An array of elements to filter
5253          * @param {String} selector The simple selector to test
5254          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5255          * the selector instead of the ones that match
5256          * @return {Array}
5257          */
5258         filter : function(Af, ss, Ag){
5259             ss = ss.replace(C, "");
5260             if(!simpleCache[ss]){
5261                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5262             }
5263             var  Ah = simpleCache[ss](Af);
5264             return  Ag ? b(Ah, Af) : Ah;
5265         },
5266
5267         /**
5268          * Collection of matching regular expressions and code snippets.
5269          */
5270         matchers : [{
5271                 re: /^\.([\w-]+)/,
5272                 select: 'n = byClassName(n, null, " {1} ");'
5273             }, {
5274                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5275                 select: 'n = byPseudo(n, "{1}", "{2}");'
5276             },{
5277                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5278                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5279             }, {
5280                 re: /^#([\w-]+)/,
5281                 select: 'n = byId(n, null, "{1}");'
5282             },{
5283                 re: /^@([\w-]+)/,
5284                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5285             }
5286         ],
5287
5288         /**
5289          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5290          * 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;.
5291          */
5292         operators : {
5293             "=" : function(a, v){
5294                 return  a == v;
5295             },
5296             "!=" : function(a, v){
5297                 return  a != v;
5298             },
5299             "^=" : function(a, v){
5300                 return  a && a.substr(0, v.length) == v;
5301             },
5302             "$=" : function(a, v){
5303                 return  a && a.substr(a.length-v.length) == v;
5304             },
5305             "*=" : function(a, v){
5306                 return  a && a.indexOf(v) !== -1;
5307             },
5308             "%=" : function(a, v){
5309                 return  (a % v) == 0;
5310             },
5311             "|=" : function(a, v){
5312                 return  a && (a == v || a.substr(0, v.length+1) == v+'-');
5313             },
5314             "~=" : function(a, v){
5315                 return  a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5316             }
5317         },
5318
5319         /**
5320          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5321          * and the argument (if any) supplied in the selector.
5322          */
5323         pseudos : {
5324             "first-child" : function(c){
5325                 var  r = [], ri = -1, n;
5326                 for(var  i = 0, ci; ci = n = c[i]; i++){
5327                     while((n = n.previousSibling) && n.nodeType != 1);
5328                     if(!n){
5329                         r[++ri] = ci;
5330                     }
5331                 }
5332                 return  r;
5333             },
5334
5335             "last-child" : function(c){
5336                 var  r = [], ri = -1, n;
5337                 for(var  i = 0, ci; ci = n = c[i]; i++){
5338                     while((n = n.nextSibling) && n.nodeType != 1);
5339                     if(!n){
5340                         r[++ri] = ci;
5341                     }
5342                 }
5343                 return  r;
5344             },
5345
5346             "nth-child" : function(c, a) {
5347                 var  r = [], ri = -1;
5348                 var  m = G.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !H.test(a) && "n+" + a || a);
5349                 var  f = (m[1] || 1) - 0, l = m[2] - 0;
5350                 for(var  i = 0, n; n = c[i]; i++){
5351                     var  pn = n.parentNode;
5352                     if (V != pn._batch) {
5353                         var  j = 0;
5354                         for(var  cn = pn.firstChild; cn; cn = cn.nextSibling){
5355                             if(cn.nodeType == 1){
5356                                cn.nodeIndex = ++j;
5357                             }
5358                         }
5359
5360                         pn._batch = V;
5361                     }
5362                     if (f == 1) {
5363                         if (l == 0 || n.nodeIndex == l){
5364                             r[++ri] = n;
5365                         }
5366                     } else  if ((n.nodeIndex + l) % f == 0){
5367                         r[++ri] = n;
5368                     }
5369                 }
5370
5371                 return  r;
5372             },
5373
5374             "only-child" : function(c){
5375                 var  r = [], ri = -1;;
5376                 for(var  i = 0, ci; ci = c[i]; i++){
5377                     if(!K(ci) && !J(ci)){
5378                         r[++ri] = ci;
5379                     }
5380                 }
5381                 return  r;
5382             },
5383
5384             "empty" : function(c){
5385                 var  r = [], ri = -1;
5386                 for(var  i = 0, ci; ci = c[i]; i++){
5387                     var  cns = ci.childNodes, j = 0, cn, empty = true;
5388                     while(cn = cns[j]){
5389                         ++j;
5390                         if(cn.nodeType == 1 || cn.nodeType == 3){
5391                             empty = false;
5392                             break;
5393                         }
5394                     }
5395                     if(empty){
5396                         r[++ri] = ci;
5397                     }
5398                 }
5399                 return  r;
5400             },
5401
5402             "contains" : function(c, v){
5403                 var  r = [], ri = -1;
5404                 for(var  i = 0, ci; ci = c[i]; i++){
5405                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5406                         r[++ri] = ci;
5407                     }
5408                 }
5409                 return  r;
5410             },
5411
5412             "nodeValue" : function(c, v){
5413                 var  r = [], ri = -1;
5414                 for(var  i = 0, ci; ci = c[i]; i++){
5415                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5416                         r[++ri] = ci;
5417                     }
5418                 }
5419                 return  r;
5420             },
5421
5422             "checked" : function(c){
5423                 var  r = [], ri = -1;
5424                 for(var  i = 0, ci; ci = c[i]; i++){
5425                     if(ci.checked == true){
5426                         r[++ri] = ci;
5427                     }
5428                 }
5429                 return  r;
5430             },
5431
5432             "not" : function(c, ss){
5433                 return  Roo.DomQuery.filter(c, ss, true);
5434             },
5435
5436             "odd" : function(c){
5437                 return  this["nth-child"](c, "odd");
5438             },
5439
5440             "even" : function(c){
5441                 return  this["nth-child"](c, "even");
5442             },
5443
5444             "nth" : function(c, a){
5445                 return  c[a-1] || [];
5446             },
5447
5448             "first" : function(c){
5449                 return  c[0] || [];
5450             },
5451
5452             "last" : function(c){
5453                 return  c[c.length-1] || [];
5454             },
5455
5456             "has" : function(c, ss){
5457                 var  s = Roo.DomQuery.select;
5458                 var  r = [], ri = -1;
5459                 for(var  i = 0, ci; ci = c[i]; i++){
5460                     if(s(ss, ci).length > 0){
5461                         r[++ri] = ci;
5462                     }
5463                 }
5464                 return  r;
5465             },
5466
5467             "next" : function(c, ss){
5468                 var  is = Roo.DomQuery.is;
5469                 var  r = [], ri = -1;
5470                 for(var  i = 0, ci; ci = c[i]; i++){
5471                     var  n = J(ci);
5472                     if(n && is(n, ss)){
5473                         r[++ri] = ci;
5474                     }
5475                 }
5476                 return  r;
5477             },
5478
5479             "prev" : function(c, ss){
5480                 var  is = Roo.DomQuery.is;
5481                 var  r = [], ri = -1;
5482                 for(var  i = 0, ci; ci = c[i]; i++){
5483                     var  n = K(ci);
5484                     if(n && is(n, ss)){
5485                         r[++ri] = ci;
5486                     }
5487                 }
5488                 return  r;
5489             }
5490         }
5491     };
5492 }();
5493
5494 /**
5495  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5496  * @param {String} path The selector/xpath query
5497  * @param {Node} root (optional) The start of the query (defaults to document).
5498  * @return {Array}
5499  * @member Roo
5500  * @method query
5501  */
5502 Roo.query = Roo.DomQuery.select;
5503
5504 /*
5505  * Based on:
5506  * Ext JS Library 1.1.1
5507  * Copyright(c) 2006-2007, Ext JS, LLC.
5508  *
5509  * Originally Released Under LGPL - original licence link has changed is not relivant.
5510  *
5511  * Fork - LGPL
5512  * <script type="text/javascript">
5513  */
5514
5515 /**
5516  * @class Roo.util.Observable
5517  * Base class that provides a common interface for publishing events. Subclasses are expected to
5518  * to have a property "events" with all the events defined.<br>
5519  * For example:
5520  * <pre><code>
5521  Employee = function(name){
5522     this.name = name;
5523     this.addEvents({
5524         "fired" : true,
5525         "quit" : true
5526     });
5527  }
5528  Roo.extend(Employee, Roo.util.Observable);
5529 </code></pre>
5530  * @param {Object} config properties to use (incuding events / listeners)
5531  */
5532
5533 Roo.util.Observable = function(A){
5534     
5535     A = A|| {};
5536     this.addEvents(A.events || {});
5537     if (A.events) {
5538         delete  A.events; // make sure
5539     }
5540
5541      
5542     Roo.apply(this, A);
5543     
5544     if(this.listeners){
5545         this.on(this.listeners);
5546         delete  this.listeners;
5547     }
5548 };
5549 Roo.util.Observable.prototype = {
5550     /** 
5551  * @cfg {Object} listeners  list of events and functions to call for this object, 
5552  * For example :
5553  * <pre><code>
5554     listeners :  { 
5555        'click' : function(e) {
5556            ..... 
5557         } ,
5558         .... 
5559     } 
5560   </code></pre>
5561  */
5562     
5563     
5564     /**
5565      * Fires the specified event with the passed parameters (minus the event name).
5566      * @param {String} eventName
5567      * @param {Object...} args Variable number of parameters are passed to handlers
5568      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5569      */
5570     fireEvent : function(){
5571         var  ce = this.events[arguments[0].toLowerCase()];
5572         if(typeof  ce == "object"){
5573             return  ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5574         }else {
5575             return  true;
5576         }
5577     },
5578
5579     // private
5580     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5581
5582     /**
5583      * Appends an event handler to this component
5584      * @param {String}   eventName The type of event to listen for
5585      * @param {Function} handler The method the event invokes
5586      * @param {Object}   scope (optional) The scope in which to execute the handler
5587      * function. The handler function's "this" context.
5588      * @param {Object}   options (optional) An object containing handler configuration
5589      * properties. This may contain any of the following properties:<ul>
5590      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5591      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5592      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5593      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5594      * by the specified number of milliseconds. If the event fires again within that time, the original
5595      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5596      * </ul><br>
5597      * <p>
5598      * <b>Combining Options</b><br>
5599      * Using the options argument, it is possible to combine different types of listeners:<br>
5600      * <br>
5601      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5602                 <pre><code>
5603                 el.on('click', this.onClick, this, {
5604                         single: true,
5605                 delay: 100,
5606                 forumId: 4
5607                 });
5608                 </code></pre>
5609      * <p>
5610      * <b>Attaching multiple handlers in 1 call</b><br>
5611      * The method also allows for a single argument to be passed which is a config object containing properties
5612      * which specify multiple handlers.
5613      * <pre><code>
5614                 el.on({
5615                         'click': {
5616                         fn: this.onClick,
5617                         scope: this,
5618                         delay: 100
5619                 }, 
5620                 'mouseover': {
5621                         fn: this.onMouseOver,
5622                         scope: this
5623                 },
5624                 'mouseout': {
5625                         fn: this.onMouseOut,
5626                         scope: this
5627                 }
5628                 });
5629                 </code></pre>
5630      * <p>
5631      * Or a shorthand syntax which passes the same scope object to all handlers:
5632         <pre><code>
5633                 el.on({
5634                         'click': this.onClick,
5635                 'mouseover': this.onMouseOver,
5636                 'mouseout': this.onMouseOut,
5637                 scope: this
5638                 });
5639                 </code></pre>
5640      */
5641     addListener : function(B, fn, C, o){
5642         if(typeof  B == "object"){
5643             o = B;
5644             for(var  e  in  o){
5645                 if(this.filterOptRe.test(e)){
5646                     continue;
5647                 }
5648                 if(typeof  o[e] == "function"){
5649                     // shared options
5650                     this.addListener(e, o[e], o.scope,  o);
5651                 }else {
5652                     // individual options
5653                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5654                 }
5655             }
5656             return;
5657         }
5658
5659         o = (!o || typeof  o == "boolean") ? {} : o;
5660         B = B.toLowerCase();
5661         var  ce = this.events[B] || true;
5662         if(typeof  ce == "boolean"){
5663             ce = new  Roo.util.Event(this, B);
5664             this.events[B] = ce;
5665         }
5666
5667         ce.addListener(fn, C, o);
5668     },
5669
5670     /**
5671      * Removes a listener
5672      * @param {String}   eventName     The type of event to listen for
5673      * @param {Function} handler        The handler to remove
5674      * @param {Object}   scope  (optional) The scope (this object) for the handler
5675      */
5676     removeListener : function(D, fn, E){
5677         var  ce = this.events[D.toLowerCase()];
5678         if(typeof  ce == "object"){
5679             ce.removeListener(fn, E);
5680         }
5681     },
5682
5683     /**
5684      * Removes all listeners for this object
5685      */
5686     purgeListeners : function(){
5687         for(var  evt  in  this.events){
5688             if(typeof  this.events[evt] == "object"){
5689                  this.events[evt].clearListeners();
5690             }
5691         }
5692     },
5693
5694     relayEvents : function(o, F){
5695         var  G = function(H){
5696             return  function(){
5697                 return  this.fireEvent.apply(this, Roo.combine(H, Array.prototype.slice.call(arguments, 0)));
5698             };
5699         };
5700         for(var  i = 0, len = F.length; i < len; i++){
5701             var  ename = F[i];
5702             if(!this.events[ename]){ this.events[ename] = true; };
5703             o.on(ename, G(ename), this);
5704         }
5705     },
5706
5707     /**
5708      * Used to define events on this Observable
5709      * @param {Object} object The object with the events defined
5710      */
5711     addEvents : function(o){
5712         if(!this.events){
5713             this.events = {};
5714         }
5715
5716         Roo.applyIf(this.events, o);
5717     },
5718
5719     /**
5720      * Checks to see if this object has any listeners for a specified event
5721      * @param {String} eventName The name of the event to check for
5722      * @return {Boolean} True if the event is being listened for, else false
5723      */
5724     hasListener : function(H){
5725         var  e = this.events[H];
5726         return  typeof  e == "object" && e.listeners.length > 0;
5727     }
5728 };
5729 /**
5730  * Appends an event handler to this element (shorthand for addListener)
5731  * @param {String}   eventName     The type of event to listen for
5732  * @param {Function} handler        The method the event invokes
5733  * @param {Object}   scope (optional) The scope in which to execute the handler
5734  * function. The handler function's "this" context.
5735  * @param {Object}   options  (optional)
5736  * @method
5737  */
5738 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5739 /**
5740  * Removes a listener (shorthand for removeListener)
5741  * @param {String}   eventName     The type of event to listen for
5742  * @param {Function} handler        The handler to remove
5743  * @param {Object}   scope  (optional) The scope (this object) for the handler
5744  * @method
5745  */
5746 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5747
5748 /**
5749  * Starts capture on the specified Observable. All events will be passed
5750  * to the supplied function with the event name + standard signature of the event
5751  * <b>before</b> the event is fired. If the supplied function returns false,
5752  * the event will not fire.
5753  * @param {Observable} o The Observable to capture
5754  * @param {Function} fn The function to call
5755  * @param {Object} scope (optional) The scope (this object) for the fn
5756  * @static
5757  */
5758 Roo.util.Observable.capture = function(o, fn, I){
5759     o.fireEvent = o.fireEvent.createInterceptor(fn, I);
5760 };
5761
5762 /**
5763  * Removes <b>all</b> added captures from the Observable.
5764  * @param {Observable} o The Observable to release
5765  * @static
5766  */
5767 Roo.util.Observable.releaseCapture = function(o){
5768     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5769 };
5770
5771 (function(){
5772
5773     var  J = function(h, o, M){
5774         var  N = new  Roo.util.DelayedTask();
5775         return  function(){
5776             N.delay(o.buffer, h, M, Array.prototype.slice.call(arguments, 0));
5777         };
5778     };
5779
5780     var  K = function(h, e, fn, M){
5781         return  function(){
5782             e.removeListener(fn, M);
5783             return  h.apply(M, arguments);
5784         };
5785     };
5786
5787     var  L = function(h, o, M){
5788         return  function(){
5789             var  N = Array.prototype.slice.call(arguments, 0);
5790             setTimeout(function(){
5791                 h.apply(M, N);
5792             }, o.delay || 10);
5793         };
5794     };
5795
5796     Roo.util.Event = function(M, N){
5797         this.name = N;
5798         this.obj = M;
5799         this.listeners = [];
5800     };
5801
5802     Roo.util.Event.prototype = {
5803         addListener : function(fn, M, N){
5804             var  o = N || {};
5805             M = M || this.obj;
5806             if(!this.isListening(fn, M)){
5807                 var  l = {fn: fn, scope: M, options: o};
5808                 var  h = fn;
5809                 if(o.delay){
5810                     h = L(h, o, M);
5811                 }
5812                 if(o.single){
5813                     h = K(h, this, fn, M);
5814                 }
5815                 if(o.buffer){
5816                     h = J(h, o, M);
5817                 }
5818
5819                 l.fireFn = h;
5820                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5821                     this.listeners.push(l);
5822                 }else {
5823                     this.listeners = this.listeners.slice(0);
5824                     this.listeners.push(l);
5825                 }
5826             }
5827         },
5828
5829         findListener : function(fn, O){
5830             O = O || this.obj;
5831             var  ls = this.listeners;
5832             for(var  i = 0, len = ls.length; i < len; i++){
5833                 var  l = ls[i];
5834                 if(l.fn == fn && l.scope == O){
5835                     return  i;
5836                 }
5837             }
5838             return  -1;
5839         },
5840
5841         isListening : function(fn, P){
5842             return  this.findListener(fn, P) != -1;
5843         },
5844
5845         removeListener : function(fn, Q){
5846             var  R;
5847             if((R = this.findListener(fn, Q)) != -1){
5848                 if(!this.firing){
5849                     this.listeners.splice(R, 1);
5850                 }else {
5851                     this.listeners = this.listeners.slice(0);
5852                     this.listeners.splice(R, 1);
5853                 }
5854                 return  true;
5855             }
5856             return  false;
5857         },
5858
5859         clearListeners : function(){
5860             this.listeners = [];
5861         },
5862
5863         fire : function(){
5864             var  ls = this.listeners, S, T = ls.length;
5865             if(T > 0){
5866                 this.firing = true;
5867                 var  args = Array.prototype.slice.call(arguments, 0);
5868                 for(var  i = 0; i < T; i++){
5869                     var  l = ls[i];
5870                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5871                         this.firing = false;
5872                         return  false;
5873                     }
5874                 }
5875
5876                 this.firing = false;
5877             }
5878             return  true;
5879         }
5880     };
5881 })();
5882 /*
5883  * Based on:
5884  * Ext JS Library 1.1.1
5885  * Copyright(c) 2006-2007, Ext JS, LLC.
5886  *
5887  * Originally Released Under LGPL - original licence link has changed is not relivant.
5888  *
5889  * Fork - LGPL
5890  * <script type="text/javascript">
5891  */
5892
5893 /**
5894  * @class Roo.EventManager
5895  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
5896  * several useful events directly.
5897  * See {@link Roo.EventObject} for more details on normalized event objects.
5898  * @singleton
5899  */
5900 Roo.EventManager = function(){
5901     var  A, B, C = false;
5902     var  F, G, H, I;
5903     var  E = Roo.lib.Event;
5904     var  D = Roo.lib.Dom;
5905
5906
5907     var  J = function(){
5908         if(!C){
5909             C = true;
5910             Roo.isReady = true;
5911             if(B){
5912                 clearInterval(B);
5913             }
5914             if(Roo.isGecko || Roo.isOpera) {
5915                 document.removeEventListener("DOMContentLoaded", J, false);
5916             }
5917             if(Roo.isIE){
5918                 var  defer = document.getElementById("ie-deferred-loader");
5919                 if(defer){
5920                     defer.onreadystatechange = null;
5921                     defer.parentNode.removeChild(defer);
5922                 }
5923             }
5924             if(A){
5925                 A.fire();
5926                 A.clearListeners();
5927             }
5928         }
5929     };
5930     
5931     var  K = function(){
5932         A = new  Roo.util.Event();
5933         if(Roo.isGecko || Roo.isOpera) {
5934             document.addEventListener("DOMContentLoaded", J, false);
5935         }else  if(Roo.isIE){
5936             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5937             var  defer = document.getElementById("ie-deferred-loader");
5938             defer.onreadystatechange = function(){
5939                 if(this.readyState == "complete"){
5940                     J();
5941                 }
5942             };
5943         }else  if(Roo.isSafari){ 
5944             B = setInterval(function(){
5945                 var  rs = document.readyState;
5946                 if(rs == "complete") {
5947                     J();     
5948                  }
5949             }, 10);
5950         }
5951
5952         // no matter what, make sure it fires on load
5953         E.on(window, "load", J);
5954     };
5955
5956     var  L = function(h, o){
5957         var  S = new  Roo.util.DelayedTask(h);
5958         return  function(e){
5959             // create new event object impl so new events don't wipe out properties
5960             e = new  Roo.EventObjectImpl(e);
5961             S.delay(o.buffer, h, null, [e]);
5962         };
5963     };
5964
5965     var  M = function(h, el, S, fn){
5966         return  function(e){
5967             Roo.EventManager.removeListener(el, S, fn);
5968             h(e);
5969         };
5970     };
5971
5972     var  N = function(h, o){
5973         return  function(e){
5974             // create new event object impl so new events don't wipe out properties
5975             e = new  Roo.EventObjectImpl(e);
5976             setTimeout(function(){
5977                 h(e);
5978             }, o.delay || 10);
5979         };
5980     };
5981
5982     var  O = function(S, T, U, fn, V){
5983         var  o = (!U || typeof  U == "boolean") ? {} : U;
5984         fn = fn || o.fn; V = V || o.scope;
5985         var  el = Roo.getDom(S);
5986         if(!el){
5987             throw  "Error listening for \"" + T + '\". Element "' + S + '" doesn\'t exist.';
5988         }
5989         var  h = function(e){
5990             e = Roo.EventObject.setEvent(e);
5991             var  t;
5992             if(o.delegate){
5993                 t = e.getTarget(o.delegate, el);
5994                 if(!t){
5995                     return;
5996                 }
5997             }else {
5998                 t = e.target;
5999             }
6000             if(o.stopEvent === true){
6001                 e.stopEvent();
6002             }
6003             if(o.preventDefault === true){
6004                e.preventDefault();
6005             }
6006             if(o.stopPropagation === true){
6007                 e.stopPropagation();
6008             }
6009
6010             if(o.normalized === false){
6011                 e = e.browserEvent;
6012             }
6013
6014
6015             fn.call(V || el, e, t, o);
6016         };
6017         if(o.delay){
6018             h = N(h, o);
6019         }
6020         if(o.single){
6021             h = M(h, el, T, fn);
6022         }
6023         if(o.buffer){
6024             h = L(h, o);
6025         }
6026
6027         fn._handlers = fn._handlers || [];
6028         fn._handlers.push([Roo.id(el), T, h]);
6029
6030         E.on(el, T, h);
6031         if(T == "mousewheel" && el.addEventListener){ // workaround for jQuery
6032             el.addEventListener("DOMMouseScroll", h, false);
6033             E.on(window, 'unload', function(){
6034                 el.removeEventListener("DOMMouseScroll", h, false);
6035             });
6036         }
6037         if(T == "mousedown" && el == document){ // fix stopped mousedowns on the document
6038             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6039         }
6040         return  h;
6041     };
6042
6043     var  P = function(el, S, fn){
6044         var  id = Roo.id(el), T = fn._handlers, hd = fn;
6045         if(T){
6046             for(var  i = 0, len = T.length; i < len; i++){
6047                 var  h = T[i];
6048                 if(h[0] == id && h[1] == S){
6049                     hd = h[2];
6050                     T.splice(i, 1);
6051                     break;
6052                 }
6053             }
6054         }
6055
6056         E.un(el, S, hd);
6057         el = Roo.getDom(el);
6058         if(S == "mousewheel" && el.addEventListener){
6059             el.removeEventListener("DOMMouseScroll", hd, false);
6060         }
6061         if(S == "mousedown" && el == document){ // fix stopped mousedowns on the document
6062             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6063         }
6064     };
6065
6066     var  Q = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6067     
6068     var  R = {
6069         
6070         
6071         /** 
6072          * Fix for doc tools
6073          * @scope Roo.EventManager
6074          */
6075         
6076         
6077         /** 
6078          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6079          * object with a Roo.EventObject
6080          * @param {Function} fn        The method the event invokes
6081          * @param {Object}   scope    An object that becomes the scope of the handler
6082          * @param {boolean}  override If true, the obj passed in becomes
6083          *                             the execution scope of the listener
6084          * @return {Function} The wrapped function
6085          * @deprecated
6086          */
6087         wrap : function(fn, S, T){
6088             return  function(e){
6089                 Roo.EventObject.setEvent(e);
6090                 fn.call(T ? S || window : window, Roo.EventObject, S);
6091             };
6092         },
6093         
6094         /**
6095      * Appends an event handler to an element (shorthand for addListener)
6096      * @param {String/HTMLElement}   element        The html element or id to assign the
6097      * @param {String}   eventName The type of event to listen for
6098      * @param {Function} handler The method the event invokes
6099      * @param {Object}   scope (optional) The scope in which to execute the handler
6100      * function. The handler function's "this" context.
6101      * @param {Object}   options (optional) An object containing handler configuration
6102      * properties. This may contain any of the following properties:<ul>
6103      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6104      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6105      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6106      * <li>preventDefault {Boolean} True to prevent the default action</li>
6107      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6108      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6109      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6110      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6111      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6112      * by the specified number of milliseconds. If the event fires again within that time, the original
6113      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6114      * </ul><br>
6115      * <p>
6116      * <b>Combining Options</b><br>
6117      * Using the options argument, it is possible to combine different types of listeners:<br>
6118      * <br>
6119      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6120      * Code:<pre><code>
6121 el.on('click', this.onClick, this, {
6122     single: true,
6123     delay: 100,
6124     stopEvent : true,
6125     forumId: 4
6126 });</code></pre>
6127      * <p>
6128      * <b>Attaching multiple handlers in 1 call</b><br>
6129       * The method also allows for a single argument to be passed which is a config object containing properties
6130      * which specify multiple handlers.
6131      * <p>
6132      * Code:<pre><code>
6133 el.on({
6134     'click' : {
6135         fn: this.onClick
6136         scope: this,
6137         delay: 100
6138     },
6139     'mouseover' : {
6140         fn: this.onMouseOver
6141         scope: this
6142     },
6143     'mouseout' : {
6144         fn: this.onMouseOut
6145         scope: this
6146     }
6147 });</code></pre>
6148      * <p>
6149      * Or a shorthand syntax:<br>
6150      * Code:<pre><code>
6151 el.on({
6152     'click' : this.onClick,
6153     'mouseover' : this.onMouseOver,
6154     'mouseout' : this.onMouseOut
6155     scope: this
6156 });</code></pre>
6157      */
6158         addListener : function(U, V, fn, W, X){
6159             if(typeof  V == "object"){
6160                 var  o = V;
6161                 for(var  e  in  o){
6162                     if(Q.test(e)){
6163                         continue;
6164                     }
6165                     if(typeof  o[e] == "function"){
6166                         // shared options
6167                         O(U, e, o, o[e], o.scope);
6168                     }else {
6169                         // individual options
6170                         O(U, e, o[e]);
6171                     }
6172                 }
6173                 return;
6174             }
6175             return  O(U, V, X, fn, W);
6176         },
6177         
6178         /**
6179          * Removes an event handler
6180          *
6181          * @param {String/HTMLElement}   element        The id or html element to remove the 
6182          *                             event from
6183          * @param {String}   eventName     The type of event
6184          * @param {Function} fn
6185          * @return {Boolean} True if a listener was actually removed
6186          */
6187         removeListener : function(Y, Z, fn){
6188             return  P(Y, Z, fn);
6189         },
6190         
6191         /**
6192          * Fires when the document is ready (before onload and before images are loaded). Can be 
6193          * accessed shorthanded Roo.onReady().
6194          * @param {Function} fn        The method the event invokes
6195          * @param {Object}   scope    An  object that becomes the scope of the handler
6196          * @param {boolean}  options
6197          */
6198         onDocumentReady : function(fn, a, b){
6199             if(C){ // if it already fired
6200                 A.addListener(fn, a, b);
6201                 A.fire();
6202                 A.clearListeners();
6203                 return;
6204             }
6205             if(!A){
6206                 K();
6207             }
6208
6209             A.addListener(fn, a, b);
6210         },
6211         
6212         /**
6213          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6214          * @param {Function} fn        The method the event invokes
6215          * @param {Object}   scope    An object that becomes the scope of the handler
6216          * @param {boolean}  options
6217          */
6218         onWindowResize : function(fn, c, d){
6219             if(!F){
6220                 F = new  Roo.util.Event();
6221                 G = new  Roo.util.DelayedTask(function(){
6222                     F.fire(D.getViewWidth(), D.getViewHeight());
6223                 });
6224                 E.on(window, "resize", function(){
6225                     if(Roo.isIE){
6226                         G.delay(50);
6227                     }else {
6228                         F.fire(D.getViewWidth(), D.getViewHeight());
6229                     }
6230                 });
6231             }
6232
6233             F.addListener(fn, c, d);
6234         },
6235
6236         /**
6237          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6238          * @param {Function} fn        The method the event invokes
6239          * @param {Object}   scope    An object that becomes the scope of the handler
6240          * @param {boolean}  options
6241          */
6242         onTextResize : function(fn, f, g){
6243             if(!H){
6244                 H = new  Roo.util.Event();
6245                 var  textEl = new  Roo.Element(document.createElement('div'));
6246                 textEl.dom.className = 'x-text-resize';
6247                 textEl.dom.innerHTML = 'X';
6248                 textEl.appendTo(document.body);
6249                 I = textEl.dom.offsetHeight;
6250                 setInterval(function(){
6251                     if(textEl.dom.offsetHeight != I){
6252                         H.fire(I, I = textEl.dom.offsetHeight);
6253                     }
6254                 }, this.textResizeInterval);
6255             }
6256
6257             H.addListener(fn, f, g);
6258         },
6259
6260         /**
6261          * Removes the passed window resize listener.
6262          * @param {Function} fn        The method the event invokes
6263          * @param {Object}   scope    The scope of handler
6264          */
6265         removeResizeListener : function(fn, j){
6266             if(F){
6267                 F.removeListener(fn, j);
6268             }
6269         },
6270
6271         // private
6272         fireResize : function(){
6273             if(F){
6274                 F.fire(D.getViewWidth(), D.getViewHeight());
6275             }   
6276         },
6277         /**
6278          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6279          */
6280         ieDeferSrc : false,
6281         /**
6282          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6283          */
6284         textResizeInterval : 50
6285     };
6286     
6287     /**
6288      * Fix for doc tools
6289      * @scopeAlias pub=Roo.EventManager
6290      */
6291     
6292      /**
6293      * Appends an event handler to an element (shorthand for addListener)
6294      * @param {String/HTMLElement}   element        The html element or id to assign the
6295      * @param {String}   eventName The type of event to listen for
6296      * @param {Function} handler The method the event invokes
6297      * @param {Object}   scope (optional) The scope in which to execute the handler
6298      * function. The handler function's "this" context.
6299      * @param {Object}   options (optional) An object containing handler configuration
6300      * properties. This may contain any of the following properties:<ul>
6301      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304      * <li>preventDefault {Boolean} True to prevent the default action</li>
6305      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310      * by the specified number of milliseconds. If the event fires again within that time, the original
6311      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6312      * </ul><br>
6313      * <p>
6314      * <b>Combining Options</b><br>
6315      * Using the options argument, it is possible to combine different types of listeners:<br>
6316      * <br>
6317      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6318      * Code:<pre><code>
6319 el.on('click', this.onClick, this, {
6320     single: true,
6321     delay: 100,
6322     stopEvent : true,
6323     forumId: 4
6324 });</code></pre>
6325      * <p>
6326      * <b>Attaching multiple handlers in 1 call</b><br>
6327       * The method also allows for a single argument to be passed which is a config object containing properties
6328      * which specify multiple handlers.
6329      * <p>
6330      * Code:<pre><code>
6331 el.on({
6332     'click' : {
6333         fn: this.onClick
6334         scope: this,
6335         delay: 100
6336     },
6337     'mouseover' : {
6338         fn: this.onMouseOver
6339         scope: this
6340     },
6341     'mouseout' : {
6342         fn: this.onMouseOut
6343         scope: this
6344     }
6345 });</code></pre>
6346      * <p>
6347      * Or a shorthand syntax:<br>
6348      * Code:<pre><code>
6349 el.on({
6350     'click' : this.onClick,
6351     'mouseover' : this.onMouseOver,
6352     'mouseout' : this.onMouseOut
6353     scope: this
6354 });</code></pre>
6355      */
6356     R.on = R.addListener;
6357     R.un = R.removeListener;
6358
6359     R.stoppedMouseDownEvent = new  Roo.util.Event();
6360     return  R;
6361 }();
6362 /**
6363   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6364   * @param {Function} fn        The method the event invokes
6365   * @param {Object}   scope    An  object that becomes the scope of the handler
6366   * @param {boolean}  override If true, the obj passed in becomes
6367   *                             the execution scope of the listener
6368   * @member Roo
6369   * @method onReady
6370  */
6371 Roo.onReady = Roo.EventManager.onDocumentReady;
6372
6373 Roo.onReady(function(){
6374     var  bd = Roo.get(document.body);
6375     if(!bd){ return; }
6376
6377     var  S = [
6378             Roo.isIE ? "roo-ie"
6379             : Roo.isGecko ? "roo-gecko"
6380             : Roo.isOpera ? "roo-opera"
6381             : Roo.isSafari ? "roo-safari" : ""];
6382
6383     if(Roo.isMac){
6384         S.push("roo-mac");
6385     }
6386     if(Roo.isLinux){
6387         S.push("roo-linux");
6388     }
6389     if(Roo.isBorderBox){
6390         S.push('roo-border-box');
6391     }
6392     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6393         var  p = bd.dom.parentNode;
6394         if(p){
6395             p.className += ' roo-strict';
6396         }
6397     }
6398
6399     bd.addClass(S.join(' '));
6400 });
6401
6402 /**
6403  * @class Roo.EventObject
6404  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6405  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6406  * Example:
6407  * <pre><code>
6408  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6409     e.preventDefault();
6410     var target = e.getTarget();
6411     ...
6412  }
6413  var myDiv = Roo.get("myDiv");
6414  myDiv.on("click", handleClick);
6415  //or
6416  Roo.EventManager.on("myDiv", 'click', handleClick);
6417  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6418  </code></pre>
6419  * @singleton
6420  */
6421 Roo.EventObject = function(){
6422     
6423     var  E = Roo.lib.Event;
6424     
6425     // safari keypress events for special keys return bad keycodes
6426     var  T = {
6427         63234 : 37, // left
6428         63235 : 39, // right
6429         63232 : 38, // up
6430         63233 : 40, // down
6431         63276 : 33, // page up
6432         63277 : 34, // page down
6433         63272 : 46, // delete
6434         63273 : 36, // home
6435         63275 : 35  // end
6436     };
6437
6438     // normalize button clicks
6439     var  U = Roo.isIE ? {1:0,4:1,2:2} :
6440                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6441
6442     Roo.EventObjectImpl = function(e){
6443         if(e){
6444             this.setEvent(e.browserEvent || e);
6445         }
6446     };
6447     Roo.EventObjectImpl.prototype = {
6448         /**
6449          * Used to fix doc tools.
6450          * @scope Roo.EventObject.prototype
6451          */
6452             
6453
6454         
6455         
6456         /** The normal browser event */
6457         browserEvent : null,
6458         /** The button pressed in a mouse event */
6459         button : -1,
6460         /** True if the shift key was down during the event */
6461         shiftKey : false,
6462         /** True if the control key was down during the event */
6463         ctrlKey : false,
6464         /** True if the alt key was down during the event */
6465         altKey : false,
6466
6467         /** Key constant 
6468         * @type Number */
6469         BACKSPACE : 8,
6470         /** Key constant 
6471         * @type Number */
6472         TAB : 9,
6473         /** Key constant 
6474         * @type Number */
6475         RETURN  : 13,
6476         /** Key constant 
6477         * @type Number */
6478         ENTER : 13,
6479         /** Key constant 
6480         * @type Number */
6481         SHIFT : 16,
6482         /** Key constant 
6483         * @type Number */
6484         CONTROL : 17,
6485         /** Key constant 
6486         * @type Number */
6487         ESC : 27,
6488         /** Key constant 
6489         * @type Number */
6490         SPACE : 32,
6491         /** Key constant 
6492         * @type Number */
6493         PAGEUP : 33,
6494         /** Key constant 
6495         * @type Number */
6496         PAGEDOWN : 34,
6497         /** Key constant 
6498         * @type Number */
6499         END : 35,
6500         /** Key constant 
6501         * @type Number */
6502         HOME : 36,
6503         /** Key constant 
6504         * @type Number */
6505         LEFT : 37,
6506         /** Key constant 
6507         * @type Number */
6508         UP : 38,
6509         /** Key constant 
6510         * @type Number */
6511         RIGHT : 39,
6512         /** Key constant 
6513         * @type Number */
6514         DOWN : 40,
6515         /** Key constant 
6516         * @type Number */
6517         DELETE  : 46,
6518         /** Key constant 
6519         * @type Number */
6520         F5 : 116,
6521
6522            /** @private */
6523         setEvent : function(e){
6524             if(e == this || (e && e.browserEvent)){ // already wrapped
6525                 return  e;
6526             }
6527
6528             this.browserEvent = e;
6529             if(e){
6530                 // normalize buttons
6531                 this.button = e.button ? U[e.button] : (e.which ? e.which-1 : -1);
6532                 if(e.type == 'click' && this.button == -1){
6533                     this.button = 0;
6534                 }
6535
6536                 this.type = e.type;
6537                 this.shiftKey = e.shiftKey;
6538                 // mac metaKey behaves like ctrlKey
6539                 this.ctrlKey = e.ctrlKey || e.metaKey;
6540                 this.altKey = e.altKey;
6541                 // in getKey these will be normalized for the mac
6542                 this.keyCode = e.keyCode;
6543                 // keyup warnings on firefox.
6544                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6545                 // cache the target for the delayed and or buffered events
6546                 this.target = E.getTarget(e);
6547                 // same for XY
6548                 this.xy = E.getXY(e);
6549             }else {
6550                 this.button = -1;
6551                 this.shiftKey = false;
6552                 this.ctrlKey = false;
6553                 this.altKey = false;
6554                 this.keyCode = 0;
6555                 this.charCode =0;
6556                 this.target = null;
6557                 this.xy = [0, 0];
6558             }
6559             return  this;
6560         },
6561
6562         /**
6563          * Stop the event (preventDefault and stopPropagation)
6564          */
6565         stopEvent : function(){
6566             if(this.browserEvent){
6567                 if(this.browserEvent.type == 'mousedown'){
6568                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6569                 }
6570
6571                 E.stopEvent(this.browserEvent);
6572             }
6573         },
6574
6575         /**
6576          * Prevents the browsers default handling of the event.
6577          */
6578         preventDefault : function(){
6579             if(this.browserEvent){
6580                 E.preventDefault(this.browserEvent);
6581             }
6582         },
6583
6584         /** @private */
6585         isNavKeyPress : function(){
6586             var  k = this.keyCode;
6587             k = Roo.isSafari ? (T[k] || k) : k;
6588             return  (k >= 33 && k <= 40) || k == this.RETURN  || k == this.TAB || k == this.ESC;
6589         },
6590
6591         isSpecialKey : function(){
6592             var  k = this.keyCode;
6593             return  (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6594             (k == 16) || (k == 17) ||
6595             (k >= 18 && k <= 20) ||
6596             (k >= 33 && k <= 35) ||
6597             (k >= 36 && k <= 39) ||
6598             (k >= 44 && k <= 45);
6599         },
6600         /**
6601          * Cancels bubbling of the event.
6602          */
6603         stopPropagation : function(){
6604             if(this.browserEvent){
6605                 if(this.type == 'mousedown'){
6606                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6607                 }
6608
6609                 E.stopPropagation(this.browserEvent);
6610             }
6611         },
6612
6613         /**
6614          * Gets the key code for the event.
6615          * @return {Number}
6616          */
6617         getCharCode : function(){
6618             return  this.charCode || this.keyCode;
6619         },
6620
6621         /**
6622          * Returns a normalized keyCode for the event.
6623          * @return {Number} The key code
6624          */
6625         getKey : function(){
6626             var  k = this.keyCode || this.charCode;
6627             return  Roo.isSafari ? (T[k] || k) : k;
6628         },
6629
6630         /**
6631          * Gets the x coordinate of the event.
6632          * @return {Number}
6633          */
6634         getPageX : function(){
6635             return  this.xy[0];
6636         },
6637
6638         /**
6639          * Gets the y coordinate of the event.
6640          * @return {Number}
6641          */
6642         getPageY : function(){
6643             return  this.xy[1];
6644         },
6645
6646         /**
6647          * Gets the time of the event.
6648          * @return {Number}
6649          */
6650         getTime : function(){
6651             if(this.browserEvent){
6652                 return  E.getTime(this.browserEvent);
6653             }
6654             return  null;
6655         },
6656
6657         /**
6658          * Gets the page coordinates of the event.
6659          * @return {Array} The xy values like [x, y]
6660          */
6661         getXY : function(){
6662             return  this.xy;
6663         },
6664
6665         /**
6666          * Gets the target for the event.
6667          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6668          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6669                 search as a number or element (defaults to 10 || document.body)
6670          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6671          * @return {HTMLelement}
6672          */
6673         getTarget : function(V, W, X){
6674             return  V ? Roo.fly(this.target).findParent(V, W, X) : this.target;
6675         },
6676         /**
6677          * Gets the related target.
6678          * @return {HTMLElement}
6679          */
6680         getRelatedTarget : function(){
6681             if(this.browserEvent){
6682                 return  E.getRelatedTarget(this.browserEvent);
6683             }
6684             return  null;
6685         },
6686
6687         /**
6688          * Normalizes mouse wheel delta across browsers
6689          * @return {Number} The delta
6690          */
6691         getWheelDelta : function(){
6692             var  e = this.browserEvent;
6693             var  Y = 0;
6694             if(e.wheelDelta){ /* IE/Opera. */
6695                 Y = e.wheelDelta/120;
6696             }else  if(e.detail){ /* Mozilla case. */
6697                 Y = -e.detail/3;
6698             }
6699             return  Y;
6700         },
6701
6702         /**
6703          * Returns true if the control, meta, shift or alt key was pressed during this event.
6704          * @return {Boolean}
6705          */
6706         hasModifier : function(){
6707             return  !!((this.ctrlKey || this.altKey) || this.shiftKey);
6708         },
6709
6710         /**
6711          * Returns true if the target of this event equals el or is a child of el
6712          * @param {String/HTMLElement/Element} el
6713          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6714          * @return {Boolean}
6715          */
6716         within : function(el, Z){
6717             var  t = this[Z ? "getRelatedTarget" : "getTarget"]();
6718             return  t && Roo.fly(el).contains(t);
6719         },
6720
6721         getPoint : function(){
6722             return  new  Roo.lib.Point(this.xy[0], this.xy[1]);
6723         }
6724     };
6725
6726     return  new  Roo.EventObjectImpl();
6727 }();
6728             
6729     
6730 /*
6731  * Based on:
6732  * Ext JS Library 1.1.1
6733  * Copyright(c) 2006-2007, Ext JS, LLC.
6734  *
6735  * Originally Released Under LGPL - original licence link has changed is not relivant.
6736  *
6737  * Fork - LGPL
6738  * <script type="text/javascript">
6739  */
6740
6741  
6742 // was in Composite Element!??!?!
6743  
6744 (function(){
6745     var  D = Roo.lib.Dom;
6746     var  E = Roo.lib.Event;
6747     var  A = Roo.lib.Anim;
6748
6749     // local style camelizing for speed
6750     var  B = {};
6751     var  C = /(-[a-z])/gi;
6752     var  F = function(m, a){ return  a.charAt(1).toUpperCase(); };
6753     var  G = document.defaultView;
6754
6755 /**
6756  * @class Roo.Element
6757  * Represents an Element in the DOM.<br><br>
6758  * Usage:<br>
6759 <pre><code>
6760 var el = Roo.get("my-div");
6761
6762 // or with getEl
6763 var el = getEl("my-div");
6764
6765 // or with a DOM element
6766 var el = Roo.get(myDivElement);
6767 </code></pre>
6768  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6769  * each call instead of constructing a new one.<br><br>
6770  * <b>Animations</b><br />
6771  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6772  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6773 <pre>
6774 Option    Default   Description
6775 --------- --------  ---------------------------------------------
6776 duration  .35       The duration of the animation in seconds
6777 easing    easeOut   The YUI easing method
6778 callback  none      A function to execute when the anim completes
6779 scope     this      The scope (this) of the callback function
6780 </pre>
6781 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6782 * manipulate the animation. Here's an example:
6783 <pre><code>
6784 var el = Roo.get("my-div");
6785
6786 // no animation
6787 el.setWidth(100);
6788
6789 // default animation
6790 el.setWidth(100, true);
6791
6792 // animation with some options set
6793 el.setWidth(100, {
6794     duration: 1,
6795     callback: this.foo,
6796     scope: this
6797 });
6798
6799 // using the "anim" property to get the Anim object
6800 var opt = {
6801     duration: 1,
6802     callback: this.foo,
6803     scope: this
6804 };
6805 el.setWidth(100, opt);
6806 ...
6807 if(opt.anim.isAnimated()){
6808     opt.anim.stop();
6809 }
6810 </code></pre>
6811 * <b> Composite (Collections of) Elements</b><br />
6812  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6813  * @constructor Create a new Element directly.
6814  * @param {String/HTMLElement} element
6815  * @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).
6816  */
6817     Roo.Element = function(J, K){
6818         var  L = typeof  J == "string" ?
6819                 document.getElementById(J) : J;
6820         if(!L){ // invalid id/element
6821             return  null;
6822         }
6823         var  id = L.id;
6824         if(K !== true && id && Roo.Element.cache[id]){ // element object already exists
6825             return  Roo.Element.cache[id];
6826         }
6827
6828
6829         /**
6830          * The DOM element
6831          * @type HTMLElement
6832          */
6833         this.dom = L;
6834
6835         /**
6836          * The DOM element ID
6837          * @type String
6838          */
6839         this.id = id || Roo.id(L);
6840     };
6841
6842     var  El = Roo.Element;
6843
6844     El.prototype = {
6845         /**
6846          * The element's default display mode  (defaults to "")
6847          * @type String
6848          */
6849         originalDisplay : "",
6850
6851         visibilityMode : 1,
6852         /**
6853          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6854          * @type String
6855          */
6856         defaultUnit : "px",
6857         /**
6858          * Sets the element's visibility mode. When setVisible() is called it
6859          * will use this to determine whether to set the visibility or the display property.
6860          * @param visMode Element.VISIBILITY or Element.DISPLAY
6861          * @return {Roo.Element} this
6862          */
6863         setVisibilityMode : function(J){
6864             this.visibilityMode = J;
6865             return  this;
6866         },
6867         /**
6868          * Convenience method for setVisibilityMode(Element.DISPLAY)
6869          * @param {String} display (optional) What to set display to when visible
6870          * @return {Roo.Element} this
6871          */
6872         enableDisplayMode : function(K){
6873             this.setVisibilityMode(El.DISPLAY);
6874             if(typeof  K != "undefined") this.originalDisplay = K;
6875             return  this;
6876         },
6877
6878         /**
6879          * 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)
6880          * @param {String} selector The simple selector to test
6881          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6882                 search as a number or element (defaults to 10 || document.body)
6883          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6884          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6885          */
6886         findParent : function(L, M, N){
6887             var  p = this.dom, b = document.body, O = 0, dq = Roo.DomQuery, P;
6888             M = M || 50;
6889             if(typeof  M != "number"){
6890                 P = Roo.getDom(M);
6891                 M = 10;
6892             }
6893             while(p && p.nodeType == 1 && O < M && p != b && p != P){
6894                 if(dq.is(p, L)){
6895                     return  N ? Roo.get(p) : p;
6896                 }
6897
6898                 O++;
6899                 p = p.parentNode;
6900             }
6901             return  null;
6902         },
6903
6904
6905         /**
6906          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6907          * @param {String} selector The simple selector to test
6908          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6909                 search as a number or element (defaults to 10 || document.body)
6910          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6911          * @return {HTMLElement} The matching DOM node (or null if no match was found)
6912          */
6913         findParentNode : function(Q, R, S){
6914             var  p = Roo.fly(this.dom.parentNode, '_internal');
6915             return  p ? p.findParent(Q, R, S) : null;
6916         },
6917
6918         /**
6919          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6920          * This is a shortcut for findParentNode() that always returns an Roo.Element.
6921          * @param {String} selector The simple selector to test
6922          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6923                 search as a number or element (defaults to 10 || document.body)
6924          * @return {Roo.Element} The matching DOM node (or null if no match was found)
6925          */
6926         up : function(T, U){
6927             return  this.findParentNode(T, U, true);
6928         },
6929
6930
6931
6932         /**
6933          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6934          * @param {String} selector The simple selector to test
6935          * @return {Boolean} True if this element matches the selector, else false
6936          */
6937         is : function(V){
6938             return  Roo.DomQuery.is(this.dom, V);
6939         },
6940
6941         /**
6942          * Perform animation on this element.
6943          * @param {Object} args The YUI animation control args
6944          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6945          * @param {Function} onComplete (optional) Function to call when animation completes
6946          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6947          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6948          * @return {Roo.Element} this
6949          */
6950         animate : function(W, X, Y, Z, c){
6951             this.anim(W, {duration: X, callback: Y, easing: Z}, c);
6952             return  this;
6953         },
6954
6955         /*
6956          * @private Internal animation call
6957          */
6958         anim : function(e, g, h, j, k, cb){
6959             h = h || 'run';
6960             g = g || {};
6961             var  l = Roo.lib.Anim[h](
6962                 this.dom, e,
6963                 (g.duration || j) || .35,
6964                 (g.easing || k) || 'easeOut',
6965                 function(){
6966                     Roo.callback(cb, this);
6967                     Roo.callback(g.callback, g.scope || this, [this, g]);
6968                 },
6969                 this
6970             );
6971             g.anim = l;
6972             return  l;
6973         },
6974
6975         // private legacy anim prep
6976         preanim : function(a, i){
6977             return  !a[i] ? false : (typeof  a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6978         },
6979
6980         /**
6981          * Removes worthless text nodes
6982          * @param {Boolean} forceReclean (optional) By default the element
6983          * keeps track if it has been cleaned already so
6984          * you can call this over and over. However, if you update the element and
6985          * need to force a reclean, you can pass true.
6986          */
6987         clean : function(o){
6988             if(this.isCleaned && o !== true){
6989                 return  this;
6990             }
6991             var  ns = /\S/;
6992             var  d = this.dom, n = d.firstChild, ni = -1;
6993             while(n){
6994                 var  nx = n.nextSibling;
6995                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6996                     d.removeChild(n);
6997                 }else {
6998                     n.nodeIndex = ++ni;
6999                 }
7000
7001                 n = nx;
7002             }
7003
7004             this.isCleaned = true;
7005             return  this;
7006         },
7007
7008         // private
7009         calcOffsetsTo : function(el){
7010             el = Roo.get(el);
7011             var  d = el.dom;
7012             var  q = false;
7013             if(el.getStyle('position') == 'static'){
7014                 el.position('relative');
7015                 q = true;
7016             }
7017             var  x = 0, y =0;
7018             var  op = this.dom;
7019             while(op && op != d && op.tagName != 'HTML'){
7020                 x+= op.offsetLeft;
7021                 y+= op.offsetTop;
7022                 op = op.offsetParent;
7023             }
7024             if(q){
7025                 el.position('static');
7026             }
7027             return  [x, y];
7028         },
7029
7030         /**
7031          * Scrolls this element into view within the passed container.
7032          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7033          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7034          * @return {Roo.Element} this
7035          */
7036         scrollIntoView : function(u, v){
7037             var  c = Roo.getDom(u) || document.body;
7038             var  el = this.dom;
7039
7040             var  o = this.calcOffsetsTo(c),
7041                 l = o[0],
7042                 t = o[1],
7043                 b = t+el.offsetHeight,
7044                 r = l+el.offsetWidth;
7045
7046             var  ch = c.clientHeight;
7047             var  ct = parseInt(c.scrollTop, 10);
7048             var  cl = parseInt(c.scrollLeft, 10);
7049             var  cb = ct + ch;
7050             var  cr = cl + c.clientWidth;
7051
7052             if(t < ct){
7053                 c.scrollTop = t;
7054             }else  if(b > cb){
7055                 c.scrollTop = b-ch;
7056             }
7057
7058             if(v !== false){
7059                 if(l < cl){
7060                     c.scrollLeft = l;
7061                 }else  if(r > cr){
7062                     c.scrollLeft = r-c.clientWidth;
7063                 }
7064             }
7065             return  this;
7066         },
7067
7068         // private
7069         scrollChildIntoView : function(w, z){
7070             Roo.fly(w, '_scrollChildIntoView').scrollIntoView(this, z);
7071         },
7072
7073         /**
7074          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7075          * the new height may not be available immediately.
7076          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7077          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7078          * @param {Function} onComplete (optional) Function to call when animation completes
7079          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7080          * @return {Roo.Element} this
7081          */
7082         autoHeight : function(AA, AB, AC, AD){
7083             var  AE = this.getHeight();
7084             this.clip();
7085             this.setHeight(1); // force clipping
7086             setTimeout(function(){
7087                 var  AG = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7088                 if(!AA){
7089                     this.setHeight(AG);
7090                     this.unclip();
7091                     if(typeof  AC == "function"){
7092                         AC();
7093                     }
7094                 }else {
7095                     this.setHeight(AE); // restore original height
7096                     this.setHeight(AG, AA, AB, function(){
7097                         this.unclip();
7098                         if(typeof  AC == "function") AC();
7099                     }.createDelegate(this), AD);
7100                 }
7101             }.createDelegate(this), 0);
7102             return  this;
7103         },
7104
7105         /**
7106          * Returns true if this element is an ancestor of the passed element
7107          * @param {HTMLElement/String} el The element to check
7108          * @return {Boolean} True if this element is an ancestor of el, else false
7109          */
7110         contains : function(el){
7111             if(!el){return  false;}
7112             return  D.isAncestor(this.dom, el.dom ? el.dom : el);
7113         },
7114
7115         /**
7116          * Checks whether the element is currently visible using both visibility and display properties.
7117          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7118          * @return {Boolean} True if the element is currently visible, else false
7119          */
7120         isVisible : function(AF) {
7121             var  AG = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7122             if(AF !== true || !AG){
7123                 return  AG;
7124             }
7125             var  p = this.dom.parentNode;
7126             while(p && p.tagName.toLowerCase() != "body"){
7127                 if(!Roo.fly(p, '_isVisible').isVisible()){
7128                     return  false;
7129                 }
7130
7131                 p = p.parentNode;
7132             }
7133             return  true;
7134         },
7135
7136         /**
7137          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7138          * @param {String} selector The CSS selector
7139          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7140          * @return {CompositeElement/CompositeElementLite} The composite element
7141          */
7142         select : function(AH, AI){
7143             return  El.select(AH, AI, this.dom);
7144         },
7145
7146         /**
7147          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7148          * @param {String} selector The CSS selector
7149          * @return {Array} An array of the matched nodes
7150          */
7151         query : function(AJ, AK){
7152             return  Roo.DomQuery.select(AJ, this.dom);
7153         },
7154
7155         /**
7156          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7157          * @param {String} selector The CSS selector
7158          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7159          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7160          */
7161         child : function(AL, AM){
7162             var  n = Roo.DomQuery.selectNode(AL, this.dom);
7163             return  AM ? n : Roo.get(n);
7164         },
7165
7166         /**
7167          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7168          * @param {String} selector The CSS selector
7169          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7170          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7171          */
7172         down : function(AN, AO){
7173             var  n = Roo.DomQuery.selectNode(" > " + AN, this.dom);
7174             return  AO ? n : Roo.get(n);
7175         },
7176
7177         /**
7178          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7179          * @param {String} group The group the DD object is member of
7180          * @param {Object} config The DD config object
7181          * @param {Object} overrides An object containing methods to override/implement on the DD object
7182          * @return {Roo.dd.DD} The DD object
7183          */
7184         initDD : function(AP, AQ, AR){
7185             var  dd = new  Roo.dd.DD(Roo.id(this.dom), AP, AQ);
7186             return  Roo.apply(dd, AR);
7187         },
7188
7189         /**
7190          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7191          * @param {String} group The group the DDProxy object is member of
7192          * @param {Object} config The DDProxy config object
7193          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7194          * @return {Roo.dd.DDProxy} The DDProxy object
7195          */
7196         initDDProxy : function(AS, AT, AU){
7197             var  dd = new  Roo.dd.DDProxy(Roo.id(this.dom), AS, AT);
7198             return  Roo.apply(dd, AU);
7199         },
7200
7201         /**
7202          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7203          * @param {String} group The group the DDTarget object is member of
7204          * @param {Object} config The DDTarget config object
7205          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7206          * @return {Roo.dd.DDTarget} The DDTarget object
7207          */
7208         initDDTarget : function(AV, AW, AX){
7209             var  dd = new  Roo.dd.DDTarget(Roo.id(this.dom), AV, AW);
7210             return  Roo.apply(dd, AX);
7211         },
7212
7213         /**
7214          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7215          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7216          * @param {Boolean} visible Whether the element is visible
7217          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7218          * @return {Roo.Element} this
7219          */
7220          setVisible : function(AY, AZ){
7221             if(!AZ || !A){
7222                 if(this.visibilityMode == El.DISPLAY){
7223                     this.setDisplayed(AY);
7224                 }else {
7225                     this.fixDisplay();
7226                     this.dom.style.visibility = AY ? "visible" : "hidden";
7227                 }
7228             }else {
7229                 // closure for composites
7230                 var  dom = this.dom;
7231                 var  J = this.visibilityMode;
7232                 if(AY){
7233                     this.setOpacity(.01);
7234                     this.setVisible(true);
7235                 }
7236
7237                 this.anim({opacity: { to: (AY?1:0) }},
7238                       this.preanim(arguments, 1),
7239                       null, .35, 'easeIn', function(){
7240                          if(!AY){
7241                              if(J == El.DISPLAY){
7242                                  dom.style.display = "none";
7243                              }else {
7244                                  dom.style.visibility = "hidden";
7245                              }
7246
7247                              Roo.get(dom).setOpacity(1);
7248                          }
7249                      });
7250             }
7251             return  this;
7252         },
7253
7254         /**
7255          * Returns true if display is not "none"
7256          * @return {Boolean}
7257          */
7258         isDisplayed : function() {
7259             return  this.getStyle("display") != "none";
7260         },
7261
7262         /**
7263          * Toggles the element's visibility or display, depending on visibility mode.
7264          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7265          * @return {Roo.Element} this
7266          */
7267         toggle : function(Aa){
7268             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7269             return  this;
7270         },
7271
7272         /**
7273          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7274          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7275          * @return {Roo.Element} this
7276          */
7277         setDisplayed : function(Ab) {
7278             if(typeof  Ab == "boolean"){
7279                Ab = Ab ? this.originalDisplay : "none";
7280             }
7281
7282             this.setStyle("display", Ab);
7283             return  this;
7284         },
7285
7286         /**
7287          * Tries to focus the element. Any exceptions are caught and ignored.
7288          * @return {Roo.Element} this
7289          */
7290         focus : function() {
7291             try{
7292                 this.dom.focus();
7293             }catch(e){}
7294             return  this;
7295         },
7296
7297         /**
7298          * Tries to blur the element. Any exceptions are caught and ignored.
7299          * @return {Roo.Element} this
7300          */
7301         blur : function() {
7302             try{
7303                 this.dom.blur();
7304             }catch(e){}
7305             return  this;
7306         },
7307
7308         /**
7309          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7310          * @param {String/Array} className The CSS class to add, or an array of classes
7311          * @return {Roo.Element} this
7312          */
7313         addClass : function(Ac){
7314             if(Ac  instanceof  Array){
7315                 for(var  i = 0, len = Ac.length; i < len; i++) {
7316                     this.addClass(Ac[i]);
7317                 }
7318             }else {
7319                 if(Ac && !this.hasClass(Ac)){
7320                     this.dom.className = this.dom.className + " " + Ac;
7321                 }
7322             }
7323             return  this;
7324         },
7325
7326         /**
7327          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7328          * @param {String/Array} className The CSS class to add, or an array of classes
7329          * @return {Roo.Element} this
7330          */
7331         radioClass : function(Ad){
7332             var  Ae = this.dom.parentNode.childNodes;
7333             for(var  i = 0; i < Ae.length; i++) {
7334                 var  s = Ae[i];
7335                 if(s.nodeType == 1){
7336                     Roo.get(s).removeClass(Ad);
7337                 }
7338             }
7339
7340             this.addClass(Ad);
7341             return  this;
7342         },
7343
7344         /**
7345          * Removes one or more CSS classes from the element.
7346          * @param {String/Array} className The CSS class to remove, or an array of classes
7347          * @return {Roo.Element} this
7348          */
7349         removeClass : function(Af){
7350             if(!Af || !this.dom.className){
7351                 return  this;
7352             }
7353             if(Af  instanceof  Array){
7354                 for(var  i = 0, len = Af.length; i < len; i++) {
7355                     this.removeClass(Af[i]);
7356                 }
7357             }else {
7358                 if(this.hasClass(Af)){
7359                     var  re = this.classReCache[Af];
7360                     if (!re) {
7361                        re = new  RegExp('(?:^|\\s+)' + Af + '(?:\\s+|$)', "g");
7362                        this.classReCache[Af] = re;
7363                     }
7364
7365                     this.dom.className =
7366                         this.dom.className.replace(re, " ");
7367                 }
7368             }
7369             return  this;
7370         },
7371
7372         // private
7373         classReCache: {},
7374
7375         /**
7376          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7377          * @param {String} className The CSS class to toggle
7378          * @return {Roo.Element} this
7379          */
7380         toggleClass : function(Ag){
7381             if(this.hasClass(Ag)){
7382                 this.removeClass(Ag);
7383             }else {
7384                 this.addClass(Ag);
7385             }
7386             return  this;
7387         },
7388
7389         /**
7390          * Checks if the specified CSS class exists on this element's DOM node.
7391          * @param {String} className The CSS class to check for
7392          * @return {Boolean} True if the class exists, else false
7393          */
7394         hasClass : function(Ah){
7395             return  Ah && (' '+this.dom.className+' ').indexOf(' '+Ah+' ') != -1;
7396         },
7397
7398         /**
7399          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7400          * @param {String} oldClassName The CSS class to replace
7401          * @param {String} newClassName The replacement CSS class
7402          * @return {Roo.Element} this
7403          */
7404         replaceClass : function(Ai, Aj){
7405             this.removeClass(Ai);
7406             this.addClass(Aj);
7407             return  this;
7408         },
7409
7410         /**
7411          * Returns an object with properties matching the styles requested.
7412          * For example, el.getStyles('color', 'font-size', 'width') might return
7413          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7414          * @param {String} style1 A style name
7415          * @param {String} style2 A style name
7416          * @param {String} etc.
7417          * @return {Object} The style object
7418          */
7419         getStyles : function(){
7420             var  a = arguments, Ak = a.length, r = {};
7421             for(var  i = 0; i < Ak; i++){
7422                 r[a[i]] = this.getStyle(a[i]);
7423             }
7424             return  r;
7425         },
7426
7427         /**
7428          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7429          * @param {String} property The style property whose value is returned.
7430          * @return {String} The current value of the style property for this element.
7431          */
7432         getStyle : function(){
7433             return  G && G.getComputedStyle ?
7434                 function(Al){
7435                     var  el = this.dom, v, cs, Am;
7436                     if(Al == 'float'){
7437                         Al = "cssFloat";
7438                     }
7439                     if(el.style && (v = el.style[Al])){
7440                         return  v;
7441                     }
7442                     if(cs = G.getComputedStyle(el, "")){
7443                         if(!(Am = B[Al])){
7444                             Am = B[Al] = Al.replace(C, F);
7445                         }
7446                         return  cs[Am];
7447                     }
7448                     return  null;
7449                 } :
7450                 function(Al){
7451                     var  el = this.dom, v, cs, Am;
7452                     if(Al == 'opacity'){
7453                         if(typeof  el.style.filter == 'string'){
7454                             var  m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7455                             if(m){
7456                                 var  fv = parseFloat(m[1]);
7457                                 if(!isNaN(fv)){
7458                                     return  fv ? fv / 100 : 0;
7459                                 }
7460                             }
7461                         }
7462                         return  1;
7463                     }else  if(Al == 'float'){
7464                         Al = "styleFloat";
7465                     }
7466                     if(!(Am = B[Al])){
7467                         Am = B[Al] = Al.replace(C, F);
7468                     }
7469                     if(v = el.style[Am]){
7470                         return  v;
7471                     }
7472                     if(cs = el.currentStyle){
7473                         return  cs[Am];
7474                     }
7475                     return  null;
7476                 };
7477         }(),
7478
7479         /**
7480          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7481          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7482          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7483          * @return {Roo.Element} this
7484          */
7485         setStyle : function(Al, Am){
7486             if(typeof  Al == "string"){
7487                 var  camel;
7488                 if(!(camel = B[Al])){
7489                     camel = B[Al] = Al.replace(C, F);
7490                 }
7491                 if(camel == 'opacity') {
7492                     this.setOpacity(Am);
7493                 }else {
7494                     this.dom.style[camel] = Am;
7495                 }
7496             }else {
7497                 for(var  style  in  Al){
7498                     if(typeof  Al[style] != "function"){
7499                        this.setStyle(style, Al[style]);
7500                     }
7501                 }
7502             }
7503             return  this;
7504         },
7505
7506         /**
7507          * More flexible version of {@link #setStyle} for setting style properties.
7508          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7509          * a function which returns such a specification.
7510          * @return {Roo.Element} this
7511          */
7512         applyStyles : function(An){
7513             Roo.DomHelper.applyStyles(this.dom, An);
7514             return  this;
7515         },
7516
7517         /**
7518           * 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).
7519           * @return {Number} The X position of the element
7520           */
7521         getX : function(){
7522             return  D.getX(this.dom);
7523         },
7524
7525         /**
7526           * 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).
7527           * @return {Number} The Y position of the element
7528           */
7529         getY : function(){
7530             return  D.getY(this.dom);
7531         },
7532
7533         /**
7534           * 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).
7535           * @return {Array} The XY position of the element
7536           */
7537         getXY : function(){
7538             return  D.getXY(this.dom);
7539         },
7540
7541         /**
7542          * 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).
7543          * @param {Number} The X position of the element
7544          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7545          * @return {Roo.Element} this
7546          */
7547         setX : function(x, Ao){
7548             if(!Ao || !A){
7549                 D.setX(this.dom, x);
7550             }else {
7551                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7552             }
7553             return  this;
7554         },
7555
7556         /**
7557          * 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).
7558          * @param {Number} The Y position of the element
7559          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7560          * @return {Roo.Element} this
7561          */
7562         setY : function(y, Ap){
7563             if(!Ap || !A){
7564                 D.setY(this.dom, y);
7565             }else {
7566                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7567             }
7568             return  this;
7569         },
7570
7571         /**
7572          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7573          * @param {String} left The left CSS property value
7574          * @return {Roo.Element} this
7575          */
7576         setLeft : function(Aq){
7577             this.setStyle("left", this.addUnits(Aq));
7578             return  this;
7579         },
7580
7581         /**
7582          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7583          * @param {String} top The top CSS property value
7584          * @return {Roo.Element} this
7585          */
7586         setTop : function(Ar){
7587             this.setStyle("top", this.addUnits(Ar));
7588             return  this;
7589         },
7590
7591         /**
7592          * Sets the element's CSS right style.
7593          * @param {String} right The right CSS property value
7594          * @return {Roo.Element} this
7595          */
7596         setRight : function(As){
7597             this.setStyle("right", this.addUnits(As));
7598             return  this;
7599         },
7600
7601         /**
7602          * Sets the element's CSS bottom style.
7603          * @param {String} bottom The bottom CSS property value
7604          * @return {Roo.Element} this
7605          */
7606         setBottom : function(At){
7607             this.setStyle("bottom", this.addUnits(At));
7608             return  this;
7609         },
7610
7611         /**
7612          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7613          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7614          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7615          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7616          * @return {Roo.Element} this
7617          */
7618         setXY : function(Au, Av){
7619             if(!Av || !A){
7620                 D.setXY(this.dom, Au);
7621             }else {
7622                 this.anim({points: {to: Au}}, this.preanim(arguments, 1), 'motion');
7623             }
7624             return  this;
7625         },
7626
7627         /**
7628          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7629          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7630          * @param {Number} x X value for new position (coordinates are page-based)
7631          * @param {Number} y Y value for new position (coordinates are page-based)
7632          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7633          * @return {Roo.Element} this
7634          */
7635         setLocation : function(x, y, Aw){
7636             this.setXY([x, y], this.preanim(arguments, 2));
7637             return  this;
7638         },
7639
7640         /**
7641          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7642          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7643          * @param {Number} x X value for new position (coordinates are page-based)
7644          * @param {Number} y Y value for new position (coordinates are page-based)
7645          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7646          * @return {Roo.Element} this
7647          */
7648         moveTo : function(x, y, Ax){
7649             this.setXY([x, y], this.preanim(arguments, 2));
7650             return  this;
7651         },
7652
7653         /**
7654          * Returns the region of the given element.
7655          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7656          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7657          */
7658         getRegion : function(){
7659             return  D.getRegion(this.dom);
7660         },
7661
7662         /**
7663          * Returns the offset height of the element
7664          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7665          * @return {Number} The element's height
7666          */
7667         getHeight : function(Ay){
7668             var  h = this.dom.offsetHeight || 0;
7669             return  Ay !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7670         },
7671
7672         /**
7673          * Returns the offset width of the element
7674          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7675          * @return {Number} The element's width
7676          */
7677         getWidth : function(Az){
7678             var  w = this.dom.offsetWidth || 0;
7679             return  Az !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7680         },
7681
7682         /**
7683          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7684          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7685          * if a height has not been set using CSS.
7686          * @return {Number}
7687          */
7688         getComputedHeight : function(){
7689             var  h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7690             if(!h){
7691                 h = parseInt(this.getStyle('height'), 10) || 0;
7692                 if(!this.isBorderBox()){
7693                     h += this.getFrameWidth('tb');
7694                 }
7695             }
7696             return  h;
7697         },
7698
7699         /**
7700          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7701          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7702          * if a width has not been set using CSS.
7703          * @return {Number}
7704          */
7705         getComputedWidth : function(){
7706             var  w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7707             if(!w){
7708                 w = parseInt(this.getStyle('width'), 10) || 0;
7709                 if(!this.isBorderBox()){
7710                     w += this.getFrameWidth('lr');
7711                 }
7712             }
7713             return  w;
7714         },
7715
7716         /**
7717          * Returns the size of the element.
7718          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7719          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7720          */
7721         getSize : function(A0){
7722             return  {width: this.getWidth(A0), height: this.getHeight(A0)};
7723         },
7724
7725         /**
7726          * Returns the width and height of the viewport.
7727          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7728          */
7729         getViewSize : function(){
7730             var  d = this.dom, A1 = document, aw = 0, ah = 0;
7731             if(d == A1 || d == A1.body){
7732                 return  {width : D.getViewWidth(), height: D.getViewHeight()};
7733             }else {
7734                 return  {
7735                     width : d.clientWidth,
7736                     height: d.clientHeight
7737                 };
7738             }
7739         },
7740
7741         /**
7742          * Returns the value of the "value" attribute
7743          * @param {Boolean} asNumber true to parse the value as a number
7744          * @return {String/Number}
7745          */
7746         getValue : function(A2){
7747             return  A2 ? parseInt(this.dom.value, 10) : this.dom.value;
7748         },
7749
7750         // private
7751         adjustWidth : function(A3){
7752             if(typeof  A3 == "number"){
7753                 if(this.autoBoxAdjust && !this.isBorderBox()){
7754                    A3 -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7755                 }
7756                 if(A3 < 0){
7757                     A3 = 0;
7758                 }
7759             }
7760             return  A3;
7761         },
7762
7763         // private
7764         adjustHeight : function(A4){
7765             if(typeof  A4 == "number"){
7766                if(this.autoBoxAdjust && !this.isBorderBox()){
7767                    A4 -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7768                }
7769                if(A4 < 0){
7770                    A4 = 0;
7771                }
7772             }
7773             return  A4;
7774         },
7775
7776         /**
7777          * Set the width of the element
7778          * @param {Number} width The new width
7779          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7780          * @return {Roo.Element} this
7781          */
7782         setWidth : function(A5, A6){
7783             A5 = this.adjustWidth(A5);
7784             if(!A6 || !A){
7785                 this.dom.style.width = this.addUnits(A5);
7786             }else {
7787                 this.anim({width: {to: A5}}, this.preanim(arguments, 1));
7788             }
7789             return  this;
7790         },
7791
7792         /**
7793          * Set the height of the element
7794          * @param {Number} height The new height
7795          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7796          * @return {Roo.Element} this
7797          */
7798          setHeight : function(A7, A8){
7799             A7 = this.adjustHeight(A7);
7800             if(!A8 || !A){
7801                 this.dom.style.height = this.addUnits(A7);
7802             }else {
7803                 this.anim({height: {to: A7}}, this.preanim(arguments, 1));
7804             }
7805             return  this;
7806         },
7807
7808         /**
7809          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7810          * @param {Number} width The new width
7811          * @param {Number} height The new height
7812          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7813          * @return {Roo.Element} this
7814          */
7815          setSize : function(A9, BA, BB){
7816             if(typeof  A9 == "object"){ // in case of object from getSize()
7817                 BA = A9.height; A9 = A9.width;
7818             }
7819
7820             A9 = this.adjustWidth(A9); BA = this.adjustHeight(BA);
7821             if(!BB || !A){
7822                 this.dom.style.width = this.addUnits(A9);
7823                 this.dom.style.height = this.addUnits(BA);
7824             }else {
7825                 this.anim({width: {to: A9}, height: {to: BA}}, this.preanim(arguments, 2));
7826             }
7827             return  this;
7828         },
7829
7830         /**
7831          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7832          * @param {Number} x X value for new position (coordinates are page-based)
7833          * @param {Number} y Y value for new position (coordinates are page-based)
7834          * @param {Number} width The new width
7835          * @param {Number} height The new height
7836          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7837          * @return {Roo.Element} this
7838          */
7839         setBounds : function(x, y, BC, BD, BE){
7840             if(!BE || !A){
7841                 this.setSize(BC, BD);
7842                 this.setLocation(x, y);
7843             }else {
7844                 BC = this.adjustWidth(BC); BD = this.adjustHeight(BD);
7845                 this.anim({points: {to: [x, y]}, width: {to: BC}, height: {to: BD}},
7846                               this.preanim(arguments, 4), 'motion');
7847             }
7848             return  this;
7849         },
7850
7851         /**
7852          * 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.
7853          * @param {Roo.lib.Region} region The region to fill
7854          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7855          * @return {Roo.Element} this
7856          */
7857         setRegion : function(BF, BG){
7858             this.setBounds(BF.left, BF.top, BF.right-BF.left, BF.bottom-BF.top, this.preanim(arguments, 1));
7859             return  this;
7860         },
7861
7862         /**
7863          * Appends an event handler
7864          *
7865          * @param {String}   eventName     The type of event to append
7866          * @param {Function} fn        The method the event invokes
7867          * @param {Object} scope       (optional) The scope (this object) of the fn
7868          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7869          */
7870         addListener : function(BH, fn, BI, BJ){
7871             Roo.EventManager.on(this.dom,  BH, fn, BI || this, BJ);
7872         },
7873
7874         /**
7875          * Removes an event handler from this element
7876          * @param {String} eventName the type of event to remove
7877          * @param {Function} fn the method the event invokes
7878          * @return {Roo.Element} this
7879          */
7880         removeListener : function(BK, fn){
7881             Roo.EventManager.removeListener(this.dom,  BK, fn);
7882             return  this;
7883         },
7884
7885         /**
7886          * Removes all previous added listeners from this element
7887          * @return {Roo.Element} this
7888          */
7889         removeAllListeners : function(){
7890             E.purgeElement(this.dom);
7891             return  this;
7892         },
7893
7894         relayEvent : function(BL, BM){
7895             this.on(BL, function(e){
7896                 BM.fireEvent(BL, e);
7897             });
7898         },
7899
7900         /**
7901          * Set the opacity of the element
7902          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7903          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7904          * @return {Roo.Element} this
7905          */
7906          setOpacity : function(BN, BO){
7907             if(!BO || !A){
7908                 var  s = this.dom.style;
7909                 if(Roo.isIE){
7910                     s.zoom = 1;
7911                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7912                                (BN == 1 ? "" : "alpha(opacity=" + BN * 100 + ")");
7913                 }else {
7914                     s.opacity = BN;
7915                 }
7916             }else {
7917                 this.anim({opacity: {to: BN}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7918             }
7919             return  this;
7920         },
7921
7922         /**
7923          * Gets the left X coordinate
7924          * @param {Boolean} local True to get the local css position instead of page coordinate
7925          * @return {Number}
7926          */
7927         getLeft : function(BP){
7928             if(!BP){
7929                 return  this.getX();
7930             }else {
7931                 return  parseInt(this.getStyle("left"), 10) || 0;
7932             }
7933         },
7934
7935         /**
7936          * Gets the right X coordinate of the element (element X position + element width)
7937          * @param {Boolean} local True to get the local css position instead of page coordinate
7938          * @return {Number}
7939          */
7940         getRight : function(BQ){
7941             if(!BQ){
7942                 return  this.getX() + this.getWidth();
7943             }else {
7944                 return  (this.getLeft(true) + this.getWidth()) || 0;
7945             }
7946         },
7947
7948         /**
7949          * Gets the top Y coordinate
7950          * @param {Boolean} local True to get the local css position instead of page coordinate
7951          * @return {Number}
7952          */
7953         getTop : function(BR) {
7954             if(!BR){
7955                 return  this.getY();
7956             }else {
7957                 return  parseInt(this.getStyle("top"), 10) || 0;
7958             }
7959         },
7960
7961         /**
7962          * Gets the bottom Y coordinate of the element (element Y position + element height)
7963          * @param {Boolean} local True to get the local css position instead of page coordinate
7964          * @return {Number}
7965          */
7966         getBottom : function(BS){
7967             if(!BS){
7968                 return  this.getY() + this.getHeight();
7969             }else {
7970                 return  (this.getTop(true) + this.getHeight()) || 0;
7971             }
7972         },
7973
7974         /**
7975         * Initializes positioning on this element. If a desired position is not passed, it will make the
7976         * the element positioned relative IF it is not already positioned.
7977         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7978         * @param {Number} zIndex (optional) The zIndex to apply
7979         * @param {Number} x (optional) Set the page X position
7980         * @param {Number} y (optional) Set the page Y position
7981         */
7982         position : function(BT, BU, x, y){
7983             if(!BT){
7984                if(this.getStyle('position') == 'static'){
7985                    this.setStyle('position', 'relative');
7986                }
7987             }else {
7988                 this.setStyle("position", BT);
7989             }
7990             if(BU){
7991                 this.setStyle("z-index", BU);
7992             }
7993             if(x !== undefined && y !== undefined){
7994                 this.setXY([x, y]);
7995             }else  if(x !== undefined){
7996                 this.setX(x);
7997             }else  if(y !== undefined){
7998                 this.setY(y);
7999             }
8000         },
8001
8002         /**
8003         * Clear positioning back to the default when the document was loaded
8004         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8005         * @return {Roo.Element} this
8006          */
8007         clearPositioning : function(BV){
8008             BV = BV ||'';
8009             this.setStyle({
8010                 "left": BV,
8011                 "right": BV,
8012                 "top": BV,
8013                 "bottom": BV,
8014                 "z-index": "",
8015                 "position" : "static"
8016             });
8017             return  this;
8018         },
8019
8020         /**
8021         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8022         * snapshot before performing an update and then restoring the element.
8023         * @return {Object}
8024         */
8025         getPositioning : function(){
8026             var  l = this.getStyle("left");
8027             var  t = this.getStyle("top");
8028             return  {
8029                 "position" : this.getStyle("position"),
8030                 "left" : l,
8031                 "right" : l ? "" : this.getStyle("right"),
8032                 "top" : t,
8033                 "bottom" : t ? "" : this.getStyle("bottom"),
8034                 "z-index" : this.getStyle("z-index")
8035             };
8036         },
8037
8038         /**
8039          * Gets the width of the border(s) for the specified side(s)
8040          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8041          * passing lr would get the border (l)eft width + the border (r)ight width.
8042          * @return {Number} The width of the sides passed added together
8043          */
8044         getBorderWidth : function(BW){
8045             return  this.addStyles(BW, El.borders);
8046         },
8047
8048         /**
8049          * Gets the width of the padding(s) for the specified side(s)
8050          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8051          * passing lr would get the padding (l)eft + the padding (r)ight.
8052          * @return {Number} The padding of the sides passed added together
8053          */
8054         getPadding : function(BX){
8055             return  this.addStyles(BX, El.paddings);
8056         },
8057
8058         /**
8059         * Set positioning with an object returned by getPositioning().
8060         * @param {Object} posCfg
8061         * @return {Roo.Element} this
8062          */
8063         setPositioning : function(pc){
8064             this.applyStyles(pc);
8065             if(pc.right == "auto"){
8066                 this.dom.style.right = "";
8067             }
8068             if(pc.bottom == "auto"){
8069                 this.dom.style.bottom = "";
8070             }
8071             return  this;
8072         },
8073
8074         // private
8075         fixDisplay : function(){
8076             if(this.getStyle("display") == "none"){
8077                 this.setStyle("visibility", "hidden");
8078                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8079                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8080                     this.setStyle("display", "block");
8081                 }
8082             }
8083         },
8084
8085         /**
8086          * Quick set left and top adding default units
8087          * @param {String} left The left CSS property value
8088          * @param {String} top The top CSS property value
8089          * @return {Roo.Element} this
8090          */
8091          setLeftTop : function(BY, BZ){
8092             this.dom.style.left = this.addUnits(BY);
8093             this.dom.style.top = this.addUnits(BZ);
8094             return  this;
8095         },
8096
8097         /**
8098          * Move this element relative to its current position.
8099          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8100          * @param {Number} distance How far to move the element in pixels
8101          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8102          * @return {Roo.Element} this
8103          */
8104          move : function(Ba, Bb, Bc){
8105             var  xy = this.getXY();
8106             Ba = Ba.toLowerCase();
8107             switch(Ba){
8108                 case  "l":
8109                 case  "left":
8110                     this.moveTo(xy[0]-Bb, xy[1], this.preanim(arguments, 2));
8111                     break;
8112                case  "r":
8113                case  "right":
8114                     this.moveTo(xy[0]+Bb, xy[1], this.preanim(arguments, 2));
8115                     break;
8116                case  "t":
8117                case  "top":
8118                case  "up":
8119                     this.moveTo(xy[0], xy[1]-Bb, this.preanim(arguments, 2));
8120                     break;
8121                case  "b":
8122                case  "bottom":
8123                case  "down":
8124                     this.moveTo(xy[0], xy[1]+Bb, this.preanim(arguments, 2));
8125                     break;
8126             }
8127             return  this;
8128         },
8129
8130         /**
8131          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8132          * @return {Roo.Element} this
8133          */
8134         clip : function(){
8135             if(!this.isClipped){
8136                this.isClipped = true;
8137                this.originalClip = {
8138                    "o": this.getStyle("overflow"),
8139                    "x": this.getStyle("overflow-x"),
8140                    "y": this.getStyle("overflow-y")
8141                };
8142                this.setStyle("overflow", "hidden");
8143                this.setStyle("overflow-x", "hidden");
8144                this.setStyle("overflow-y", "hidden");
8145             }
8146             return  this;
8147         },
8148
8149         /**
8150          *  Return clipping (overflow) to original clipping before clip() was called
8151          * @return {Roo.Element} this
8152          */
8153         unclip : function(){
8154             if(this.isClipped){
8155                 this.isClipped = false;
8156                 var  o = this.originalClip;
8157                 if(o.o){this.setStyle("overflow", o.o);}
8158                 if(o.x){this.setStyle("overflow-x", o.x);}
8159                 if(o.y){this.setStyle("overflow-y", o.y);}
8160             }
8161             return  this;
8162         },
8163
8164
8165         /**
8166          * Gets the x,y coordinates specified by the anchor position on the element.
8167          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8168          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8169          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8170          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8171          * @return {Array} [x, y] An array containing the element's x and y coordinates
8172          */
8173         getAnchorXY : function(Bd, Be, s){
8174             //Passing a different size is useful for pre-calculating anchors,
8175             //especially for anchored animations that change the el size.
8176
8177             var  w, h, vp = false;
8178             if(!s){
8179                 var  d = this.dom;
8180                 if(d == document.body || d == document){
8181                     vp = true;
8182                     w = D.getViewWidth(); h = D.getViewHeight();
8183                 }else {
8184                     w = this.getWidth(); h = this.getHeight();
8185                 }
8186             }else {
8187                 w = s.width;  h = s.height;
8188             }
8189             var  x = 0, y = 0, r = Math.round;
8190             switch((Bd || "tl").toLowerCase()){
8191                 case  "c":
8192                     x = r(w*.5);
8193                     y = r(h*.5);
8194                 break;
8195                 case  "t":
8196                     x = r(w*.5);
8197                     y = 0;
8198                 break;
8199                 case  "l":
8200                     x = 0;
8201                     y = r(h*.5);
8202                 break;
8203                 case  "r":
8204                     x = w;
8205                     y = r(h*.5);
8206                 break;
8207                 case  "b":
8208                     x = r(w*.5);
8209                     y = h;
8210                 break;
8211                 case  "tl":
8212                     x = 0;
8213                     y = 0;
8214                 break;
8215                 case  "bl":
8216                     x = 0;
8217                     y = h;
8218                 break;
8219                 case  "br":
8220                     x = w;
8221                     y = h;
8222                 break;
8223                 case  "tr":
8224                     x = w;
8225                     y = 0;
8226                 break;
8227             }
8228             if(Be === true){
8229                 return  [x, y];
8230             }
8231             if(vp){
8232                 var  sc = this.getScroll();
8233                 return  [x + sc.left, y + sc.top];
8234             }
8235             //Add the element's offset xy
8236             var  o = this.getXY();
8237             return  [x+o[0], y+o[1]];
8238         },
8239
8240         /**
8241          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8242          * supported position values.
8243          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8244          * @param {String} position The position to align to.
8245          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8246          * @return {Array} [x, y]
8247          */
8248         getAlignToXY : function(el, p, o){
8249             el = Roo.get(el);
8250             var  d = this.dom;
8251             if(!el.dom){
8252                 throw  "Element.alignTo with an element that doesn't exist";
8253             }
8254             var  c = false; //constrain to viewport
8255             var  p1 = "", p2 = "";
8256             o = o || [0,0];
8257
8258             if(!p){
8259                 p = "tl-bl";
8260             }else  if(p == "?"){
8261                 p = "tl-bl?";
8262             }else  if(p.indexOf("-") == -1){
8263                 p = "tl-" + p;
8264             }
8265
8266             p = p.toLowerCase();
8267             var  m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8268             if(!m){
8269                throw  "Element.alignTo with an invalid alignment " + p;
8270             }
8271
8272             p1 = m[1]; p2 = m[2]; c = !!m[3];
8273
8274             //Subtract the aligned el's internal xy from the target's offset xy
8275             //plus custom offset to get the aligned el's new offset xy
8276             var  a1 = this.getAnchorXY(p1, true);
8277             var  a2 = el.getAnchorXY(p2, false);
8278             var  x = a2[0] - a1[0] + o[0];
8279             var  y = a2[1] - a1[1] + o[1];
8280             if(c){
8281                 //constrain the aligned el to viewport if necessary
8282                 var  w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8283                 // 5px of margin for ie
8284                 var  dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8285
8286                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8287                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8288                 //otherwise swap the aligned el to the opposite border of the target.
8289                 var  p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8290                var  p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8291                var  swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8292                var  swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8293
8294                var  A1 = document;
8295                var  scrollX = (A1.documentElement.scrollLeft || A1.body.scrollLeft || 0)+5;
8296                var  scrollY = (A1.documentElement.scrollTop || A1.body.scrollTop || 0)+5;
8297
8298                if((x+w) > dw + scrollX){
8299                     x = swapX ? r.left-w : dw+scrollX-w;
8300                 }
8301                if(x < scrollX){
8302                    x = swapX ? r.right : scrollX;
8303                }
8304                if((y+h) > dh + scrollY){
8305                     y = swapY ? r.top-h : dh+scrollY-h;
8306                 }
8307                if (y < scrollY){
8308                    y = swapY ? r.bottom : scrollY;
8309                }
8310             }
8311             return  [x,y];
8312         },
8313
8314         // private
8315         getConstrainToXY : function(){
8316             var  os = {top:0, left:0, bottom:0, right: 0};
8317
8318             return  function(el, Bf, Bg, Bh){
8319                 el = Roo.get(el);
8320                 Bg = Bg ? Roo.applyIf(Bg, os) : os;
8321
8322                 var  vw, vh, vx = 0, vy = 0;
8323                 if(el.dom == document.body || el.dom == document){
8324                     vw = Roo.lib.Dom.getViewWidth();
8325                     vh = Roo.lib.Dom.getViewHeight();
8326                 }else {
8327                     vw = el.dom.clientWidth;
8328                     vh = el.dom.clientHeight;
8329                     if(!Bf){
8330                         var  vxy = el.getXY();
8331                         vx = vxy[0];
8332                         vy = vxy[1];
8333                     }
8334                 }
8335
8336                 var  s = el.getScroll();
8337
8338                 vx += Bg.left + s.left;
8339                 vy += Bg.top + s.top;
8340
8341                 vw -= Bg.right;
8342                 vh -= Bg.bottom;
8343
8344                 var  vr = vx+vw;
8345                 var  vb = vy+vh;
8346
8347                 var  xy = Bh || (!Bf ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8348                 var  x = xy[0], y = xy[1];
8349                 var  w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8350
8351                 // only move it if it needs it
8352                 var  Bi = false;
8353
8354                 // first validate right/bottom
8355                 if((x + w) > vr){
8356                     x = vr - w;
8357                     Bi = true;
8358                 }
8359                 if((y + h) > vb){
8360                     y = vb - h;
8361                     Bi = true;
8362                 }
8363                 // then make sure top/left isn't negative
8364                 if(x < vx){
8365                     x = vx;
8366                     Bi = true;
8367                 }
8368                 if(y < vy){
8369                     y = vy;
8370                     Bi = true;
8371                 }
8372                 return  Bi ? [x, y] : false;
8373             };
8374         }(),
8375
8376         // private
8377         adjustForConstraints : function(xy, Bf, Bg){
8378             return  this.getConstrainToXY(Bf || document, false, Bg, xy) ||  xy;
8379         },
8380
8381         /**
8382          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8383          * document it aligns it to the viewport.
8384          * The position parameter is optional, and can be specified in any one of the following formats:
8385          * <ul>
8386          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8387          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8388          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8389          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8390          *   <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
8391          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8392          * </ul>
8393          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8394          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8395          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8396          * that specified in order to enforce the viewport constraints.
8397          * Following are all of the supported anchor positions:
8398     <pre>
8399     Value  Description
8400     -----  -----------------------------
8401     tl     The top left corner (default)
8402     t      The center of the top edge
8403     tr     The top right corner
8404     l      The center of the left edge
8405     c      In the center of the element
8406     r      The center of the right edge
8407     bl     The bottom left corner
8408     b      The center of the bottom edge
8409     br     The bottom right corner
8410     </pre>
8411     Example Usage:
8412     <pre><code>
8413     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8414     el.alignTo("other-el");
8415
8416     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8417     el.alignTo("other-el", "tr?");
8418
8419     // align the bottom right corner of el with the center left edge of other-el
8420     el.alignTo("other-el", "br-l?");
8421
8422     // align the center of el with the bottom left corner of other-el and
8423     // adjust the x position by -6 pixels (and the y position by 0)
8424     el.alignTo("other-el", "c-bl", [-6, 0]);
8425     </code></pre>
8426          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8427          * @param {String} position The position to align to.
8428          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8429          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8430          * @return {Roo.Element} this
8431          */
8432         alignTo : function(Bh, Bi, Bj, Bk){
8433             var  xy = this.getAlignToXY(Bh, Bi, Bj);
8434             this.setXY(xy, this.preanim(arguments, 3));
8435             return  this;
8436         },
8437
8438         /**
8439          * Anchors an element to another element and realigns it when the window is resized.
8440          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8441          * @param {String} position The position to align to.
8442          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8443          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8444          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8445          * is a number, it is used as the buffer delay (defaults to 50ms).
8446          * @param {Function} callback The function to call after the animation finishes
8447          * @return {Roo.Element} this
8448          */
8449         anchorTo : function(el, Bl, Bm, Bn, Bo, Bp){
8450             var  Bq = function(){
8451                 this.alignTo(el, Bl, Bm, Bn);
8452                 Roo.callback(Bp, this);
8453             };
8454             Roo.EventManager.onWindowResize(Bq, this);
8455             var  tm = typeof  Bo;
8456             if(tm != 'undefined'){
8457                 Roo.EventManager.on(window, 'scroll', Bq, this,
8458                     {buffer: tm == 'number' ? Bo : 50});
8459             }
8460
8461             Bq.call(this); // align immediately
8462             return  this;
8463         },
8464         /**
8465          * Clears any opacity settings from this element. Required in some cases for IE.
8466          * @return {Roo.Element} this
8467          */
8468         clearOpacity : function(){
8469             if (window.ActiveXObject) {
8470                 if(typeof  this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8471                     this.dom.style.filter = "";
8472                 }
8473             } else  {
8474                 this.dom.style.opacity = "";
8475                 this.dom.style["-moz-opacity"] = "";
8476                 this.dom.style["-khtml-opacity"] = "";
8477             }
8478             return  this;
8479         },
8480
8481         /**
8482          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8483          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8484          * @return {Roo.Element} this
8485          */
8486         hide : function(Br){
8487             this.setVisible(false, this.preanim(arguments, 0));
8488             return  this;
8489         },
8490
8491         /**
8492         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8493         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8494          * @return {Roo.Element} this
8495          */
8496         show : function(Bs){
8497             this.setVisible(true, this.preanim(arguments, 0));
8498             return  this;
8499         },
8500
8501         /**
8502          * @private Test if size has a unit, otherwise appends the default
8503          */
8504         addUnits : function(Bt){
8505             return  Roo.Element.addUnits(Bt, this.defaultUnit);
8506         },
8507
8508         /**
8509          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8510          * @return {Roo.Element} this
8511          */
8512         beginMeasure : function(){
8513             var  el = this.dom;
8514             if(el.offsetWidth || el.offsetHeight){
8515                 return  this; // offsets work already
8516             }
8517             var  Bu = [];
8518             var  p = this.dom, b = document.body; // start with this element
8519             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8520                 var  pe = Roo.get(p);
8521                 if(pe.getStyle('display') == 'none'){
8522                     Bu.push({el: p, visibility: pe.getStyle("visibility")});
8523                     p.style.visibility = "hidden";
8524                     p.style.display = "block";
8525                 }
8526
8527                 p = p.parentNode;
8528             }
8529
8530             this._measureChanged = Bu;
8531             return  this;
8532
8533         },
8534
8535         /**
8536          * Restores displays to before beginMeasure was called
8537          * @return {Roo.Element} this
8538          */
8539         endMeasure : function(){
8540             var  Bv = this._measureChanged;
8541             if(Bv){
8542                 for(var  i = 0, Ak = Bv.length; i < Ak; i++) {
8543                     var  r = Bv[i];
8544                     r.el.style.visibility = r.visibility;
8545                     r.el.style.display = "none";
8546                 }
8547
8548                 this._measureChanged = null;
8549             }
8550             return  this;
8551         },
8552
8553         /**
8554         * Update the innerHTML of this element, optionally searching for and processing scripts
8555         * @param {String} html The new HTML
8556         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8557         * @param {Function} callback For async script loading you can be noticed when the update completes
8558         * @return {Roo.Element} this
8559          */
8560         update : function(Bw, Bx, By){
8561             if(typeof  Bw == "undefined"){
8562                 Bw = "";
8563             }
8564             if(Bx !== true){
8565                 this.dom.innerHTML = Bw;
8566                 if(typeof  By == "function"){
8567                     By();
8568                 }
8569                 return  this;
8570             }
8571             var  id = Roo.id();
8572             var  Bz = this.dom;
8573
8574             Bw += '<span id="' + id + '"></span>';
8575
8576             E.onAvailable(id, function(){
8577                 var  hd = document.getElementsByTagName("head")[0];
8578                 var  re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8579                 var  B0 = /\ssrc=([\'\"])(.*?)\1/i;
8580                 var  B1 = /\stype=([\'\"])(.*?)\1/i;
8581
8582                 var  B2;
8583                 while(B2 = re.exec(Bw)){
8584                     var  attrs = B2[1];
8585                     var  srcMatch = attrs ? attrs.match(B0) : false;
8586                     if(srcMatch && srcMatch[2]){
8587                        var  s = document.createElement("script");
8588                        s.src = srcMatch[2];
8589                        var  typeMatch = attrs.match(B1);
8590                        if(typeMatch && typeMatch[2]){
8591                            s.type = typeMatch[2];
8592                        }
8593
8594                        hd.appendChild(s);
8595                     }else  if(B2[2] && B2[2].length > 0){
8596                         if(window.execScript) {
8597                            window.execScript(B2[2]);
8598                         } else  {
8599                             /**
8600                              * eval:var:id
8601                              * eval:var:dom
8602                              * eval:var:html
8603                              * 
8604                              */
8605                            window.eval(B2[2]);
8606                         }
8607                     }
8608                 }
8609                 var  el = document.getElementById(id);
8610                 if(el){el.parentNode.removeChild(el);}
8611                 if(typeof  By == "function"){
8612                     By();
8613                 }
8614             });
8615             Bz.innerHTML = Bw.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8616             return  this;
8617         },
8618
8619         /**
8620          * Direct access to the UpdateManager update() method (takes the same parameters).
8621          * @param {String/Function} url The url for this request or a function to call to get the url
8622          * @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}
8623          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8624          * @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.
8625          * @return {Roo.Element} this
8626          */
8627         load : function(){
8628             var  um = this.getUpdateManager();
8629             um.update.apply(um, arguments);
8630             return  this;
8631         },
8632
8633         /**
8634         * Gets this element's UpdateManager
8635         * @return {Roo.UpdateManager} The UpdateManager
8636         */
8637         getUpdateManager : function(){
8638             if(!this.updateManager){
8639                 this.updateManager = new  Roo.UpdateManager(this);
8640             }
8641             return  this.updateManager;
8642         },
8643
8644         /**
8645          * Disables text selection for this element (normalized across browsers)
8646          * @return {Roo.Element} this
8647          */
8648         unselectable : function(){
8649             this.dom.unselectable = "on";
8650             this.swallowEvent("selectstart", true);
8651             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8652             this.addClass("x-unselectable");
8653             return  this;
8654         },
8655
8656         /**
8657         * Calculates the x, y to center this element on the screen
8658         * @return {Array} The x, y values [x, y]
8659         */
8660         getCenterXY : function(){
8661             return  this.getAlignToXY(document, 'c-c');
8662         },
8663
8664         /**
8665         * Centers the Element in either the viewport, or another Element.
8666         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8667         */
8668         center : function(B0){
8669             this.alignTo(B0 || document, 'c-c');
8670             return  this;
8671         },
8672
8673         /**
8674          * Tests various css rules/browsers to determine if this element uses a border box
8675          * @return {Boolean}
8676          */
8677         isBorderBox : function(){
8678             return  I[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8679         },
8680
8681         /**
8682          * Return a box {x, y, width, height} that can be used to set another elements
8683          * size/location to match this element.
8684          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8685          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8686          * @return {Object} box An object in the format {x, y, width, height}
8687          */
8688         getBox : function(B1, B2){
8689             var  xy;
8690             if(!B2){
8691                 xy = this.getXY();
8692             }else {
8693                 var  BY = parseInt(this.getStyle("left"), 10) || 0;
8694                 var  BZ = parseInt(this.getStyle("top"), 10) || 0;
8695                 xy = [BY, BZ];
8696             }
8697             var  el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8698             if(!B1){
8699                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8700             }else {
8701                 var  l = this.getBorderWidth("l")+this.getPadding("l");
8702                 var  r = this.getBorderWidth("r")+this.getPadding("r");
8703                 var  t = this.getBorderWidth("t")+this.getPadding("t");
8704                 var  b = this.getBorderWidth("b")+this.getPadding("b");
8705                 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)};
8706             }
8707
8708             bx.right = bx.x + bx.width;
8709             bx.bottom = bx.y + bx.height;
8710             return  bx;
8711         },
8712
8713         /**
8714          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8715          for more information about the sides.
8716          * @param {String} sides
8717          * @return {Number}
8718          */
8719         getFrameWidth : function(B3, B4){
8720             return  B4 && Roo.isBorderBox ? 0 : (this.getPadding(B3) + this.getBorderWidth(B3));
8721         },
8722
8723         /**
8724          * 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.
8725          * @param {Object} box The box to fill {x, y, width, height}
8726          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8727          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8728          * @return {Roo.Element} this
8729          */
8730         setBox : function(B5, B6, B7){
8731             var  w = B5.width, h = B5.height;
8732             if((B6 && !this.autoBoxAdjust) && !this.isBorderBox()){
8733                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8734                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8735             }
8736
8737             this.setBounds(B5.x, B5.y, w, h, this.preanim(arguments, 2));
8738             return  this;
8739         },
8740
8741         /**
8742          * Forces the browser to repaint this element
8743          * @return {Roo.Element} this
8744          */
8745          repaint : function(){
8746             var  B8 = this.dom;
8747             this.addClass("x-repaint");
8748             setTimeout(function(){
8749                 Roo.get(B8).removeClass("x-repaint");
8750             }, 1);
8751             return  this;
8752         },
8753
8754         /**
8755          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8756          * then it returns the calculated width of the sides (see getPadding)
8757          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8758          * @return {Object/Number}
8759          */
8760         getMargins : function(B9){
8761             if(!B9){
8762                 return  {
8763                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8764                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8765                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8766                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8767                 };
8768             }else {
8769                 return  this.addStyles(B9, El.margins);
8770              }
8771         },
8772
8773         // private
8774         addStyles : function(CA, CB){
8775             var  CC = 0, v, w;
8776             for(var  i = 0, Ak = CA.length; i < Ak; i++){
8777                 v = this.getStyle(CB[CA.charAt(i)]);
8778                 if(v){
8779                      w = parseInt(v, 10);
8780                      if(w){ CC += w; }
8781                 }
8782             }
8783             return  CC;
8784         },
8785
8786         /**
8787          * Creates a proxy element of this element
8788          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8789          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8790          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8791          * @return {Roo.Element} The new proxy element
8792          */
8793         createProxy : function(CD, CE, CF){
8794             if(CE){
8795                 CE = Roo.getDom(CE);
8796             }else {
8797                 CE = document.body;
8798             }
8799
8800             CD = typeof  CD == "object" ?
8801                 CD : {tag : "div", cls: CD};
8802             var  CG = Roo.DomHelper.append(CE, CD, true);
8803             if(CF){
8804                CG.setBox(this.getBox());
8805             }
8806             return  CG;
8807         },
8808
8809         /**
8810          * Puts a mask over this element to disable user interaction. Requires core.css.
8811          * This method can only be applied to elements which accept child nodes.
8812          * @param {String} msg (optional) A message to display in the mask
8813          * @param {String} msgCls (optional) A css class to apply to the msg element
8814          * @return {Element} The mask  element
8815          */
8816         mask : function(CH, CI){
8817             if(this.getStyle("position") == "static"){
8818                 this.setStyle("position", "relative");
8819             }
8820             if(!this._mask){
8821                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8822             }
8823
8824             this.addClass("x-masked");
8825             this._mask.setDisplayed(true);
8826             if(typeof  CH == 'string'){
8827                 if(!this._maskMsg){
8828                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8829                 }
8830                 var  mm = this._maskMsg;
8831                 mm.dom.className = CI ? "roo-el-mask-msg " + CI : "roo-el-mask-msg";
8832                 mm.dom.firstChild.innerHTML = CH;
8833                 mm.setDisplayed(true);
8834                 mm.center(this);
8835             }
8836             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8837                 this._mask.setHeight(this.getHeight());
8838             }
8839             return  this._mask;
8840         },
8841
8842         /**
8843          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8844          * it is cached for reuse.
8845          */
8846         unmask : function(CJ){
8847             if(this._mask){
8848                 if(CJ === true){
8849                     this._mask.remove();
8850                     delete  this._mask;
8851                     if(this._maskMsg){
8852                         this._maskMsg.remove();
8853                         delete  this._maskMsg;
8854                     }
8855                 }else {
8856                     this._mask.setDisplayed(false);
8857                     if(this._maskMsg){
8858                         this._maskMsg.setDisplayed(false);
8859                     }
8860                 }
8861             }
8862
8863             this.removeClass("x-masked");
8864         },
8865
8866         /**
8867          * Returns true if this element is masked
8868          * @return {Boolean}
8869          */
8870         isMasked : function(){
8871             return  this._mask && this._mask.isVisible();
8872         },
8873
8874         /**
8875          * Creates an iframe shim for this element to keep selects and other windowed objects from
8876          * showing through.
8877          * @return {Roo.Element} The new shim element
8878          */
8879         createShim : function(){
8880             var  el = document.createElement('iframe');
8881             el.frameBorder = 'no';
8882             el.className = 'roo-shim';
8883             if(Roo.isIE && Roo.isSecure){
8884                 el.src = Roo.SSL_SECURE_URL;
8885             }
8886             var  CK = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8887             CK.autoBoxAdjust = false;
8888             return  CK;
8889         },
8890
8891         /**
8892          * Removes this element from the DOM and deletes it from the cache
8893          */
8894         remove : function(){
8895             if(this.dom.parentNode){
8896                 this.dom.parentNode.removeChild(this.dom);
8897             }
8898             delete  El.cache[this.dom.id];
8899         },
8900
8901         /**
8902          * Sets up event handlers to add and remove a css class when the mouse is over this element
8903          * @param {String} className
8904          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8905          * mouseout events for children elements
8906          * @return {Roo.Element} this
8907          */
8908         addClassOnOver : function(CL, CM){
8909             this.on("mouseover", function(){
8910                 Roo.fly(this, '_internal').addClass(CL);
8911             }, this.dom);
8912             var  CN = function(e){
8913                 if(CM !== true || !e.within(this, true)){
8914                     Roo.fly(this, '_internal').removeClass(CL);
8915                 }
8916             };
8917             this.on("mouseout", CN, this.dom);
8918             return  this;
8919         },
8920
8921         /**
8922          * Sets up event handlers to add and remove a css class when this element has the focus
8923          * @param {String} className
8924          * @return {Roo.Element} this
8925          */
8926         addClassOnFocus : function(CO){
8927             this.on("focus", function(){
8928                 Roo.fly(this, '_internal').addClass(CO);
8929             }, this.dom);
8930             this.on("blur", function(){
8931                 Roo.fly(this, '_internal').removeClass(CO);
8932             }, this.dom);
8933             return  this;
8934         },
8935         /**
8936          * 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)
8937          * @param {String} className
8938          * @return {Roo.Element} this
8939          */
8940         addClassOnClick : function(CP){
8941             var  CQ = this.dom;
8942             this.on("mousedown", function(){
8943                 Roo.fly(CQ, '_internal').addClass(CP);
8944                 var  d = Roo.get(document);
8945                 var  fn = function(){
8946                     Roo.fly(CQ, '_internal').removeClass(CP);
8947                     d.removeListener("mouseup", fn);
8948                 };
8949                 d.on("mouseup", fn);
8950             });
8951             return  this;
8952         },
8953
8954         /**
8955          * Stops the specified event from bubbling and optionally prevents the default action
8956          * @param {String} eventName
8957          * @param {Boolean} preventDefault (optional) true to prevent the default action too
8958          * @return {Roo.Element} this
8959          */
8960         swallowEvent : function(CR, CS){
8961             var  fn = function(e){
8962                 e.stopPropagation();
8963                 if(CS){
8964                     e.preventDefault();
8965                 }
8966             };
8967             if(CR  instanceof  Array){
8968                 for(var  i = 0, Ak = CR.length; i < Ak; i++){
8969                      this.on(CR[i], fn);
8970                 }
8971                 return  this;
8972             }
8973
8974             this.on(CR, fn);
8975             return  this;
8976         },
8977
8978         /**
8979          * @private
8980          */
8981       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8982
8983         /**
8984          * Sizes this element to its parent element's dimensions performing
8985          * neccessary box adjustments.
8986          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8987          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8988          * @return {Roo.Element} this
8989          */
8990         fitToParent : function(CT, CU) {
8991           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8992           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8993           if (CT === true && !this.dom.parentNode) { // check if this Element still exists
8994             return;
8995           }
8996           var  p = Roo.get(CU || this.dom.parentNode);
8997           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8998           if (CT === true) {
8999             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, CU]);
9000             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9001           }
9002           return  this;
9003         },
9004
9005         /**
9006          * Gets the next sibling, skipping text nodes
9007          * @return {HTMLElement} The next sibling or null
9008          */
9009         getNextSibling : function(){
9010             var  n = this.dom.nextSibling;
9011             while(n && n.nodeType != 1){
9012                 n = n.nextSibling;
9013             }
9014             return  n;
9015         },
9016
9017         /**
9018          * Gets the previous sibling, skipping text nodes
9019          * @return {HTMLElement} The previous sibling or null
9020          */
9021         getPrevSibling : function(){
9022             var  n = this.dom.previousSibling;
9023             while(n && n.nodeType != 1){
9024                 n = n.previousSibling;
9025             }
9026             return  n;
9027         },
9028
9029
9030         /**
9031          * Appends the passed element(s) to this element
9032          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9033          * @return {Roo.Element} this
9034          */
9035         appendChild: function(el){
9036             el = Roo.get(el);
9037             el.appendTo(this);
9038             return  this;
9039         },
9040
9041         /**
9042          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9043          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9044          * automatically generated with the specified attributes.
9045          * @param {HTMLElement} insertBefore (optional) a child element of this element
9046          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9047          * @return {Roo.Element} The new child element
9048          */
9049         createChild: function(CV, CW, CX){
9050             CV = CV || {tag:'div'};
9051             if(CW){
9052                 return  Roo.DomHelper.insertBefore(CW, CV, CX !== true);
9053             }
9054             return  Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, CV,  CX !== true);
9055         },
9056
9057         /**
9058          * Appends this element to the passed element
9059          * @param {String/HTMLElement/Element} el The new parent element
9060          * @return {Roo.Element} this
9061          */
9062         appendTo: function(el){
9063             el = Roo.getDom(el);
9064             el.appendChild(this.dom);
9065             return  this;
9066         },
9067
9068         /**
9069          * Inserts this element before the passed element in the DOM
9070          * @param {String/HTMLElement/Element} el The element to insert before
9071          * @return {Roo.Element} this
9072          */
9073         insertBefore: function(el){
9074             el = Roo.getDom(el);
9075             el.parentNode.insertBefore(this.dom, el);
9076             return  this;
9077         },
9078
9079         /**
9080          * Inserts this element after the passed element in the DOM
9081          * @param {String/HTMLElement/Element} el The element to insert after
9082          * @return {Roo.Element} this
9083          */
9084         insertAfter: function(el){
9085             el = Roo.getDom(el);
9086             el.parentNode.insertBefore(this.dom, el.nextSibling);
9087             return  this;
9088         },
9089
9090         /**
9091          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9092          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9093          * @return {Roo.Element} The new child
9094          */
9095         insertFirst: function(el, CY){
9096             el = el || {};
9097             if(typeof  el == 'object' && !el.nodeType){ // dh config
9098                 return  this.createChild(el, this.dom.firstChild, CY);
9099             }else {
9100                 el = Roo.getDom(el);
9101                 this.dom.insertBefore(el, this.dom.firstChild);
9102                 return  !CY ? Roo.get(el) : el;
9103             }
9104         },
9105
9106         /**
9107          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9108          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9109          * @param {String} where (optional) 'before' or 'after' defaults to before
9110          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9111          * @return {Roo.Element} the inserted Element
9112          */
9113         insertSibling: function(el, CZ, Ca){
9114             CZ = CZ ? CZ.toLowerCase() : 'before';
9115             el = el || {};
9116             var  rt, Cb = CZ == 'before' ? this.dom : this.dom.nextSibling;
9117
9118             if(typeof  el == 'object' && !el.nodeType){ // dh config
9119                 if(CZ == 'after' && !this.dom.nextSibling){
9120                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !Ca);
9121                 }else {
9122                     rt = Roo.DomHelper[CZ == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !Ca);
9123                 }
9124
9125             }else {
9126                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9127                             CZ == 'before' ? this.dom : this.dom.nextSibling);
9128                 if(!Ca){
9129                     rt = Roo.get(rt);
9130                 }
9131             }
9132             return  rt;
9133         },
9134
9135         /**
9136          * Creates and wraps this element with another element
9137          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9138          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9139          * @return {HTMLElement/Element} The newly created wrapper element
9140          */
9141         wrap: function(Cc, Cd){
9142             if(!Cc){
9143                 Cc = {tag: "div"};
9144             }
9145             var  Ce = Roo.DomHelper.insertBefore(this.dom, Cc, !Cd);
9146             Ce.dom ? Ce.dom.appendChild(this.dom) : Ce.appendChild(this.dom);
9147             return  Ce;
9148         },
9149
9150         /**
9151          * Replaces the passed element with this element
9152          * @param {String/HTMLElement/Element} el The element to replace
9153          * @return {Roo.Element} this
9154          */
9155         replace: function(el){
9156             el = Roo.get(el);
9157             this.insertBefore(el);
9158             el.remove();
9159             return  this;
9160         },
9161
9162         /**
9163          * Inserts an html fragment into this element
9164          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9165          * @param {String} html The HTML fragment
9166          * @param {Boolean} returnEl True to return an Roo.Element
9167          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9168          */
9169         insertHtml : function(Cf, Cg, Ch){
9170             var  el = Roo.DomHelper.insertHtml(Cf, this.dom, Cg);
9171             return  Ch ? Roo.get(el) : el;
9172         },
9173
9174         /**
9175          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9176          * @param {Object} o The object with the attributes
9177          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9178          * @return {Roo.Element} this
9179          */
9180         set : function(o, Ci){
9181             var  el = this.dom;
9182             Ci = typeof  Ci == 'undefined' ? (el.setAttribute ? true : false) : Ci;
9183             for(var  attr  in  o){
9184                 if(attr == "style" || typeof  o[attr] == "function") continue;
9185                 if(attr=="cls"){
9186                     el.className = o["cls"];
9187                 }else {
9188                     if(Ci) el.setAttribute(attr, o[attr]);
9189                     else  el[attr] = o[attr];
9190                 }
9191             }
9192             if(o.style){
9193                 Roo.DomHelper.applyStyles(el, o.style);
9194             }
9195             return  this;
9196         },
9197
9198         /**
9199          * Convenience method for constructing a KeyMap
9200          * @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:
9201          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9202          * @param {Function} fn The function to call
9203          * @param {Object} scope (optional) The scope of the function
9204          * @return {Roo.KeyMap} The KeyMap created
9205          */
9206         addKeyListener : function(Cj, fn, Ck){
9207             var  Cl;
9208             if(typeof  Cj != "object" || Cj  instanceof  Array){
9209                 Cl = {
9210                     key: Cj,
9211                     fn: fn,
9212                     scope: Ck
9213                 };
9214             }else {
9215                 Cl = {
9216                     key : Cj.key,
9217                     shift : Cj.shift,
9218                     ctrl : Cj.ctrl,
9219                     alt : Cj.alt,
9220                     fn: fn,
9221                     scope: Ck
9222                 };
9223             }
9224             return  new  Roo.KeyMap(this, Cl);
9225         },
9226
9227         /**
9228          * Creates a KeyMap for this element
9229          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9230          * @return {Roo.KeyMap} The KeyMap created
9231          */
9232         addKeyMap : function(Cm){
9233             return  new  Roo.KeyMap(this, Cm);
9234         },
9235
9236         /**
9237          * Returns true if this element is scrollable.
9238          * @return {Boolean}
9239          */
9240          isScrollable : function(){
9241             var  Cn = this.dom;
9242             return  Cn.scrollHeight > Cn.clientHeight || Cn.scrollWidth > Cn.clientWidth;
9243         },
9244
9245         /**
9246          * 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().
9247          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9248          * @param {Number} value The new scroll value
9249          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9250          * @return {Element} this
9251          */
9252
9253         scrollTo : function(Co, Cp, Cq){
9254             var  Cr = Co.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9255             if(!Cq || !A){
9256                 this.dom[Cr] = Cp;
9257             }else {
9258                 var  to = Cr == "scrollLeft" ? [Cp, this.dom.scrollTop] : [this.dom.scrollLeft, Cp];
9259                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9260             }
9261             return  this;
9262         },
9263
9264         /**
9265          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9266          * within this element's scrollable range.
9267          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9268          * @param {Number} distance How far to scroll the element in pixels
9269          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9270          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9271          * was scrolled as far as it could go.
9272          */
9273          scroll : function(Cs, Ct, Cu){
9274              if(!this.isScrollable()){
9275                  return;
9276              }
9277              var  el = this.dom;
9278              var  l = el.scrollLeft, t = el.scrollTop;
9279              var  w = el.scrollWidth, h = el.scrollHeight;
9280              var  cw = el.clientWidth, ch = el.clientHeight;
9281              Cs = Cs.toLowerCase();
9282              var  Cv = false;
9283              var  a = this.preanim(arguments, 2);
9284              switch(Cs){
9285                  case  "l":
9286                  case  "left":
9287                      if(w - l > cw){
9288                          var  v = Math.min(l + Ct, w-cw);
9289                          this.scrollTo("left", v, a);
9290                          Cv = true;
9291                      }
9292                      break;
9293                 case  "r":
9294                 case  "right":
9295                      if(l > 0){
9296                          var  v = Math.max(l - Ct, 0);
9297                          this.scrollTo("left", v, a);
9298                          Cv = true;
9299                      }
9300                      break;
9301                 case  "t":
9302                 case  "top":
9303                 case  "up":
9304                      if(t > 0){
9305                          var  v = Math.max(t - Ct, 0);
9306                          this.scrollTo("top", v, a);
9307                          Cv = true;
9308                      }
9309                      break;
9310                 case  "b":
9311                 case  "bottom":
9312                 case  "down":
9313                      if(h - t > ch){
9314                          var  v = Math.min(t + Ct, h-ch);
9315                          this.scrollTo("top", v, a);
9316                          Cv = true;
9317                      }
9318                      break;
9319              }
9320              return  Cv;
9321         },
9322
9323         /**
9324          * Translates the passed page coordinates into left/top css values for this element
9325          * @param {Number/Array} x The page x or an array containing [x, y]
9326          * @param {Number} y The page y
9327          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9328          */
9329         translatePoints : function(x, y){
9330             if(typeof  x == 'object' || x  instanceof  Array){
9331                 y = x[1]; x = x[0];
9332             }
9333             var  p = this.getStyle('position');
9334             var  o = this.getXY();
9335
9336             var  l = parseInt(this.getStyle('left'), 10);
9337             var  t = parseInt(this.getStyle('top'), 10);
9338
9339             if(isNaN(l)){
9340                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9341             }
9342             if(isNaN(t)){
9343                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9344             }
9345
9346             return  {left: (x - o[0] + l), top: (y - o[1] + t)};
9347         },
9348
9349         /**
9350          * Returns the current scroll position of the element.
9351          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9352          */
9353         getScroll : function(){
9354             var  d = this.dom, Cw = document;
9355             if(d == Cw || d == Cw.body){
9356                 var  l = window.pageXOffset || Cw.documentElement.scrollLeft || Cw.body.scrollLeft || 0;
9357                 var  t = window.pageYOffset || Cw.documentElement.scrollTop || Cw.body.scrollTop || 0;
9358                 return  {left: l, top: t};
9359             }else {
9360                 return  {left: d.scrollLeft, top: d.scrollTop};
9361             }
9362         },
9363
9364         /**
9365          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9366          * are convert to standard 6 digit hex color.
9367          * @param {String} attr The css attribute
9368          * @param {String} defaultValue The default value to use when a valid color isn't found
9369          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9370          * YUI color anims.
9371          */
9372         getColor : function(Cx, Cy, Cz){
9373             var  v = this.getStyle(Cx);
9374             if(!v || v == "transparent" || v == "inherit") {
9375                 return  Cy;
9376             }
9377             var  C0 = typeof  Cz == "undefined" ? "#" : Cz;
9378             if(v.substr(0, 4) == "rgb("){
9379                 var  rvs = v.slice(4, v.length -1).split(",");
9380                 for(var  i = 0; i < 3; i++){
9381                     var  h = parseInt(rvs[i]).toString(16);
9382                     if(h < 16){
9383                         h = "0" + h;
9384                     }
9385
9386                     C0 += h;
9387                 }
9388             } else  {
9389                 if(v.substr(0, 1) == "#"){
9390                     if(v.length == 4) {
9391                         for(var  i = 1; i < 4; i++){
9392                             var  c = v.charAt(i);
9393                             C0 +=  c + c;
9394                         }
9395                     }else  if(v.length == 7){
9396                         C0 += v.substr(1);
9397                     }
9398                 }
9399             }
9400             return (C0.length > 5 ? C0.toLowerCase() : Cy);
9401         },
9402
9403         /**
9404          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9405          * gradient background, rounded corners and a 4-way shadow.
9406          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9407          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9408          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9409          * @return {Roo.Element} this
9410          */
9411         boxWrap : function(C1){
9412             C1 = C1 || 'x-box';
9413             var  el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', C1)));
9414             el.child('.'+C1+'-mc').dom.appendChild(this.dom);
9415             return  el;
9416         },
9417
9418         /**
9419          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9420          * @param {String} namespace The namespace in which to look for the attribute
9421          * @param {String} name The attribute name
9422          * @return {String} The attribute value
9423          */
9424         getAttributeNS : Roo.isIE ? function(ns, C2){
9425             var  d = this.dom;
9426             var  C3 = typeof  d[ns+":"+C2];
9427             if(C3 != 'undefined' && C3 != 'unknown'){
9428                 return  d[ns+":"+C2];
9429             }
9430             return  d[C2];
9431         } : function(ns, C4){
9432             var  d = this.dom;
9433             return  d.getAttributeNS(ns, C4) || d.getAttribute(ns+":"+C4) || d.getAttribute(C4) || d[C4];
9434         }
9435     };
9436
9437     var  ep = El.prototype;
9438
9439     /**
9440      * Appends an event handler (Shorthand for addListener)
9441      * @param {String}   eventName     The type of event to append
9442      * @param {Function} fn        The method the event invokes
9443      * @param {Object} scope       (optional) The scope (this object) of the fn
9444      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9445      * @method
9446      */
9447     ep.on = ep.addListener;
9448         // backwards compat
9449     ep.mon = ep.addListener;
9450
9451     /**
9452      * Removes an event handler from this element (shorthand for removeListener)
9453      * @param {String} eventName the type of event to remove
9454      * @param {Function} fn the method the event invokes
9455      * @return {Roo.Element} this
9456      * @method
9457      */
9458     ep.un = ep.removeListener;
9459
9460     /**
9461      * true to automatically adjust width and height settings for box-model issues (default to true)
9462      */
9463     ep.autoBoxAdjust = true;
9464
9465     // private
9466     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9467
9468     // private
9469     El.addUnits = function(v, J){
9470         if(v === "" || v == "auto"){
9471             return  v;
9472         }
9473         if(v === undefined){
9474             return  '';
9475         }
9476         if(typeof  v == "number" || !El.unitPattern.test(v)){
9477             return  v + (J || 'px');
9478         }
9479         return  v;
9480     };
9481
9482     // special markup used throughout Roo when box wrapping elements
9483     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>';
9484     /**
9485      * Visibility mode constant - Use visibility to hide element
9486      * @static
9487      * @type Number
9488      */
9489     El.VISIBILITY = 1;
9490     /**
9491      * Visibility mode constant - Use display to hide element
9492      * @static
9493      * @type Number
9494      */
9495     El.DISPLAY = 2;
9496
9497     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9498     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9499     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9500
9501
9502
9503     /**
9504      * @private
9505      */
9506     El.cache = {};
9507
9508     var  H;
9509
9510     /**
9511      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9512      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9513      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9514      * @return {Element} The Element object
9515      * @static
9516      */
9517     El.get = function(el){
9518         var  ex, J, id;
9519         if(!el){ return  null; }
9520         if(typeof  el == "string"){ // element id
9521             if(!(J = document.getElementById(el))){
9522                 return  null;
9523             }
9524             if(ex = El.cache[el]){
9525                 ex.dom = J;
9526             }else {
9527                 ex = El.cache[el] = new  El(J);
9528             }
9529             return  ex;
9530         }else  if(el.tagName){ // dom element
9531             if(!(id = el.id)){
9532                 id = Roo.id(el);
9533             }
9534             if(ex = El.cache[id]){
9535                 ex.dom = el;
9536             }else {
9537                 ex = El.cache[id] = new  El(el);
9538             }
9539             return  ex;
9540         }else  if(el  instanceof  El){
9541             if(el != H){
9542                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9543                                                               // catch case where it hasn't been appended
9544                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9545             }
9546             return  el;
9547         }else  if(el.isComposite){
9548             return  el;
9549         }else  if(el  instanceof  Array){
9550             return  El.select(el);
9551         }else  if(el == document){
9552             // create a bogus element object representing the document object
9553             if(!H){
9554                 var  f = function(){};
9555                 f.prototype = El.prototype;
9556                 H = new  f();
9557                 H.dom = document;
9558             }
9559             return  H;
9560         }
9561         return  null;
9562     };
9563
9564     // private
9565     El.uncache = function(el){
9566         for(var  i = 0, a = arguments, len = a.length; i < len; i++) {
9567             if(a[i]){
9568                 delete  El.cache[a[i].id || a[i]];
9569             }
9570         }
9571     };
9572
9573     // private
9574     // Garbage collection - uncache elements/purge listeners on orphaned elements
9575     // so we don't hold a reference and cause the browser to retain them
9576     El.garbageCollect = function(){
9577         if(!Roo.enableGarbageCollector){
9578             clearInterval(El.collectorThread);
9579             return;
9580         }
9581         for(var  eid  in  El.cache){
9582             var  el = El.cache[eid], d = el.dom;
9583             // -------------------------------------------------------
9584             // Determining what is garbage:
9585             // -------------------------------------------------------
9586             // !d
9587             // dom node is null, definitely garbage
9588             // -------------------------------------------------------
9589             // !d.parentNode
9590             // no parentNode == direct orphan, definitely garbage
9591             // -------------------------------------------------------
9592             // !d.offsetParent && !document.getElementById(eid)
9593             // display none elements have no offsetParent so we will
9594             // also try to look it up by it's id. However, check
9595             // offsetParent first so we don't do unneeded lookups.
9596             // This enables collection of elements that are not orphans
9597             // directly, but somewhere up the line they have an orphan
9598             // parent.
9599             // -------------------------------------------------------
9600             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9601                 delete  El.cache[eid];
9602                 if(d && Roo.enableListenerCollection){
9603                     E.purgeElement(d);
9604                 }
9605             }
9606         }
9607     }
9608
9609     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9610
9611
9612     // dom is optional
9613     El.Flyweight = function(J){
9614         this.dom = J;
9615     };
9616     El.Flyweight.prototype = El.prototype;
9617
9618     El._flyweights = {};
9619     /**
9620      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9621      * the dom node can be overwritten by other code.
9622      * @param {String/HTMLElement} el The dom node or id
9623      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9624      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9625      * @static
9626      * @return {Element} The shared Element object
9627      */
9628     El.fly = function(el, J){
9629         J = J || '_global';
9630         el = Roo.getDom(el);
9631         if(!el){
9632             return  null;
9633         }
9634         if(!El._flyweights[J]){
9635             El._flyweights[J] = new  El.Flyweight();
9636         }
9637
9638         El._flyweights[J].dom = el;
9639         return  El._flyweights[J];
9640     };
9641
9642     /**
9643      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9644      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9645      * Shorthand of {@link Roo.Element#get}
9646      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9647      * @return {Element} The Element object
9648      * @member Roo
9649      * @method get
9650      */
9651     Roo.get = El.get;
9652     /**
9653      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9654      * the dom node can be overwritten by other code.
9655      * Shorthand of {@link Roo.Element#fly}
9656      * @param {String/HTMLElement} el The dom node or id
9657      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9658      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9659      * @static
9660      * @return {Element} The shared Element object
9661      * @member Roo
9662      * @method fly
9663      */
9664     Roo.fly = El.fly;
9665
9666     // speedy lookup for elements never to box adjust
9667     var  I = Roo.isStrict ? {
9668         select:1
9669     } : {
9670         input:1, select:1, textarea:1
9671     };
9672     if(Roo.isIE || Roo.isGecko){
9673         I['button'] = 1;
9674     }
9675
9676
9677
9678     Roo.EventManager.on(window, 'unload', function(){
9679         delete  El.cache;
9680         delete  El._flyweights;
9681     });
9682 })();
9683
9684
9685
9686
9687 if(Roo.DomQuery){
9688     Roo.Element.selectorFunction = Roo.DomQuery.select;
9689 }
9690
9691
9692 Roo.Element.select = function(J, K, L){
9693     var  M;
9694     if(typeof  J == "string"){
9695         M = Roo.Element.selectorFunction(J, L);
9696     }else  if(J.length !== undefined){
9697         M = J;
9698     }else {
9699         throw  "Invalid selector";
9700     }
9701     if(K === true){
9702         return  new  Roo.CompositeElement(M);
9703     }else {
9704         return  new  Roo.CompositeElementLite(M);
9705     }
9706 };
9707 /**
9708  * Selects elements based on the passed CSS selector to enable working on them as 1.
9709  * @param {String/Array} selector The CSS selector or an array of elements
9710  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9711  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9712  * @return {CompositeElementLite/CompositeElement}
9713  * @member Roo
9714  * @method select
9715  */
9716 Roo.select = Roo.Element.select;
9717
9718
9719
9720
9721
9722
9723
9724
9725
9726
9727
9728
9729
9730
9731
9732 /*
9733  * Based on:
9734  * Ext JS Library 1.1.1
9735  * Copyright(c) 2006-2007, Ext JS, LLC.
9736  *
9737  * Originally Released Under LGPL - original licence link has changed is not relivant.
9738  *
9739  * Fork - LGPL
9740  * <script type="text/javascript">
9741  */
9742
9743
9744
9745 //Notifies Element that fx methods are available
9746 Roo.enableFx = true;
9747
9748 /**
9749  * @class Roo.Fx
9750  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9751  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9752  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9753  * Element effects to work.</p><br/>
9754  *
9755  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9756  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9757  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9758  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9759  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9760  * expected results and should be done with care.</p><br/>
9761  *
9762  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9763  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9764 <pre>
9765 Value  Description
9766 -----  -----------------------------
9767 tl     The top left corner
9768 t      The center of the top edge
9769 tr     The top right corner
9770 l      The center of the left edge
9771 r      The center of the right edge
9772 bl     The bottom left corner
9773 b      The center of the bottom edge
9774 br     The bottom right corner
9775 </pre>
9776  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9777  * below are common options that can be passed to any Fx method.</b>
9778  * @cfg {Function} callback A function called when the effect is finished
9779  * @cfg {Object} scope The scope of the effect function
9780  * @cfg {String} easing A valid Easing value for the effect
9781  * @cfg {String} afterCls A css class to apply after the effect
9782  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9783  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9784  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9785  * effects that end with the element being visually hidden, ignored otherwise)
9786  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9787  * a function which returns such a specification that will be applied to the Element after the effect finishes
9788  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9789  * @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
9790  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9791  */
9792 Roo.Fx = {
9793         /**
9794          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9795          * origin for the slide effect.  This function automatically handles wrapping the element with
9796          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9797          * Usage:
9798          *<pre><code>
9799 // default: slide the element in from the top
9800 el.slideIn();
9801
9802 // custom: slide the element in from the right with a 2-second duration
9803 el.slideIn('r', { duration: 2 });
9804
9805 // common config options shown with default values
9806 el.slideIn('t', {
9807     easing: 'easeOut',
9808     duration: .5
9809 });
9810 </code></pre>
9811          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9812          * @param {Object} options (optional) Object literal with any of the Fx config options
9813          * @return {Roo.Element} The Element
9814          */
9815     slideIn : function(A, o){
9816         var  el = this.getFxEl();
9817         o = o || {};
9818
9819         el.queueFx(o, function(){
9820
9821             A = A || "t";
9822
9823             // fix display to visibility
9824             this.fixDisplay();
9825
9826             // restore values after effect
9827             var  r = this.getFxRestore();
9828             var  b = this.getBox();
9829             // fixed size for slide
9830             this.setSize(b);
9831
9832             // wrap if needed
9833             var  B = this.fxWrap(r.pos, o, "hidden");
9834
9835             var  st = this.dom.style;
9836             st.visibility = "visible";
9837             st.position = "absolute";
9838
9839             // clear out temp styles after slide and unwrap
9840             var  C = function(){
9841                 el.fxUnwrap(B, r.pos, o);
9842                 st.width = r.width;
9843                 st.height = r.height;
9844                 el.afterFx(o);
9845             };
9846             // time to calc the positions
9847             var  a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9848
9849             switch(A.toLowerCase()){
9850                 case  "t":
9851                     B.setSize(b.width, 0);
9852                     st.left = st.bottom = "0";
9853                     a = {height: bh};
9854                 break;
9855                 case  "l":
9856                     B.setSize(0, b.height);
9857                     st.right = st.top = "0";
9858                     a = {width: bw};
9859                 break;
9860                 case  "r":
9861                     B.setSize(0, b.height);
9862                     B.setX(b.right);
9863                     st.left = st.top = "0";
9864                     a = {width: bw, points: pt};
9865                 break;
9866                 case  "b":
9867                     B.setSize(b.width, 0);
9868                     B.setY(b.bottom);
9869                     st.left = st.top = "0";
9870                     a = {height: bh, points: pt};
9871                 break;
9872                 case  "tl":
9873                     B.setSize(0, 0);
9874                     st.right = st.bottom = "0";
9875                     a = {width: bw, height: bh};
9876                 break;
9877                 case  "bl":
9878                     B.setSize(0, 0);
9879                     B.setY(b.y+b.height);
9880                     st.right = st.top = "0";
9881                     a = {width: bw, height: bh, points: pt};
9882                 break;
9883                 case  "br":
9884                     B.setSize(0, 0);
9885                     B.setXY([b.right, b.bottom]);
9886                     st.left = st.top = "0";
9887                     a = {width: bw, height: bh, points: pt};
9888                 break;
9889                 case  "tr":
9890                     B.setSize(0, 0);
9891                     B.setX(b.x+b.width);
9892                     st.left = st.bottom = "0";
9893                     a = {width: bw, height: bh, points: pt};
9894                 break;
9895             }
9896
9897             this.dom.style.visibility = "visible";
9898             B.show();
9899
9900             arguments.callee.anim = B.fxanim(a,
9901                 o,
9902                 'motion',
9903                 .5,
9904                 'easeOut', C);
9905         });
9906         return  this;
9907     },
9908     
9909         /**
9910          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
9911          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
9912          * 'hidden') but block elements will still take up space in the document.  The element must be removed
9913          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
9914          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9915          * Usage:
9916          *<pre><code>
9917 // default: slide the element out to the top
9918 el.slideOut();
9919
9920 // custom: slide the element out to the right with a 2-second duration
9921 el.slideOut('r', { duration: 2 });
9922
9923 // common config options shown with default values
9924 el.slideOut('t', {
9925     easing: 'easeOut',
9926     duration: .5,
9927     remove: false,
9928     useDisplay: false
9929 });
9930 </code></pre>
9931          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9932          * @param {Object} options (optional) Object literal with any of the Fx config options
9933          * @return {Roo.Element} The Element
9934          */
9935     slideOut : function(B, o){
9936         var  el = this.getFxEl();
9937         o = o || {};
9938
9939         el.queueFx(o, function(){
9940
9941             B = B || "t";
9942
9943             // restore values after effect
9944             var  r = this.getFxRestore();
9945             
9946             var  b = this.getBox();
9947             // fixed size for slide
9948             this.setSize(b);
9949
9950             // wrap if needed
9951             var  C = this.fxWrap(r.pos, o, "visible");
9952
9953             var  st = this.dom.style;
9954             st.visibility = "visible";
9955             st.position = "absolute";
9956
9957             C.setSize(b);
9958
9959             var  D = function(){
9960                 if(o.useDisplay){
9961                     el.setDisplayed(false);
9962                 }else {
9963                     el.hide();
9964                 }
9965
9966
9967                 el.fxUnwrap(C, r.pos, o);
9968
9969                 st.width = r.width;
9970                 st.height = r.height;
9971
9972                 el.afterFx(o);
9973             };
9974
9975             var  a, E = {to: 0};
9976             switch(B.toLowerCase()){
9977                 case  "t":
9978                     st.left = st.bottom = "0";
9979                     a = {height: E};
9980                 break;
9981                 case  "l":
9982                     st.right = st.top = "0";
9983                     a = {width: E};
9984                 break;
9985                 case  "r":
9986                     st.left = st.top = "0";
9987                     a = {width: E, points: {to:[b.right, b.y]}};
9988                 break;
9989                 case  "b":
9990                     st.left = st.top = "0";
9991                     a = {height: E, points: {to:[b.x, b.bottom]}};
9992                 break;
9993                 case  "tl":
9994                     st.right = st.bottom = "0";
9995                     a = {width: E, height: E};
9996                 break;
9997                 case  "bl":
9998                     st.right = st.top = "0";
9999                     a = {width: E, height: E, points: {to:[b.x, b.bottom]}};
10000                 break;
10001                 case  "br":
10002                     st.left = st.top = "0";
10003                     a = {width: E, height: E, points: {to:[b.x+b.width, b.bottom]}};
10004                 break;
10005                 case  "tr":
10006                     st.left = st.bottom = "0";
10007                     a = {width: E, height: E, points: {to:[b.right, b.y]}};
10008                 break;
10009             }
10010
10011
10012             arguments.callee.anim = C.fxanim(a,
10013                 o,
10014                 'motion',
10015                 .5,
10016                 "easeOut", D);
10017         });
10018         return  this;
10019     },
10020
10021         /**
10022          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10023          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10024          * The element must be removed from the DOM using the 'remove' config option if desired.
10025          * Usage:
10026          *<pre><code>
10027 // default
10028 el.puff();
10029
10030 // common config options shown with default values
10031 el.puff({
10032     easing: 'easeOut',
10033     duration: .5,
10034     remove: false,
10035     useDisplay: false
10036 });
10037 </code></pre>
10038          * @param {Object} options (optional) Object literal with any of the Fx config options
10039          * @return {Roo.Element} The Element
10040          */
10041     puff : function(o){
10042         var  el = this.getFxEl();
10043         o = o || {};
10044
10045         el.queueFx(o, function(){
10046             this.clearOpacity();
10047             this.show();
10048
10049             // restore values after effect
10050             var  r = this.getFxRestore();
10051             var  st = this.dom.style;
10052
10053             var  C = function(){
10054                 if(o.useDisplay){
10055                     el.setDisplayed(false);
10056                 }else {
10057                     el.hide();
10058                 }
10059
10060
10061                 el.clearOpacity();
10062
10063                 el.setPositioning(r.pos);
10064                 st.width = r.width;
10065                 st.height = r.height;
10066                 st.fontSize = '';
10067                 el.afterFx(o);
10068             };
10069
10070             var  D = this.getWidth();
10071             var  E = this.getHeight();
10072
10073             arguments.callee.anim = this.fxanim({
10074                     width : {to: this.adjustWidth(D * 2)},
10075                     height : {to: this.adjustHeight(E * 2)},
10076                     points : {by: [-(D * .5), -(E * .5)]},
10077                     opacity : {to: 0},
10078                     fontSize: {to:200, unit: "%"}
10079                 },
10080                 o,
10081                 'motion',
10082                 .5,
10083                 "easeOut", C);
10084         });
10085         return  this;
10086     },
10087
10088         /**
10089          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10090          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10091          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10092          * Usage:
10093          *<pre><code>
10094 // default
10095 el.switchOff();
10096
10097 // all config options shown with default values
10098 el.switchOff({
10099     easing: 'easeIn',
10100     duration: .3,
10101     remove: false,
10102     useDisplay: false
10103 });
10104 </code></pre>
10105          * @param {Object} options (optional) Object literal with any of the Fx config options
10106          * @return {Roo.Element} The Element
10107          */
10108     switchOff : function(o){
10109         var  el = this.getFxEl();
10110         o = o || {};
10111
10112         el.queueFx(o, function(){
10113             this.clearOpacity();
10114             this.clip();
10115
10116             // restore values after effect
10117             var  r = this.getFxRestore();
10118             var  st = this.dom.style;
10119
10120             var  C = function(){
10121                 if(o.useDisplay){
10122                     el.setDisplayed(false);
10123                 }else {
10124                     el.hide();
10125                 }
10126
10127
10128                 el.clearOpacity();
10129                 el.setPositioning(r.pos);
10130                 st.width = r.width;
10131                 st.height = r.height;
10132
10133                 el.afterFx(o);
10134             };
10135
10136             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10137                 this.clearOpacity();
10138                 (function(){
10139                     this.fxanim({
10140                         height:{to:1},
10141                         points:{by:[0, this.getHeight() * .5]}
10142                     }, o, 'motion', 0.3, 'easeIn', C);
10143                 }).defer(100, this);
10144             });
10145         });
10146         return  this;
10147     },
10148
10149     /**
10150      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10151      * changed using the "attr" config option) and then fading back to the original color. If no original
10152      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10153      * Usage:
10154 <pre><code>
10155 // default: highlight background to yellow
10156 el.highlight();
10157
10158 // custom: highlight foreground text to blue for 2 seconds
10159 el.highlight("0000ff", { attr: 'color', duration: 2 });
10160
10161 // common config options shown with default values
10162 el.highlight("ffff9c", {
10163     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10164     endColor: (current color) or "ffffff",
10165     easing: 'easeIn',
10166     duration: 1
10167 });
10168 </code></pre>
10169      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10170      * @param {Object} options (optional) Object literal with any of the Fx config options
10171      * @return {Roo.Element} The Element
10172      */ 
10173     highlight : function(C, o){
10174         var  el = this.getFxEl();
10175         o = o || {};
10176
10177         el.queueFx(o, function(){
10178             C = C || "ffff9c";
10179             attr = o.attr || "backgroundColor";
10180
10181             this.clearOpacity();
10182             this.show();
10183
10184             var  D = this.getColor(attr);
10185             var  E = this.dom.style[attr];
10186             endColor = (o.endColor || D) || "ffffff";
10187
10188             var  F = function(){
10189                 el.dom.style[attr] = E;
10190                 el.afterFx(o);
10191             };
10192
10193             var  a = {};
10194             a[attr] = {from: C, to: endColor};
10195             arguments.callee.anim = this.fxanim(a,
10196                 o,
10197                 'color',
10198                 1,
10199                 'easeIn', F);
10200         });
10201         return  this;
10202     },
10203
10204    /**
10205     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10206     * Usage:
10207 <pre><code>
10208 // default: a single light blue ripple
10209 el.frame();
10210
10211 // custom: 3 red ripples lasting 3 seconds total
10212 el.frame("ff0000", 3, { duration: 3 });
10213
10214 // common config options shown with default values
10215 el.frame("C3DAF9", 1, {
10216     duration: 1 //duration of entire animation (not each individual ripple)
10217     // Note: Easing is not configurable and will be ignored if included
10218 });
10219 </code></pre>
10220     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10221     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10222     * @param {Object} options (optional) Object literal with any of the Fx config options
10223     * @return {Roo.Element} The Element
10224     */
10225     frame : function(D, E, o){
10226         var  el = this.getFxEl();
10227         o = o || {};
10228
10229         el.queueFx(o, function(){
10230             D = D || "#C3DAF9";
10231             if(D.length == 6){
10232                 D = "#" + D;
10233             }
10234
10235             E = E || 1;
10236             duration = o.duration || 1;
10237             this.show();
10238
10239             var  b = this.getBox();
10240             var  F = function(){
10241                 var  G = this.createProxy({
10242
10243                      style:{
10244                         visbility:"hidden",
10245                         position:"absolute",
10246                         "z-index":"35000", // yee haw
10247                         border:"0px solid " + D
10248                      }
10249                   });
10250                 var  H = Roo.isBorderBox ? 2 : 1;
10251                 G.animate({
10252                     top:{from:b.y, to:b.y - 20},
10253                     left:{from:b.x, to:b.x - 20},
10254                     borderWidth:{from:0, to:10},
10255                     opacity:{from:1, to:0},
10256                     height:{from:b.height, to:(b.height + (20*H))},
10257                     width:{from:b.width, to:(b.width + (20*H))}
10258                 }, duration, function(){
10259                     G.remove();
10260                 });
10261                 if(--E > 0){
10262                      F.defer((duration/2)*1000, this);
10263                 }else {
10264                     el.afterFx(o);
10265                 }
10266             };
10267             F.call(this);
10268         });
10269         return  this;
10270     },
10271
10272    /**
10273     * Creates a pause before any subsequent queued effects begin.  If there are
10274     * no effects queued after the pause it will have no effect.
10275     * Usage:
10276 <pre><code>
10277 el.pause(1);
10278 </code></pre>
10279     * @param {Number} seconds The length of time to pause (in seconds)
10280     * @return {Roo.Element} The Element
10281     */
10282     pause : function(F){
10283         var  el = this.getFxEl();
10284         var  o = {};
10285
10286         el.queueFx(o, function(){
10287             setTimeout(function(){
10288                 el.afterFx(o);
10289             }, F * 1000);
10290         });
10291         return  this;
10292     },
10293
10294    /**
10295     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10296     * using the "endOpacity" config option.
10297     * Usage:
10298 <pre><code>
10299 // default: fade in from opacity 0 to 100%
10300 el.fadeIn();
10301
10302 // custom: fade in from opacity 0 to 75% over 2 seconds
10303 el.fadeIn({ endOpacity: .75, duration: 2});
10304
10305 // common config options shown with default values
10306 el.fadeIn({
10307     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10308     easing: 'easeOut',
10309     duration: .5
10310 });
10311 </code></pre>
10312     * @param {Object} options (optional) Object literal with any of the Fx config options
10313     * @return {Roo.Element} The Element
10314     */
10315     fadeIn : function(o){
10316         var  el = this.getFxEl();
10317         o = o || {};
10318         el.queueFx(o, function(){
10319             this.setOpacity(0);
10320             this.fixDisplay();
10321             this.dom.style.visibility = 'visible';
10322             var  to = o.endOpacity || 1;
10323             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10324                 o, null, .5, "easeOut", function(){
10325                 if(to == 1){
10326                     this.clearOpacity();
10327                 }
10328
10329                 el.afterFx(o);
10330             });
10331         });
10332         return  this;
10333     },
10334
10335    /**
10336     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10337     * using the "endOpacity" config option.
10338     * Usage:
10339 <pre><code>
10340 // default: fade out from the element's current opacity to 0
10341 el.fadeOut();
10342
10343 // custom: fade out from the element's current opacity to 25% over 2 seconds
10344 el.fadeOut({ endOpacity: .25, duration: 2});
10345
10346 // common config options shown with default values
10347 el.fadeOut({
10348     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10349     easing: 'easeOut',
10350     duration: .5
10351     remove: false,
10352     useDisplay: false
10353 });
10354 </code></pre>
10355     * @param {Object} options (optional) Object literal with any of the Fx config options
10356     * @return {Roo.Element} The Element
10357     */
10358     fadeOut : function(o){
10359         var  el = this.getFxEl();
10360         o = o || {};
10361         el.queueFx(o, function(){
10362             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10363                 o, null, .5, "easeOut", function(){
10364                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10365                      this.dom.style.display = "none";
10366                 }else {
10367                      this.dom.style.visibility = "hidden";
10368                 }
10369
10370                 this.clearOpacity();
10371                 el.afterFx(o);
10372             });
10373         });
10374         return  this;
10375     },
10376
10377    /**
10378     * Animates the transition of an element's dimensions from a starting height/width
10379     * to an ending height/width.
10380     * Usage:
10381 <pre><code>
10382 // change height and width to 100x100 pixels
10383 el.scale(100, 100);
10384
10385 // common config options shown with default values.  The height and width will default to
10386 // the element's existing values if passed as null.
10387 el.scale(
10388     [element's width],
10389     [element's height], {
10390     easing: 'easeOut',
10391     duration: .35
10392 });
10393 </code></pre>
10394     * @param {Number} width  The new width (pass undefined to keep the original width)
10395     * @param {Number} height  The new height (pass undefined to keep the original height)
10396     * @param {Object} options (optional) Object literal with any of the Fx config options
10397     * @return {Roo.Element} The Element
10398     */
10399     scale : function(w, h, o){
10400         this.shift(Roo.apply({}, o, {
10401             width: w,
10402             height: h
10403         }));
10404         return  this;
10405     },
10406
10407    /**
10408     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10409     * Any of these properties not specified in the config object will not be changed.  This effect 
10410     * requires that at least one new dimension, position or opacity setting must be passed in on
10411     * the config object in order for the function to have any effect.
10412     * Usage:
10413 <pre><code>
10414 // slide the element horizontally to x position 200 while changing the height and opacity
10415 el.shift({ x: 200, height: 50, opacity: .8 });
10416
10417 // common config options shown with default values.
10418 el.shift({
10419     width: [element's width],
10420     height: [element's height],
10421     x: [element's x position],
10422     y: [element's y position],
10423     opacity: [element's opacity],
10424     easing: 'easeOut',
10425     duration: .35
10426 });
10427 </code></pre>
10428     * @param {Object} options  Object literal with any of the Fx config options
10429     * @return {Roo.Element} The Element
10430     */
10431     shift : function(o){
10432         var  el = this.getFxEl();
10433         o = o || {};
10434         el.queueFx(o, function(){
10435             var  a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10436             if(w !== undefined){
10437                 a.width = {to: this.adjustWidth(w)};
10438             }
10439             if(h !== undefined){
10440                 a.height = {to: this.adjustHeight(h)};
10441             }
10442             if(x !== undefined || y !== undefined){
10443                 a.points = {to: [
10444                     x !== undefined ? x : this.getX(),
10445                     y !== undefined ? y : this.getY()
10446                 ]};
10447             }
10448             if(op !== undefined){
10449                 a.opacity = {to: op};
10450             }
10451             if(o.xy !== undefined){
10452                 a.points = {to: o.xy};
10453             }
10454
10455             arguments.callee.anim = this.fxanim(a,
10456                 o, 'motion', .35, "easeOut", function(){
10457                 el.afterFx(o);
10458             });
10459         });
10460         return  this;
10461     },
10462
10463         /**
10464          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10465          * ending point of the effect.
10466          * Usage:
10467          *<pre><code>
10468 // default: slide the element downward while fading out
10469 el.ghost();
10470
10471 // custom: slide the element out to the right with a 2-second duration
10472 el.ghost('r', { duration: 2 });
10473
10474 // common config options shown with default values
10475 el.ghost('b', {
10476     easing: 'easeOut',
10477     duration: .5
10478     remove: false,
10479     useDisplay: false
10480 });
10481 </code></pre>
10482          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10483          * @param {Object} options (optional) Object literal with any of the Fx config options
10484          * @return {Roo.Element} The Element
10485          */
10486     ghost : function(G, o){
10487         var  el = this.getFxEl();
10488         o = o || {};
10489
10490         el.queueFx(o, function(){
10491             G = G || "b";
10492
10493             // restore values after effect
10494             var  r = this.getFxRestore();
10495             var  w = this.getWidth(),
10496                 h = this.getHeight();
10497
10498             var  st = this.dom.style;
10499
10500             var  H = function(){
10501                 if(o.useDisplay){
10502                     el.setDisplayed(false);
10503                 }else {
10504                     el.hide();
10505                 }
10506
10507
10508                 el.clearOpacity();
10509                 el.setPositioning(r.pos);
10510                 st.width = r.width;
10511                 st.height = r.height;
10512
10513                 el.afterFx(o);
10514             };
10515
10516             var  a = {opacity: {to: 0}, points: {}}, pt = a.points;
10517             switch(G.toLowerCase()){
10518                 case  "t":
10519                     pt.by = [0, -h];
10520                 break;
10521                 case  "l":
10522                     pt.by = [-w, 0];
10523                 break;
10524                 case  "r":
10525                     pt.by = [w, 0];
10526                 break;
10527                 case  "b":
10528                     pt.by = [0, h];
10529                 break;
10530                 case  "tl":
10531                     pt.by = [-w, -h];
10532                 break;
10533                 case  "bl":
10534                     pt.by = [-w, h];
10535                 break;
10536                 case  "br":
10537                     pt.by = [w, h];
10538                 break;
10539                 case  "tr":
10540                     pt.by = [w, -h];
10541                 break;
10542             }
10543
10544
10545             arguments.callee.anim = this.fxanim(a,
10546                 o,
10547                 'motion',
10548                 .5,
10549                 "easeOut", H);
10550         });
10551         return  this;
10552     },
10553
10554         /**
10555          * Ensures that all effects queued after syncFx is called on the element are
10556          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10557          * @return {Roo.Element} The Element
10558          */
10559     syncFx : function(){
10560         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10561             block : false,
10562             concurrent : true,
10563             stopFx : false
10564         });
10565         return  this;
10566     },
10567
10568         /**
10569          * Ensures that all effects queued after sequenceFx is called on the element are
10570          * run in sequence.  This is the opposite of {@link #syncFx}.
10571          * @return {Roo.Element} The Element
10572          */
10573     sequenceFx : function(){
10574         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10575             block : false,
10576             concurrent : false,
10577             stopFx : false
10578         });
10579         return  this;
10580     },
10581
10582         /* @private */
10583     nextFx : function(){
10584         var  ef = this.fxQueue[0];
10585         if(ef){
10586             ef.call(this);
10587         }
10588     },
10589
10590         /**
10591          * Returns true if the element has any effects actively running or queued, else returns false.
10592          * @return {Boolean} True if element has active effects, else false
10593          */
10594     hasActiveFx : function(){
10595         return  this.fxQueue && this.fxQueue[0];
10596     },
10597
10598         /**
10599          * Stops any running effects and clears the element's internal effects queue if it contains
10600          * any additional effects that haven't started yet.
10601          * @return {Roo.Element} The Element
10602          */
10603     stopFx : function(){
10604         if(this.hasActiveFx()){
10605             var  cur = this.fxQueue[0];
10606             if(cur && cur.anim && cur.anim.isAnimated()){
10607                 this.fxQueue = [cur]; // clear out others
10608                 cur.anim.stop(true);
10609             }
10610         }
10611         return  this;
10612     },
10613
10614         /* @private */
10615     beforeFx : function(o){
10616         if(this.hasActiveFx() && !o.concurrent){
10617            if(o.stopFx){
10618                this.stopFx();
10619                return  true;
10620            }
10621            return  false;
10622         }
10623         return  true;
10624     },
10625
10626         /**
10627          * Returns true if the element is currently blocking so that no other effect can be queued
10628          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10629          * used to ensure that an effect initiated by a user action runs to completion prior to the
10630          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10631          * @return {Boolean} True if blocking, else false
10632          */
10633     hasFxBlock : function(){
10634         var  q = this.fxQueue;
10635         return  q && q[0] && q[0].block;
10636     },
10637
10638         /* @private */
10639     queueFx : function(o, fn){
10640         if(!this.fxQueue){
10641             this.fxQueue = [];
10642         }
10643         if(!this.hasFxBlock()){
10644             Roo.applyIf(o, this.fxDefaults);
10645             if(!o.concurrent){
10646                 var  run = this.beforeFx(o);
10647                 fn.block = o.block;
10648                 this.fxQueue.push(fn);
10649                 if(run){
10650                     this.nextFx();
10651                 }
10652             }else {
10653                 fn.call(this);
10654             }
10655         }
10656         return  this;
10657     },
10658
10659         /* @private */
10660     fxWrap : function(H, o, I){
10661         var  J;
10662         if(!o.wrap || !(J = Roo.get(o.wrap))){
10663             var  wrapXY;
10664             if(o.fixPosition){
10665                 wrapXY = this.getXY();
10666             }
10667             var  div = document.createElement("div");
10668             div.style.visibility = I;
10669             J = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10670             J.setPositioning(H);
10671             if(J.getStyle("position") == "static"){
10672                 J.position("relative");
10673             }
10674
10675             this.clearPositioning('auto');
10676             J.clip();
10677             J.dom.appendChild(this.dom);
10678             if(wrapXY){
10679                 J.setXY(wrapXY);
10680             }
10681         }
10682         return  J;
10683     },
10684
10685         /* @private */
10686     fxUnwrap : function(K, L, o){
10687         this.clearPositioning();
10688         this.setPositioning(L);
10689         if(!o.wrap){
10690             K.dom.parentNode.insertBefore(this.dom, K.dom);
10691             K.remove();
10692         }
10693     },
10694
10695         /* @private */
10696     getFxRestore : function(){
10697         var  st = this.dom.style;
10698         return  {pos: this.getPositioning(), width: st.width, height : st.height};
10699     },
10700
10701         /* @private */
10702     afterFx : function(o){
10703         if(o.afterStyle){
10704             this.applyStyles(o.afterStyle);
10705         }
10706         if(o.afterCls){
10707             this.addClass(o.afterCls);
10708         }
10709         if(o.remove === true){
10710             this.remove();
10711         }
10712
10713         Roo.callback(o.callback, o.scope, [this]);
10714         if(!o.concurrent){
10715             this.fxQueue.shift();
10716             this.nextFx();
10717         }
10718     },
10719
10720         /* @private */
10721     getFxEl : function(){ // support for composite element fx
10722         return  Roo.get(this.dom);
10723     },
10724
10725         /* @private */
10726     fxanim : function(M, N, O, P, Q, cb){
10727         O = O || 'run';
10728         N = N || {};
10729         var  R = Roo.lib.Anim[O](
10730             this.dom, M,
10731             (N.duration || P) || .35,
10732             (N.easing || Q) || 'easeOut',
10733             function(){
10734                 Roo.callback(cb, this);
10735             },
10736             this
10737         );
10738         N.anim = R;
10739         return  R;
10740     }
10741 };
10742
10743 // backwords compat
10744 Roo.Fx.resize = Roo.Fx.scale;
10745
10746 //When included, Roo.Fx is automatically applied to Element so that all basic
10747 //effects are available directly via the Element API
10748 Roo.apply(Roo.Element.prototype, Roo.Fx);
10749 /*
10750  * Based on:
10751  * Ext JS Library 1.1.1
10752  * Copyright(c) 2006-2007, Ext JS, LLC.
10753  *
10754  * Originally Released Under LGPL - original licence link has changed is not relivant.
10755  *
10756  * Fork - LGPL
10757  * <script type="text/javascript">
10758  */
10759
10760
10761 /**
10762  * @class Roo.CompositeElement
10763  * Standard composite class. Creates a Roo.Element for every element in the collection.
10764  * <br><br>
10765  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10766  * actions will be performed on all the elements in this collection.</b>
10767  * <br><br>
10768  * All methods return <i>this</i> and can be chained.
10769  <pre><code>
10770  var els = Roo.select("#some-el div.some-class", true);
10771  // or select directly from an existing element
10772  var el = Roo.get('some-el');
10773  el.select('div.some-class', true);
10774
10775  els.setWidth(100); // all elements become 100 width
10776  els.hide(true); // all elements fade out and hide
10777  // or
10778  els.setWidth(100).hide(true);
10779  </code></pre>
10780  */
10781 Roo.CompositeElement = function(A){
10782     this.elements = [];
10783     this.addElements(A);
10784 };
10785 Roo.CompositeElement.prototype = {
10786     isComposite: true,
10787     addElements : function(B){
10788         if(!B) return  this;
10789         if(typeof  B == "string"){
10790             B = Roo.Element.selectorFunction(B);
10791         }
10792         var  C = this.elements;
10793         var  D = C.length-1;
10794         for(var  i = 0, len = B.length; i < len; i++) {
10795                 C[++D] = Roo.get(B[i]);
10796         }
10797         return  this;
10798     },
10799
10800     /**
10801     * Clears this composite and adds the elements returned by the passed selector.
10802     * @param {String/Array} els A string CSS selector, an array of elements or an element
10803     * @return {CompositeElement} this
10804     */
10805     fill : function(E){
10806         this.elements = [];
10807         this.add(E);
10808         return  this;
10809     },
10810
10811     /**
10812     * Filters this composite to only elements that match the passed selector.
10813     * @param {String} selector A string CSS selector
10814     * @return {CompositeElement} this
10815     */
10816     filter : function(F){
10817         var  G = [];
10818         this.each(function(el){
10819             if(el.is(F)){
10820                 G[G.length] = el.dom;
10821             }
10822         });
10823         this.fill(G);
10824         return  this;
10825     },
10826
10827     invoke : function(fn, H){
10828         var  I = this.elements;
10829         for(var  i = 0, len = I.length; i < len; i++) {
10830                 Roo.Element.prototype[fn].apply(I[i], H);
10831         }
10832         return  this;
10833     },
10834     /**
10835     * Adds elements to this composite.
10836     * @param {String/Array} els A string CSS selector, an array of elements or an element
10837     * @return {CompositeElement} this
10838     */
10839     add : function(J){
10840         if(typeof  J == "string"){
10841             this.addElements(Roo.Element.selectorFunction(J));
10842         }else  if(J.length !== undefined){
10843             this.addElements(J);
10844         }else {
10845             this.addElements([J]);
10846         }
10847         return  this;
10848     },
10849     /**
10850     * Calls the passed function passing (el, this, index) for each element in this composite.
10851     * @param {Function} fn The function to call
10852     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10853     * @return {CompositeElement} this
10854     */
10855     each : function(fn, K){
10856         var  L = this.elements;
10857         for(var  i = 0, len = L.length; i < len; i++){
10858             if(fn.call(K || L[i], L[i], this, i) === false) {
10859                 break;
10860             }
10861         }
10862         return  this;
10863     },
10864
10865     /**
10866      * Returns the Element object at the specified index
10867      * @param {Number} index
10868      * @return {Roo.Element}
10869      */
10870     item : function(M){
10871         return  this.elements[M] || null;
10872     },
10873
10874     /**
10875      * Returns the first Element
10876      * @return {Roo.Element}
10877      */
10878     first : function(){
10879         return  this.item(0);
10880     },
10881
10882     /**
10883      * Returns the last Element
10884      * @return {Roo.Element}
10885      */
10886     last : function(){
10887         return  this.item(this.elements.length-1);
10888     },
10889
10890     /**
10891      * Returns the number of elements in this composite
10892      * @return Number
10893      */
10894     getCount : function(){
10895         return  this.elements.length;
10896     },
10897
10898     /**
10899      * Returns true if this composite contains the passed element
10900      * @return Boolean
10901      */
10902     contains : function(el){
10903         return  this.indexOf(el) !== -1;
10904     },
10905
10906     /**
10907      * Returns true if this composite contains the passed element
10908      * @return Boolean
10909      */
10910     indexOf : function(el){
10911         return  this.elements.indexOf(Roo.get(el));
10912     },
10913
10914
10915     /**
10916     * Removes the specified element(s).
10917     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10918     * or an array of any of those.
10919     * @param {Boolean} removeDom (optional) True to also remove the element from the document
10920     * @return {CompositeElement} this
10921     */
10922     removeElement : function(el, N){
10923         if(el  instanceof  Array){
10924             for(var  i = 0, len = el.length; i < len; i++){
10925                 this.removeElement(el[i]);
10926             }
10927             return  this;
10928         }
10929         var  O = typeof  el == 'number' ? el : this.indexOf(el);
10930         if(O !== -1){
10931             if(N){
10932                 var  d = this.elements[O];
10933                 if(d.dom){
10934                     d.remove();
10935                 }else {
10936                     d.parentNode.removeChild(d);
10937                 }
10938             }
10939
10940             this.elements.splice(O, 1);
10941         }
10942         return  this;
10943     },
10944
10945     /**
10946     * Replaces the specified element with the passed element.
10947     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10948     * to replace.
10949     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10950     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10951     * @return {CompositeElement} this
10952     */
10953     replaceElement : function(el, P, Q){
10954         var  R = typeof  el == 'number' ? el : this.indexOf(el);
10955         if(R !== -1){
10956             if(Q){
10957                 this.elements[R].replaceWith(P);
10958             }else {
10959                 this.elements.splice(R, 1, Roo.get(P))
10960             }
10961         }
10962         return  this;
10963     },
10964
10965     /**
10966      * Removes all elements.
10967      */
10968     clear : function(){
10969         this.elements = [];
10970     }
10971 };
10972 (function(){
10973     Roo.CompositeElement.createCall = function(S, T){
10974         if(!S[T]){
10975             S[T] = function(){
10976                 return  this.invoke(T, arguments);
10977             };
10978         }
10979     };
10980     for(var  fnName  in  Roo.Element.prototype){
10981         if(typeof  Roo.Element.prototype[fnName] == "function"){
10982             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10983         }
10984     };
10985 })();
10986
10987 /*
10988  * Based on:
10989  * Ext JS Library 1.1.1
10990  * Copyright(c) 2006-2007, Ext JS, LLC.
10991  *
10992  * Originally Released Under LGPL - original licence link has changed is not relivant.
10993  *
10994  * Fork - LGPL
10995  * <script type="text/javascript">
10996  */
10997
10998 /**
10999  * @class Roo.CompositeElementLite
11000  * @extends Roo.CompositeElement
11001  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11002  <pre><code>
11003  var els = Roo.select("#some-el div.some-class");
11004  // or select directly from an existing element
11005  var el = Roo.get('some-el');
11006  el.select('div.some-class');
11007
11008  els.setWidth(100); // all elements become 100 width
11009  els.hide(true); // all elements fade out and hide
11010  // or
11011  els.setWidth(100).hide(true);
11012  </code></pre><br><br>
11013  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11014  * actions will be performed on all the elements in this collection.</b>
11015  */
11016 Roo.CompositeElementLite = function(A){
11017     Roo.CompositeElementLite.superclass.constructor.call(this, A);
11018     this.el = new  Roo.Element.Flyweight();
11019 };
11020 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11021     addElements : function(B){
11022         if(B){
11023             if(B  instanceof  Array){
11024                 this.elements = this.elements.concat(B);
11025             }else {
11026                 var  yels = this.elements;
11027                 var  index = yels.length-1;
11028                 for(var  i = 0, len = B.length; i < len; i++) {
11029                     yels[++index] = B[i];
11030                 }
11031             }
11032         }
11033         return  this;
11034     },
11035     invoke : function(fn, C){
11036         var  D = this.elements;
11037         var  el = this.el;
11038         for(var  i = 0, len = D.length; i < len; i++) {
11039             el.dom = D[i];
11040                 Roo.Element.prototype[fn].apply(el, C);
11041         }
11042         return  this;
11043     },
11044     /**
11045      * Returns a flyweight Element of the dom element object at the specified index
11046      * @param {Number} index
11047      * @return {Roo.Element}
11048      */
11049     item : function(E){
11050         if(!this.elements[E]){
11051             return  null;
11052         }
11053
11054         this.el.dom = this.elements[E];
11055         return  this.el;
11056     },
11057
11058     // fixes scope with flyweight
11059     addListener : function(F, G, H, I){
11060         var  J = this.elements;
11061         for(var  i = 0, len = J.length; i < len; i++) {
11062             Roo.EventManager.on(J[i], F, G, H || J[i], I);
11063         }
11064         return  this;
11065     },
11066
11067     /**
11068     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11069     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11070     * a reference to the dom node, use el.dom.</b>
11071     * @param {Function} fn The function to call
11072     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11073     * @return {CompositeElement} this
11074     */
11075     each : function(fn, K){
11076         var  L = this.elements;
11077         var  el = this.el;
11078         for(var  i = 0, len = L.length; i < len; i++){
11079             el.dom = L[i];
11080                 if(fn.call(K || el, el, this, i) === false){
11081                 break;
11082             }
11083         }
11084         return  this;
11085     },
11086
11087     indexOf : function(el){
11088         return  this.elements.indexOf(Roo.getDom(el));
11089     },
11090
11091     replaceElement : function(el, M, N){
11092         var  O = typeof  el == 'number' ? el : this.indexOf(el);
11093         if(O !== -1){
11094             M = Roo.getDom(M);
11095             if(N){
11096                 var  d = this.elements[O];
11097                 d.parentNode.insertBefore(M, d);
11098                 d.parentNode.removeChild(d);
11099             }
11100
11101             this.elements.splice(O, 1, M);
11102         }
11103         return  this;
11104     }
11105 });
11106 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11107
11108
11109 /*
11110  * Based on:
11111  * Ext JS Library 1.1.1
11112  * Copyright(c) 2006-2007, Ext JS, LLC.
11113  *
11114  * Originally Released Under LGPL - original licence link has changed is not relivant.
11115  *
11116  * Fork - LGPL
11117  * <script type="text/javascript">
11118  */
11119
11120  
11121
11122 /**
11123  * @class Roo.data.Connection
11124  * @extends Roo.util.Observable
11125  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11126  * either to a configured URL, or to a URL specified at request time.<br><br>
11127  * <p>
11128  * Requests made by this class are asynchronous, and will return immediately. No data from
11129  * the server will be available to the statement immediately following the {@link #request} call.
11130  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11131  * <p>
11132  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11133  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11134  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11135  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11136  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11137  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11138  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11139  * standard DOM methods.
11140  * @constructor
11141  * @param {Object} config a configuration object.
11142  */
11143 Roo.data.Connection = function(A){
11144     Roo.apply(this, A);
11145     this.addEvents({
11146         /**
11147          * @event beforerequest
11148          * Fires before a network request is made to retrieve a data object.
11149          * @param {Connection} conn This Connection object.
11150          * @param {Object} options The options config object passed to the {@link #request} method.
11151          */
11152         "beforerequest" : true,
11153         /**
11154          * @event requestcomplete
11155          * Fires if the request was successfully completed.
11156          * @param {Connection} conn This Connection object.
11157          * @param {Object} response The XHR object containing the response data.
11158          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11159          * @param {Object} options The options config object passed to the {@link #request} method.
11160          */
11161         "requestcomplete" : true,
11162         /**
11163          * @event requestexception
11164          * Fires if an error HTTP status was returned from the server.
11165          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11166          * @param {Connection} conn This Connection object.
11167          * @param {Object} response The XHR object containing the response data.
11168          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11169          * @param {Object} options The options config object passed to the {@link #request} method.
11170          */
11171         "requestexception" : true
11172     });
11173     Roo.data.Connection.superclass.constructor.call(this);
11174 };
11175
11176 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11177     /**
11178      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11179      */
11180     /**
11181      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11182      * extra parameters to each request made by this object. (defaults to undefined)
11183      */
11184     /**
11185      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11186      *  to each request made by this object. (defaults to undefined)
11187      */
11188     /**
11189      * @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)
11190      */
11191     /**
11192      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11193      */
11194     timeout : 30000,
11195     /**
11196      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11197      * @type Boolean
11198      */
11199     autoAbort:false,
11200
11201     /**
11202      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11203      * @type Boolean
11204      */
11205     disableCaching: true,
11206
11207     /**
11208      * Sends an HTTP request to a remote server.
11209      * @param {Object} options An object which may contain the following properties:<ul>
11210      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11211      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11212      * request, a url encoded string or a function to call to get either.</li>
11213      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11214      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11215      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11216      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11217      * <li>options {Object} The parameter to the request call.</li>
11218      * <li>success {Boolean} True if the request succeeded.</li>
11219      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11220      * </ul></li>
11221      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11222      * The callback is passed the following parameters:<ul>
11223      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11224      * <li>options {Object} The parameter to the request call.</li>
11225      * </ul></li>
11226      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11227      * The callback is passed the following parameters:<ul>
11228      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11229      * <li>options {Object} The parameter to the request call.</li>
11230      * </ul></li>
11231      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11232      * for the callback function. Defaults to the browser window.</li>
11233      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11234      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11235      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11236      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11237      * params for the post data. Any params will be appended to the URL.</li>
11238      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11239      * </ul>
11240      * @return {Number} transactionId
11241      */
11242     request : function(o){
11243         if(this.fireEvent("beforerequest", this, o) !== false){
11244             var  p = o.params;
11245
11246             if(typeof  p == "function"){
11247                 p = p.call(o.scope||window, o);
11248             }
11249             if(typeof  p == "object"){
11250                 p = Roo.urlEncode(o.params);
11251             }
11252             if(this.extraParams){
11253                 var  extras = Roo.urlEncode(this.extraParams);
11254                 p = p ? (p + '&' + extras) : extras;
11255             }
11256
11257             var  url = o.url || this.url;
11258             if(typeof  url == 'function'){
11259                 url = url.call(o.scope||window, o);
11260             }
11261
11262             if(o.form){
11263                 var  form = Roo.getDom(o.form);
11264                 url = url || form.action;
11265
11266                 var  enctype = form.getAttribute("enctype");
11267                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11268                     return  this.doFormUpload(o, p, url);
11269                 }
11270                 var  f = Roo.lib.Ajax.serializeForm(form);
11271                 p = p ? (p + '&' + f) : f;
11272             }
11273
11274             var  hs = o.headers;
11275             if(this.defaultHeaders){
11276                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11277                 if(!o.headers){
11278                     o.headers = hs;
11279                 }
11280             }
11281
11282             var  cb = {
11283                 success: this.handleResponse,
11284                 failure: this.handleFailure,
11285                 scope: this,
11286                 argument: {options: o},
11287                 timeout : this.timeout
11288             };
11289
11290             var  method = o.method||this.method||(p ? "POST" : "GET");
11291
11292             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11293                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new  Date().getTime());
11294             }
11295
11296             if(typeof  o.autoAbort == 'boolean'){ // options gets top priority
11297                 if(o.autoAbort){
11298                     this.abort();
11299                 }
11300             }else  if(this.autoAbort !== false){
11301                 this.abort();
11302             }
11303
11304             if((method == 'GET' && p) || o.xmlData){
11305                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11306                 p = '';
11307             }
11308
11309             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11310             return  this.transId;
11311         }else {
11312             Roo.callback(o.callback, o.scope, [o, null, null]);
11313             return  null;
11314         }
11315     },
11316
11317     /**
11318      * Determine whether this object has a request outstanding.
11319      * @param {Number} transactionId (Optional) defaults to the last transaction
11320      * @return {Boolean} True if there is an outstanding request.
11321      */
11322     isLoading : function(B){
11323         if(B){
11324             return  Roo.lib.Ajax.isCallInProgress(B);
11325         }else {
11326             return  this.transId ? true : false;
11327         }
11328     },
11329
11330     /**
11331      * Aborts any outstanding request.
11332      * @param {Number} transactionId (Optional) defaults to the last transaction
11333      */
11334     abort : function(C){
11335         if(C || this.isLoading()){
11336             Roo.lib.Ajax.abort(C || this.transId);
11337         }
11338     },
11339
11340     // private
11341     handleResponse : function(D){
11342         this.transId = false;
11343         var  E = D.argument.options;
11344         D.argument = E ? E.argument : null;
11345         this.fireEvent("requestcomplete", this, D, E);
11346         Roo.callback(E.success, E.scope, [D, E]);
11347         Roo.callback(E.callback, E.scope, [E, true, D]);
11348     },
11349
11350     // private
11351     handleFailure : function(F, e){
11352         this.transId = false;
11353         var  G = F.argument.options;
11354         F.argument = G ? G.argument : null;
11355         this.fireEvent("requestexception", this, F, G, e);
11356         Roo.callback(G.failure, G.scope, [F, G]);
11357         Roo.callback(G.callback, G.scope, [G, false, F]);
11358     },
11359
11360     // private
11361     doFormUpload : function(o, ps, H){
11362         var  id = Roo.id();
11363         var  I = document.createElement('iframe');
11364         I.id = id;
11365         I.name = id;
11366         I.className = 'x-hidden';
11367         if(Roo.isIE){
11368             I.src = Roo.SSL_SECURE_URL;
11369         }
11370
11371         document.body.appendChild(I);
11372
11373         if(Roo.isIE){
11374            document.frames[id].name = id;
11375         }
11376
11377         var  J = Roo.getDom(o.form);
11378         J.target = id;
11379         J.method = 'POST';
11380         J.enctype = J.encoding = 'multipart/form-data';
11381         if(H){
11382             J.action = H;
11383         }
11384
11385         var  K, hd;
11386         if(ps){ // add dynamic params
11387             K = [];
11388             ps = Roo.urlDecode(ps, false);
11389             for(var  k  in  ps){
11390                 if(ps.hasOwnProperty(k)){
11391                     hd = document.createElement('input');
11392                     hd.type = 'hidden';
11393                     hd.name = k;
11394                     hd.value = ps[k];
11395                     J.appendChild(hd);
11396                     K.push(hd);
11397                 }
11398             }
11399         }
11400
11401         function  cb(){
11402             var  r = {  // bogus response object
11403                 responseText : '',
11404                 responseXML : null
11405             };
11406
11407             r.argument = o ? o.argument : null;
11408
11409             try { //
11410                 var  doc;
11411                 if(Roo.isIE){
11412                     doc = I.contentWindow.document;
11413                 }else  {
11414                     doc = (I.contentDocument || window.frames[id].document);
11415                 }
11416                 if(doc && doc.body){
11417                     r.responseText = doc.body.innerHTML;
11418                 }
11419                 if(doc && doc.XMLDocument){
11420                     r.responseXML = doc.XMLDocument;
11421                 }else  {
11422                     r.responseXML = doc;
11423                 }
11424             }
11425             catch(e) {
11426                 // ignore
11427             }
11428
11429
11430             Roo.EventManager.removeListener(I, 'load', cb, this);
11431
11432             this.fireEvent("requestcomplete", this, r, o);
11433             Roo.callback(o.success, o.scope, [r, o]);
11434             Roo.callback(o.callback, o.scope, [o, true, r]);
11435
11436             setTimeout(function(){document.body.removeChild(I);}, 100);
11437         }
11438
11439
11440         Roo.EventManager.on(I, 'load', cb, this);
11441         J.submit();
11442
11443         if(K){ // remove dynamic params
11444             for(var  i = 0, len = K.length; i < len; i++){
11445                 J.removeChild(K[i]);
11446             }
11447         }
11448     }
11449 });
11450
11451 /**
11452  * @class Roo.Ajax
11453  * @extends Roo.data.Connection
11454  * Global Ajax request class.
11455  *
11456  * @singleton
11457  */
11458 Roo.Ajax = new  Roo.data.Connection({
11459     // fix up the docs
11460    /**
11461      * @cfg {String} url @hide
11462      */
11463     /**
11464      * @cfg {Object} extraParams @hide
11465      */
11466     /**
11467      * @cfg {Object} defaultHeaders @hide
11468      */
11469     /**
11470      * @cfg {String} method (Optional) @hide
11471      */
11472     /**
11473      * @cfg {Number} timeout (Optional) @hide
11474      */
11475     /**
11476      * @cfg {Boolean} autoAbort (Optional) @hide
11477      */
11478
11479     /**
11480      * @cfg {Boolean} disableCaching (Optional) @hide
11481      */
11482
11483     /**
11484      * @property  disableCaching
11485      * True to add a unique cache-buster param to GET requests. (defaults to true)
11486      * @type Boolean
11487      */
11488     /**
11489      * @property  url
11490      * The default URL to be used for requests to the server. (defaults to undefined)
11491      * @type String
11492      */
11493     /**
11494      * @property  extraParams
11495      * An object containing properties which are used as
11496      * extra parameters to each request made by this object. (defaults to undefined)
11497      * @type Object
11498      */
11499     /**
11500      * @property  defaultHeaders
11501      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11502      * @type Object
11503      */
11504     /**
11505      * @property  method
11506      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11507      * @type String
11508      */
11509     /**
11510      * @property  timeout
11511      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11512      * @type Number
11513      */
11514
11515     /**
11516      * @property  autoAbort
11517      * Whether a new request should abort any pending requests. (defaults to false)
11518      * @type Boolean
11519      */
11520     autoAbort : false,
11521
11522     /**
11523      * Serialize the passed form into a url encoded string
11524      * @param {String/HTMLElement} form
11525      * @return {String}
11526      */
11527     serializeForm : function(L){
11528         return  Roo.lib.Ajax.serializeForm(L);
11529     }
11530 });
11531 /*
11532  * Based on:
11533  * Ext JS Library 1.1.1
11534  * Copyright(c) 2006-2007, Ext JS, LLC.
11535  *
11536  * Originally Released Under LGPL - original licence link has changed is not relivant.
11537  *
11538  * Fork - LGPL
11539  * <script type="text/javascript">
11540  */
11541  
11542 /**
11543  * @class Roo.Ajax
11544  * @extends Roo.data.Connection
11545  * Global Ajax request class.
11546  *
11547  * @instanceOf  Roo.data.Connection
11548  */
11549 Roo.Ajax = new  Roo.data.Connection({
11550     // fix up the docs
11551     
11552     /**
11553      * fix up scoping
11554      * @scope Roo.Ajax
11555      */
11556     
11557    /**
11558      * @cfg {String} url @hide
11559      */
11560     /**
11561      * @cfg {Object} extraParams @hide
11562      */
11563     /**
11564      * @cfg {Object} defaultHeaders @hide
11565      */
11566     /**
11567      * @cfg {String} method (Optional) @hide
11568      */
11569     /**
11570      * @cfg {Number} timeout (Optional) @hide
11571      */
11572     /**
11573      * @cfg {Boolean} autoAbort (Optional) @hide
11574      */
11575
11576     /**
11577      * @cfg {Boolean} disableCaching (Optional) @hide
11578      */
11579
11580     /**
11581      * @property  disableCaching
11582      * True to add a unique cache-buster param to GET requests. (defaults to true)
11583      * @type Boolean
11584      */
11585     /**
11586      * @property  url
11587      * The default URL to be used for requests to the server. (defaults to undefined)
11588      * @type String
11589      */
11590     /**
11591      * @property  extraParams
11592      * An object containing properties which are used as
11593      * extra parameters to each request made by this object. (defaults to undefined)
11594      * @type Object
11595      */
11596     /**
11597      * @property  defaultHeaders
11598      * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11599      * @type Object
11600      */
11601     /**
11602      * @property  method
11603      * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11604      * @type String
11605      */
11606     /**
11607      * @property  timeout
11608      * The timeout in milliseconds to be used for requests. (defaults to 30000)
11609      * @type Number
11610      */
11611
11612     /**
11613      * @property  autoAbort
11614      * Whether a new request should abort any pending requests. (defaults to false)
11615      * @type Boolean
11616      */
11617     autoAbort : false,
11618
11619     /**
11620      * Serialize the passed form into a url encoded string
11621      * @param {String/HTMLElement} form
11622      * @return {String}
11623      */
11624     serializeForm : function(A){
11625         return  Roo.lib.Ajax.serializeForm(A);
11626     }
11627 });
11628 /*
11629  * Based on:
11630  * Ext JS Library 1.1.1
11631  * Copyright(c) 2006-2007, Ext JS, LLC.
11632  *
11633  * Originally Released Under LGPL - original licence link has changed is not relivant.
11634  *
11635  * Fork - LGPL
11636  * <script type="text/javascript">
11637  */
11638
11639  
11640 /**
11641  * @class Roo.UpdateManager
11642  * @extends Roo.util.Observable
11643  * Provides AJAX-style update for Element object.<br><br>
11644  * Usage:<br>
11645  * <pre><code>
11646  * // Get it from a Roo.Element object
11647  * var el = Roo.get("foo");
11648  * var mgr = el.getUpdateManager();
11649  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11650  * ...
11651  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11652  * <br>
11653  * // or directly (returns the same UpdateManager instance)
11654  * var mgr = new Roo.UpdateManager("myElementId");
11655  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11656  * mgr.on("update", myFcnNeedsToKnow);
11657  * <br>
11658    // short handed call directly from the element object
11659    Roo.get("foo").load({
11660         url: "bar.php",
11661         scripts:true,
11662         params: "for=bar",
11663         text: "Loading Foo..."
11664    });
11665  * </code></pre>
11666  * @constructor
11667  * Create new UpdateManager directly.
11668  * @param {String/HTMLElement/Roo.Element} el The element to update
11669  * @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).
11670  */
11671 Roo.UpdateManager = function(el, A){
11672     el = Roo.get(el);
11673     if(!A && el.updateManager){
11674         return  el.updateManager;
11675     }
11676
11677     /**
11678      * The Element object
11679      * @type Roo.Element
11680      */
11681     this.el = el;
11682     /**
11683      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11684      * @type String
11685      */
11686     this.defaultUrl = null;
11687
11688     this.addEvents({
11689         /**
11690          * @event beforeupdate
11691          * Fired before an update is made, return false from your handler and the update is cancelled.
11692          * @param {Roo.Element} el
11693          * @param {String/Object/Function} url
11694          * @param {String/Object} params
11695          */
11696         "beforeupdate": true,
11697         /**
11698          * @event update
11699          * Fired after successful update is made.
11700          * @param {Roo.Element} el
11701          * @param {Object} oResponseObject The response Object
11702          */
11703         "update": true,
11704         /**
11705          * @event failure
11706          * Fired on update failure.
11707          * @param {Roo.Element} el
11708          * @param {Object} oResponseObject The response Object
11709          */
11710         "failure": true
11711     });
11712     var  d = Roo.UpdateManager.defaults;
11713     /**
11714      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11715      * @type String
11716      */
11717     this.sslBlankUrl = d.sslBlankUrl;
11718     /**
11719      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11720      * @type Boolean
11721      */
11722     this.disableCaching = d.disableCaching;
11723     /**
11724      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11725      * @type String
11726      */
11727     this.indicatorText = d.indicatorText;
11728     /**
11729      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11730      * @type String
11731      */
11732     this.showLoadIndicator = d.showLoadIndicator;
11733     /**
11734      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11735      * @type Number
11736      */
11737     this.timeout = d.timeout;
11738
11739     /**
11740      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11741      * @type Boolean
11742      */
11743     this.loadScripts = d.loadScripts;
11744
11745     /**
11746      * Transaction object of current executing transaction
11747      */
11748     this.transaction = null;
11749
11750     /**
11751      * @private
11752      */
11753     this.autoRefreshProcId = null;
11754     /**
11755      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11756      * @type Function
11757      */
11758     this.refreshDelegate = this.refresh.createDelegate(this);
11759     /**
11760      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11761      * @type Function
11762      */
11763     this.updateDelegate = this.update.createDelegate(this);
11764     /**
11765      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11766      * @type Function
11767      */
11768     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11769     /**
11770      * @private
11771      */
11772     this.successDelegate = this.processSuccess.createDelegate(this);
11773     /**
11774      * @private
11775      */
11776     this.failureDelegate = this.processFailure.createDelegate(this);
11777
11778     if(!this.renderer){
11779      /**
11780       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11781       */
11782     this.renderer = new  Roo.UpdateManager.BasicRenderer();
11783     }
11784
11785     
11786     Roo.UpdateManager.superclass.constructor.call(this);
11787 };
11788
11789 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11790     /**
11791      * Get the Element this UpdateManager is bound to
11792      * @return {Roo.Element} The element
11793      */
11794     getEl : function(){
11795         return  this.el;
11796     },
11797     /**
11798      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11799      * @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:
11800 <pre><code>
11801 um.update({<br/>
11802     url: "your-url.php",<br/>
11803     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11804     callback: yourFunction,<br/>
11805     scope: yourObject, //(optional scope)  <br/>
11806     discardUrl: false, <br/>
11807     nocache: false,<br/>
11808     text: "Loading...",<br/>
11809     timeout: 30,<br/>
11810     scripts: false<br/>
11811 });
11812 </code></pre>
11813      * The only required property is url. The optional properties nocache, text and scripts
11814      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11815      * @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}
11816      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11817      * @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.
11818      */
11819     update : function(B, C, D, E){
11820         if(this.fireEvent("beforeupdate", this.el, B, C) !== false){
11821             var  method = this.method, cfg;
11822             if(typeof  B == "object"){ // must be config object
11823                 cfg = B;
11824                 B = cfg.url;
11825                 C = C || cfg.params;
11826                 D = D || cfg.callback;
11827                 E = E || cfg.discardUrl;
11828                 if(D && cfg.scope){
11829                     D = D.createDelegate(cfg.scope);
11830                 }
11831                 if(typeof  cfg.method != "undefined"){method = cfg.method;};
11832                 if(typeof  cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11833                 if(typeof  cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11834                 if(typeof  cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11835                 if(typeof  cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11836             }
11837
11838             this.showLoading();
11839             if(!E){
11840                 this.defaultUrl = B;
11841             }
11842             if(typeof  B == "function"){
11843                 B = B.call(this);
11844             }
11845
11846
11847             method = method || (C ? "POST" : "GET");
11848             if(method == "GET"){
11849                 B = this.prepareUrl(B);
11850             }
11851
11852             var  o = Roo.apply(cfg ||{}, {
11853                 url : B,
11854                 params: C,
11855                 success: this.successDelegate,
11856                 failure: this.failureDelegate,
11857                 callback: undefined,
11858                 timeout: (this.timeout*1000),
11859                 argument: {"url": B, "form": null, "callback": D, "params": C}
11860             });
11861
11862             this.transaction = Roo.Ajax.request(o);
11863         }
11864     },
11865
11866     /**
11867      * 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.
11868      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11869      * @param {String/HTMLElement} form The form Id or form element
11870      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11871      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11872      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11873      */
11874     formUpdate : function(F, G, H, I){
11875         if(this.fireEvent("beforeupdate", this.el, F, G) !== false){
11876             if(typeof  G == "function"){
11877                 G = G.call(this);
11878             }
11879
11880             F = Roo.getDom(F);
11881             this.transaction = Roo.Ajax.request({
11882                 form: F,
11883                 url:G,
11884                 success: this.successDelegate,
11885                 failure: this.failureDelegate,
11886                 timeout: (this.timeout*1000),
11887                 argument: {"url": G, "form": F, "callback": I, "reset": H}
11888             });
11889             this.showLoading.defer(1, this);
11890         }
11891     },
11892
11893     /**
11894      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11895      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11896      */
11897     refresh : function(J){
11898         if(this.defaultUrl == null){
11899             return;
11900         }
11901
11902         this.update(this.defaultUrl, null, J, true);
11903     },
11904
11905     /**
11906      * Set this element to auto refresh.
11907      * @param {Number} interval How often to update (in seconds).
11908      * @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)
11909      * @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}
11910      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11911      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11912      */
11913     startAutoRefresh : function(K, L, M, N, O){
11914         if(O){
11915             this.update(L || this.defaultUrl, M, N, true);
11916         }
11917         if(this.autoRefreshProcId){
11918             clearInterval(this.autoRefreshProcId);
11919         }
11920
11921         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [L || this.defaultUrl, M, N, true]), K*1000);
11922     },
11923
11924     /**
11925      * Stop auto refresh on this element.
11926      */
11927      stopAutoRefresh : function(){
11928         if(this.autoRefreshProcId){
11929             clearInterval(this.autoRefreshProcId);
11930             delete  this.autoRefreshProcId;
11931         }
11932     },
11933
11934     isAutoRefreshing : function(){
11935        return  this.autoRefreshProcId ? true : false;
11936     },
11937     /**
11938      * Called to update the element to "Loading" state. Override to perform custom action.
11939      */
11940     showLoading : function(){
11941         if(this.showLoadIndicator){
11942             this.el.update(this.indicatorText);
11943         }
11944     },
11945
11946     /**
11947      * Adds unique parameter to query string if disableCaching = true
11948      * @private
11949      */
11950     prepareUrl : function(P){
11951         if(this.disableCaching){
11952             var  append = "_dc=" + (new  Date().getTime());
11953             if(P.indexOf("?") !== -1){
11954                 P += "&" + append;
11955             }else {
11956                 P += "?" + append;
11957             }
11958         }
11959         return  P;
11960     },
11961
11962     /**
11963      * @private
11964      */
11965     processSuccess : function(Q){
11966         this.transaction = null;
11967         if(Q.argument.form && Q.argument.reset){
11968             try{ // put in try/catch since some older FF releases had problems with this
11969                 Q.argument.form.reset();
11970             }catch(e){}
11971         }
11972         if(this.loadScripts){
11973             this.renderer.render(this.el, Q, this,
11974                 this.updateComplete.createDelegate(this, [Q]));
11975         }else {
11976             this.renderer.render(this.el, Q, this);
11977             this.updateComplete(Q);
11978         }
11979     },
11980
11981     updateComplete : function(R){
11982         this.fireEvent("update", this.el, R);
11983         if(typeof  R.argument.callback == "function"){
11984             R.argument.callback(this.el, true, R);
11985         }
11986     },
11987
11988     /**
11989      * @private
11990      */
11991     processFailure : function(S){
11992         this.transaction = null;
11993         this.fireEvent("failure", this.el, S);
11994         if(typeof  S.argument.callback == "function"){
11995             S.argument.callback(this.el, false, S);
11996         }
11997     },
11998
11999     /**
12000      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12001      * @param {Object} renderer The object implementing the render() method
12002      */
12003     setRenderer : function(T){
12004         this.renderer = T;
12005     },
12006
12007     getRenderer : function(){
12008        return  this.renderer;
12009     },
12010
12011     /**
12012      * Set the defaultUrl used for updates
12013      * @param {String/Function} defaultUrl The url or a function to call to get the url
12014      */
12015     setDefaultUrl : function(U){
12016         this.defaultUrl = U;
12017     },
12018
12019     /**
12020      * Aborts the executing transaction
12021      */
12022     abort : function(){
12023         if(this.transaction){
12024             Roo.Ajax.abort(this.transaction);
12025         }
12026     },
12027
12028     /**
12029      * Returns true if an update is in progress
12030      * @return {Boolean}
12031      */
12032     isUpdating : function(){
12033         if(this.transaction){
12034             return  Roo.Ajax.isLoading(this.transaction);
12035         }
12036         return  false;
12037     }
12038 });
12039
12040 /**
12041  * @class Roo.UpdateManager.defaults
12042  * @static (not really - but it helps the doc tool)
12043  * The defaults collection enables customizing the default properties of UpdateManager
12044  */
12045    Roo.UpdateManager.defaults = {
12046        /**
12047          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12048          * @type Number
12049          */
12050          timeout : 30,
12051
12052          /**
12053          * True to process scripts by default (Defaults to false).
12054          * @type Boolean
12055          */
12056         loadScripts : false,
12057
12058         /**
12059         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12060         * @type String
12061         */
12062         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12063         /**
12064          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12065          * @type Boolean
12066          */
12067         disableCaching : false,
12068         /**
12069          * Whether to show indicatorText when loading (Defaults to true).
12070          * @type Boolean
12071          */
12072         showLoadIndicator : true,
12073         /**
12074          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12075          * @type String
12076          */
12077         indicatorText : '<div class="loading-indicator">Loading...</div>'
12078    };
12079
12080 /**
12081  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12082  *Usage:
12083  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12084  * @param {String/HTMLElement/Roo.Element} el The element to update
12085  * @param {String} url The url
12086  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12087  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12088  * @static
12089  * @deprecated
12090  * @member Roo.UpdateManager
12091  */
12092 Roo.UpdateManager.updateElement = function(el, V, W, X){
12093     var  um = Roo.get(el, true).getUpdateManager();
12094     Roo.apply(um, X);
12095     um.update(V, W, X ? X.callback : null);
12096 };
12097 // alias for backwards compat
12098 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12099 /**
12100  * @class Roo.UpdateManager.BasicRenderer
12101  * Default Content renderer. Updates the elements innerHTML with the responseText.
12102  */
12103 Roo.UpdateManager.BasicRenderer = function(){};
12104
12105 Roo.UpdateManager.BasicRenderer.prototype = {
12106     /**
12107      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12108      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12109      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12110      * @param {Roo.Element} el The element being rendered
12111      * @param {Object} response The YUI Connect response object
12112      * @param {UpdateManager} updateManager The calling update manager
12113      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12114      */
12115      render : function(el, Y, Z, a){
12116         el.update(Y.responseText, Z.loadScripts, a);
12117     }
12118 };
12119
12120 /*
12121  * Based on:
12122  * Ext JS Library 1.1.1
12123  * Copyright(c) 2006-2007, Ext JS, LLC.
12124  *
12125  * Originally Released Under LGPL - original licence link has changed is not relivant.
12126  *
12127  * Fork - LGPL
12128  * <script type="text/javascript">
12129  */
12130
12131 /**
12132  * @class Roo.util.DelayedTask
12133  * Provides a convenient method of performing setTimeout where a new
12134  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12135  * You can use this class to buffer
12136  * the keypress events for a certain number of milliseconds, and perform only if they stop
12137  * for that amount of time.
12138  * @constructor The parameters to this constructor serve as defaults and are not required.
12139  * @param {Function} fn (optional) The default function to timeout
12140  * @param {Object} scope (optional) The default scope of that timeout
12141  * @param {Array} args (optional) The default Array of arguments
12142  */
12143 Roo.util.DelayedTask = function(fn, A, B){
12144     var  id = null, d, t;
12145
12146     var  C = function(){
12147         var  D = new  Date().getTime();
12148         if(D - t >= d){
12149             clearInterval(id);
12150             id = null;
12151             fn.apply(A, B || []);
12152         }
12153     };
12154     /**
12155      * Cancels any pending timeout and queues a new one
12156      * @param {Number} delay The milliseconds to delay
12157      * @param {Function} newFn (optional) Overrides function passed to constructor
12158      * @param {Object} newScope (optional) Overrides scope passed to constructor
12159      * @param {Array} newArgs (optional) Overrides args passed to constructor
12160      */
12161     this.delay = function(D, E, F, G){
12162         if(id && D != d){
12163             this.cancel();
12164         }
12165
12166         d = D;
12167         t = new  Date().getTime();
12168         fn = E || fn;
12169         A = F || A;
12170         B = G || B;
12171         if(!id){
12172             id = setInterval(C, d);
12173         }
12174     };
12175
12176     /**
12177      * Cancel the last queued timeout
12178      */
12179     this.cancel = function(){
12180         if(id){
12181             clearInterval(id);
12182             id = null;
12183         }
12184     };
12185 };
12186 /*
12187  * Based on:
12188  * Ext JS Library 1.1.1
12189  * Copyright(c) 2006-2007, Ext JS, LLC.
12190  *
12191  * Originally Released Under LGPL - original licence link has changed is not relivant.
12192  *
12193  * Fork - LGPL
12194  * <script type="text/javascript">
12195  */
12196  
12197  
12198 Roo.util.TaskRunner = function(A){
12199     A = A || 10;
12200     var  B = [], C = [];
12201     var  id = 0;
12202     var  D = false;
12203
12204     var  E = function(){
12205         D = false;
12206         clearInterval(id);
12207         id = 0;
12208     };
12209
12210     var  F = function(){
12211         if(!D){
12212             D = true;
12213             id = setInterval(H, A);
12214         }
12215     };
12216
12217     var  G = function(I){
12218         C.push(I);
12219         if(I.onStop){
12220             I.onStop();
12221         }
12222     };
12223
12224     var  H = function(){
12225         if(C.length > 0){
12226             for(var  i = 0, len = C.length; i < len; i++){
12227                 B.remove(C[i]);
12228             }
12229
12230             C = [];
12231             if(B.length < 1){
12232                 E();
12233                 return;
12234             }
12235         }
12236         var  I = new  Date().getTime();
12237         for(var  i = 0, len = B.length; i < len; ++i){
12238             var  t = B[i];
12239             var  itime = I - t.taskRunTime;
12240             if(t.interval <= itime){
12241                 var  rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12242                 t.taskRunTime = I;
12243                 if(rt === false || t.taskRunCount === t.repeat){
12244                     G(t);
12245                     return;
12246                 }
12247             }
12248             if(t.duration && t.duration <= (I - t.taskStartTime)){
12249                 G(t);
12250             }
12251         }
12252     };
12253
12254     /**
12255      * Queues a new task.
12256      * @param {Object} task
12257      */
12258     this.start = function(I){
12259         B.push(I);
12260         I.taskStartTime = new  Date().getTime();
12261         I.taskRunTime = 0;
12262         I.taskRunCount = 0;
12263         F();
12264         return  I;
12265     };
12266
12267     this.stop = function(I){
12268         G(I);
12269         return  I;
12270     };
12271
12272     this.stopAll = function(){
12273         E();
12274         for(var  i = 0, len = B.length; i < len; i++){
12275             if(B[i].onStop){
12276                 B[i].onStop();
12277             }
12278         }
12279
12280         B = [];
12281         C = [];
12282     };
12283 };
12284
12285 Roo.TaskMgr = new  Roo.util.TaskRunner();
12286 /*
12287  * Based on:
12288  * Ext JS Library 1.1.1
12289  * Copyright(c) 2006-2007, Ext JS, LLC.
12290  *
12291  * Originally Released Under LGPL - original licence link has changed is not relivant.
12292  *
12293  * Fork - LGPL
12294  * <script type="text/javascript">
12295  */
12296
12297  
12298 /**
12299  * @class Roo.util.MixedCollection
12300  * @extends Roo.util.Observable
12301  * A Collection class that maintains both numeric indexes and keys and exposes events.
12302  * @constructor
12303  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12304  * collection (defaults to false)
12305  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12306  * and return the key value for that item.  This is used when available to look up the key on items that
12307  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12308  * equivalent to providing an implementation for the {@link #getKey} method.
12309  */
12310 Roo.util.MixedCollection = function(A, B){
12311     this.items = [];
12312     this.map = {};
12313     this.keys = [];
12314     this.length = 0;
12315     this.addEvents({
12316         /**
12317          * @event clear
12318          * Fires when the collection is cleared.
12319          */
12320         "clear" : true,
12321         /**
12322          * @event add
12323          * Fires when an item is added to the collection.
12324          * @param {Number} index The index at which the item was added.
12325          * @param {Object} o The item added.
12326          * @param {String} key The key associated with the added item.
12327          */
12328         "add" : true,
12329         /**
12330          * @event replace
12331          * Fires when an item is replaced in the collection.
12332          * @param {String} key he key associated with the new added.
12333          * @param {Object} old The item being replaced.
12334          * @param {Object} new The new item.
12335          */
12336         "replace" : true,
12337         /**
12338          * @event remove
12339          * Fires when an item is removed from the collection.
12340          * @param {Object} o The item being removed.
12341          * @param {String} key (optional) The key associated with the removed item.
12342          */
12343         "remove" : true,
12344         "sort" : true
12345     });
12346     this.allowFunctions = A === true;
12347     if(B){
12348         this.getKey = B;
12349     }
12350
12351     Roo.util.MixedCollection.superclass.constructor.call(this);
12352 };
12353
12354 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12355     allowFunctions : false,
12356     
12357 /**
12358  * Adds an item to the collection.
12359  * @param {String} key The key to associate with the item
12360  * @param {Object} o The item to add.
12361  * @return {Object} The item added.
12362  */
12363     add : function(C, o){
12364         if(arguments.length == 1){
12365             o = arguments[0];
12366             C = this.getKey(o);
12367         }
12368         if(typeof  C == "undefined" || C === null){
12369             this.length++;
12370             this.items.push(o);
12371             this.keys.push(null);
12372         }else {
12373             var  old = this.map[C];
12374             if(old){
12375                 return  this.replace(C, o);
12376             }
12377
12378             this.length++;
12379             this.items.push(o);
12380             this.map[C] = o;
12381             this.keys.push(C);
12382         }
12383
12384         this.fireEvent("add", this.length-1, o, C);
12385         return  o;
12386     },
12387    
12388 /**
12389   * MixedCollection has a generic way to fetch keys if you implement getKey.
12390 <pre><code>
12391 // normal way
12392 var mc = new Roo.util.MixedCollection();
12393 mc.add(someEl.dom.id, someEl);
12394 mc.add(otherEl.dom.id, otherEl);
12395 //and so on
12396
12397 // using getKey
12398 var mc = new Roo.util.MixedCollection();
12399 mc.getKey = function(el){
12400    return el.dom.id;
12401 };
12402 mc.add(someEl);
12403 mc.add(otherEl);
12404
12405 // or via the constructor
12406 var mc = new Roo.util.MixedCollection(false, function(el){
12407    return el.dom.id;
12408 });
12409 mc.add(someEl);
12410 mc.add(otherEl);
12411 </code></pre>
12412  * @param o {Object} The item for which to find the key.
12413  * @return {Object} The key for the passed item.
12414  */
12415     getKey : function(o){
12416          return  o.id; 
12417     },
12418    
12419 /**
12420  * Replaces an item in the collection.
12421  * @param {String} key The key associated with the item to replace, or the item to replace.
12422  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12423  * @return {Object}  The new item.
12424  */
12425     replace : function(D, o){
12426         if(arguments.length == 1){
12427             o = arguments[0];
12428             D = this.getKey(o);
12429         }
12430         var  E = this.item(D);
12431         if(typeof  D == "undefined" || D === null || typeof  E == "undefined"){
12432              return  this.add(D, o);
12433         }
12434         var  F = this.indexOfKey(D);
12435         this.items[F] = o;
12436         this.map[D] = o;
12437         this.fireEvent("replace", D, E, o);
12438         return  o;
12439     },
12440    
12441 /**
12442  * Adds all elements of an Array or an Object to the collection.
12443  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12444  * an Array of values, each of which are added to the collection.
12445  */
12446     addAll : function(G){
12447         if(arguments.length > 1 || G  instanceof  Array){
12448             var  args = arguments.length > 1 ? arguments : G;
12449             for(var  i = 0, len = args.length; i < len; i++){
12450                 this.add(args[i]);
12451             }
12452         }else {
12453             for(var  D  in  G){
12454                 if(this.allowFunctions || typeof  G[D] != "function"){
12455                     this.add(D, G[D]);
12456                 }
12457             }
12458         }
12459     },
12460    
12461 /**
12462  * Executes the specified function once for every item in the collection, passing each
12463  * item as the first and only parameter. returning false from the function will stop the iteration.
12464  * @param {Function} fn The function to execute for each item.
12465  * @param {Object} scope (optional) The scope in which to execute the function.
12466  */
12467     each : function(fn, H){
12468         var  I = [].concat(this.items); // each safe for removal
12469         for(var  i = 0, len = I.length; i < len; i++){
12470             if(fn.call(H || I[i], I[i], i, len) === false){
12471                 break;
12472             }
12473         }
12474     },
12475    
12476 /**
12477  * Executes the specified function once for every key in the collection, passing each
12478  * key, and its associated item as the first two parameters.
12479  * @param {Function} fn The function to execute for each item.
12480  * @param {Object} scope (optional) The scope in which to execute the function.
12481  */
12482     eachKey : function(fn, J){
12483         for(var  i = 0, len = this.keys.length; i < len; i++){
12484             fn.call(J || window, this.keys[i], this.items[i], i, len);
12485         }
12486     },
12487    
12488 /**
12489  * Returns the first item in the collection which elicits a true return value from the
12490  * passed selection function.
12491  * @param {Function} fn The selection function to execute for each item.
12492  * @param {Object} scope (optional) The scope in which to execute the function.
12493  * @return {Object} The first item in the collection which returned true from the selection function.
12494  */
12495     find : function(fn, K){
12496         for(var  i = 0, len = this.items.length; i < len; i++){
12497             if(fn.call(K || window, this.items[i], this.keys[i])){
12498                 return  this.items[i];
12499             }
12500         }
12501         return  null;
12502     },
12503    
12504 /**
12505  * Inserts an item at the specified index in the collection.
12506  * @param {Number} index The index to insert the item at.
12507  * @param {String} key The key to associate with the new item, or the item itself.
12508  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12509  * @return {Object} The item inserted.
12510  */
12511     insert : function(L, M, o){
12512         if(arguments.length == 2){
12513             o = arguments[1];
12514             M = this.getKey(o);
12515         }
12516         if(L >= this.length){
12517             return  this.add(M, o);
12518         }
12519
12520         this.length++;
12521         this.items.splice(L, 0, o);
12522         if(typeof  M != "undefined" && M != null){
12523             this.map[M] = o;
12524         }
12525
12526         this.keys.splice(L, 0, M);
12527         this.fireEvent("add", L, o, M);
12528         return  o;
12529     },
12530    
12531 /**
12532  * Removed an item from the collection.
12533  * @param {Object} o The item to remove.
12534  * @return {Object} The item removed.
12535  */
12536     remove : function(o){
12537         return  this.removeAt(this.indexOf(o));
12538     },
12539    
12540 /**
12541  * Remove an item from a specified index in the collection.
12542  * @param {Number} index The index within the collection of the item to remove.
12543  */
12544     removeAt : function(N){
12545         if(N < this.length && N >= 0){
12546             this.length--;
12547             var  o = this.items[N];
12548             this.items.splice(N, 1);
12549             var  M = this.keys[N];
12550             if(typeof  M != "undefined"){
12551                 delete  this.map[M];
12552             }
12553
12554             this.keys.splice(N, 1);
12555             this.fireEvent("remove", o, M);
12556         }
12557     },
12558    
12559 /**
12560  * Removed an item associated with the passed key fom the collection.
12561  * @param {String} key The key of the item to remove.
12562  */
12563     removeKey : function(O){
12564         return  this.removeAt(this.indexOfKey(O));
12565     },
12566    
12567 /**
12568  * Returns the number of items in the collection.
12569  * @return {Number} the number of items in the collection.
12570  */
12571     getCount : function(){
12572         return  this.length; 
12573     },
12574    
12575 /**
12576  * Returns index within the collection of the passed Object.
12577  * @param {Object} o The item to find the index of.
12578  * @return {Number} index of the item.
12579  */
12580     indexOf : function(o){
12581         if(!this.items.indexOf){
12582             for(var  i = 0, len = this.items.length; i < len; i++){
12583                 if(this.items[i] == o) return  i;
12584             }
12585             return  -1;
12586         }else {
12587             return  this.items.indexOf(o);
12588         }
12589     },
12590    
12591 /**
12592  * Returns index within the collection of the passed key.
12593  * @param {String} key The key to find the index of.
12594  * @return {Number} index of the key.
12595  */
12596     indexOfKey : function(P){
12597         if(!this.keys.indexOf){
12598             for(var  i = 0, len = this.keys.length; i < len; i++){
12599                 if(this.keys[i] == P) return  i;
12600             }
12601             return  -1;
12602         }else {
12603             return  this.keys.indexOf(P);
12604         }
12605     },
12606    
12607 /**
12608  * Returns the item associated with the passed key OR index. Key has priority over index.
12609  * @param {String/Number} key The key or index of the item.
12610  * @return {Object} The item associated with the passed key.
12611  */
12612     item : function(Q){
12613         var  R = typeof  this.map[Q] != "undefined" ? this.map[Q] : this.items[Q];
12614         return  typeof  R != 'function' || this.allowFunctions ? R : null; // for prototype!
12615     },
12616     
12617 /**
12618  * Returns the item at the specified index.
12619  * @param {Number} index The index of the item.
12620  * @return {Object}
12621  */
12622     itemAt : function(S){
12623         return  this.items[S];
12624     },
12625     
12626 /**
12627  * Returns the item associated with the passed key.
12628  * @param {String/Number} key The key of the item.
12629  * @return {Object} The item associated with the passed key.
12630  */
12631     key : function(T){
12632         return  this.map[T];
12633     },
12634    
12635 /**
12636  * Returns true if the collection contains the passed Object as an item.
12637  * @param {Object} o  The Object to look for in the collection.
12638  * @return {Boolean} True if the collection contains the Object as an item.
12639  */
12640     contains : function(o){
12641         return  this.indexOf(o) != -1;
12642     },
12643    
12644 /**
12645  * Returns true if the collection contains the passed Object as a key.
12646  * @param {String} key The key to look for in the collection.
12647  * @return {Boolean} True if the collection contains the Object as a key.
12648  */
12649     containsKey : function(U){
12650         return  typeof  this.map[U] != "undefined";
12651     },
12652    
12653 /**
12654  * Removes all items from the collection.
12655  */
12656     clear : function(){
12657         this.length = 0;
12658         this.items = [];
12659         this.keys = [];
12660         this.map = {};
12661         this.fireEvent("clear");
12662     },
12663    
12664 /**
12665  * Returns the first item in the collection.
12666  * @return {Object} the first item in the collection..
12667  */
12668     first : function(){
12669         return  this.items[0]; 
12670     },
12671    
12672 /**
12673  * Returns the last item in the collection.
12674  * @return {Object} the last item in the collection..
12675  */
12676     last : function(){
12677         return  this.items[this.length-1];   
12678     },
12679     
12680     _sort : function(V, W, fn){
12681         var  X = String(W).toUpperCase() == "DESC" ? -1 : 1;
12682         fn = fn || function(a, b){
12683             return  a-b;
12684         };
12685         var  c = [], k = this.keys, Y = this.items;
12686         for(var  i = 0, len = Y.length; i < len; i++){
12687             c[c.length] = {key: k[i], value: Y[i], index: i};
12688         }
12689
12690         c.sort(function(a, b){
12691             var  v = fn(a[V], b[V]) * X;
12692             if(v == 0){
12693                 v = (a.index < b.index ? -1 : 1);
12694             }
12695             return  v;
12696         });
12697         for(var  i = 0, len = c.length; i < len; i++){
12698             Y[i] = c[i].value;
12699             k[i] = c[i].key;
12700         }
12701
12702         this.fireEvent("sort", this);
12703     },
12704     
12705     /**
12706      * Sorts this collection with the passed comparison function
12707      * @param {String} direction (optional) "ASC" or "DESC"
12708      * @param {Function} fn (optional) comparison function
12709      */
12710     sort : function(Z, fn){
12711         this._sort("value", Z, fn);
12712     },
12713     
12714     /**
12715      * Sorts this collection by keys
12716      * @param {String} direction (optional) "ASC" or "DESC"
12717      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12718      */
12719     keySort : function(a, fn){
12720         this._sort("key", a, fn || function(a, b){
12721             return  String(a).toUpperCase()-String(b).toUpperCase();
12722         });
12723     },
12724     
12725     /**
12726      * Returns a range of items in this collection
12727      * @param {Number} startIndex (optional) defaults to 0
12728      * @param {Number} endIndex (optional) default to the last item
12729      * @return {Array} An array of items
12730      */
12731     getRange : function(b, d){
12732         var  e = this.items;
12733         if(e.length < 1){
12734             return  [];
12735         }
12736
12737         b = b || 0;
12738         d = Math.min(typeof  d == "undefined" ? this.length-1 : d, this.length-1);
12739         var  r = [];
12740         if(b <= d){
12741             for(var  i = b; i <= d; i++) {
12742                     r[r.length] = e[i];
12743             }
12744         }else {
12745             for(var  i = b; i >= d; i--) {
12746                     r[r.length] = e[i];
12747             }
12748         }
12749         return  r;
12750     },
12751         
12752     /**
12753      * Filter the <i>objects</i> in this collection by a specific property. 
12754      * Returns a new collection that has been filtered.
12755      * @param {String} property A property on your objects
12756      * @param {String/RegExp} value Either string that the property values 
12757      * should start with or a RegExp to test against the property
12758      * @return {MixedCollection} The new filtered collection
12759      */
12760     filter : function(f, g){
12761         if(!g.exec){ // not a regex
12762             g = String(g);
12763             if(g.length == 0){
12764                 return  this.clone();
12765             }
12766
12767             g = new  RegExp("^" + Roo.escapeRe(g), "i");
12768         }
12769         return  this.filterBy(function(o){
12770             return  o && g.test(o[f]);
12771         });
12772         },
12773     
12774     /**
12775      * Filter by a function. * Returns a new collection that has been filtered.
12776      * The passed function will be called with each 
12777      * object in the collection. If the function returns true, the value is included 
12778      * otherwise it is filtered.
12779      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12780      * @param {Object} scope (optional) The scope of the function (defaults to this) 
12781      * @return {MixedCollection} The new filtered collection
12782      */
12783     filterBy : function(fn, h){
12784         var  r = new  Roo.util.MixedCollection();
12785         r.getKey = this.getKey;
12786         var  k = this.keys, it = this.items;
12787         for(var  i = 0, len = it.length; i < len; i++){
12788             if(fn.call(h||this, it[i], k[i])){
12789                                 r.add(k[i], it[i]);
12790                         }
12791         }
12792         return  r;
12793     },
12794     
12795     /**
12796      * Creates a duplicate of this collection
12797      * @return {MixedCollection}
12798      */
12799     clone : function(){
12800         var  r = new  Roo.util.MixedCollection();
12801         var  k = this.keys, it = this.items;
12802         for(var  i = 0, len = it.length; i < len; i++){
12803             r.add(k[i], it[i]);
12804         }
12805
12806         r.getKey = this.getKey;
12807         return  r;
12808     }
12809 });
12810 /**
12811  * Returns the item associated with the passed key or index.
12812  * @method
12813  * @param {String/Number} key The key or index of the item.
12814  * @return {Object} The item associated with the passed key.
12815  */
12816 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;
12817 /*
12818  * Based on:
12819  * Ext JS Library 1.1.1
12820  * Copyright(c) 2006-2007, Ext JS, LLC.
12821  *
12822  * Originally Released Under LGPL - original licence link has changed is not relivant.
12823  *
12824  * Fork - LGPL
12825  * <script type="text/javascript">
12826  */
12827 /**
12828  * @class Roo.util.JSON
12829  * Modified version of Douglas Crockford"s json.js that doesn"t
12830  * mess with the Object prototype 
12831  * http://www.json.org/js.html
12832  * @singleton
12833  */
12834 Roo.util.JSON = new  (function(){
12835     var  A = {}.hasOwnProperty ? true : false;
12836     
12837     // crashes Safari in some instances
12838     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12839     
12840     var  B = function(n) {
12841         return  n < 10 ? "0" + n : n;
12842     };
12843     
12844     var  m = {
12845         "\b": '\\b',
12846         "\t": '\\t',
12847         "\n": '\\n',
12848         "\f": '\\f',
12849         "\r": '\\r',
12850         '"' : '\\"',
12851         "\\": '\\\\'
12852     };
12853
12854     var  C = function(s){
12855         if (/["\\\x00-\x1f]/.test(s)) {
12856             return  '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12857                 var  c = m[b];
12858                 if(c){
12859                     return  c;
12860                 }
12861
12862                 c = b.charCodeAt();
12863                 return  "\\u00" +
12864                     Math.floor(c / 16).toString(16) +
12865                     (c % 16).toString(16);
12866             }) + '"';
12867         }
12868         return  '"' + s + '"';
12869     };
12870     
12871     var  D = function(o){
12872         var  a = ["["], b, i, l = o.length, v;
12873             for (i = 0; i < l; i += 1) {
12874                 v = o[i];
12875                 switch (typeof  v) {
12876                     case  "undefined":
12877                     case  "function":
12878                     case  "unknown":
12879                         break;
12880                     default:
12881                         if (b) {
12882                             a.push(',');
12883                         }
12884
12885                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12886                         b = true;
12887                 }
12888             }
12889
12890             a.push("]");
12891             return  a.join("");
12892     };
12893     
12894     var  E = function(o){
12895         return  '"' + o.getFullYear() + "-" +
12896                 B(o.getMonth() + 1) + "-" +
12897                 B(o.getDate()) + "T" +
12898                 B(o.getHours()) + ":" +
12899                 B(o.getMinutes()) + ":" +
12900                 B(o.getSeconds()) + '"';
12901     };
12902     
12903     /**
12904      * Encodes an Object, Array or other value
12905      * @param {Mixed} o The variable to encode
12906      * @return {String} The JSON string
12907      */
12908     this.encode = function(o){
12909         if(typeof  o == "undefined" || o === null){
12910             return  "null";
12911         }else  if(o  instanceof  Array){
12912             return  D(o);
12913         }else  if(o  instanceof  Date){
12914             return  E(o);
12915         }else  if(typeof  o == "string"){
12916             return  C(o);
12917         }else  if(typeof  o == "number"){
12918             return  isFinite(o) ? String(o) : "null";
12919         }else  if(typeof  o == "boolean"){
12920             return  String(o);
12921         }else  {
12922             var  a = ["{"], b, i, v;
12923             for (i  in  o) {
12924                 if(!A || o.hasOwnProperty(i)) {
12925                     v = o[i];
12926                     switch (typeof  v) {
12927                     case  "undefined":
12928                     case  "function":
12929                     case  "unknown":
12930                         break;
12931                     default:
12932                         if(b){
12933                             a.push(',');
12934                         }
12935
12936                         a.push(this.encode(i), ":",
12937                                 v === null ? "null" : this.encode(v));
12938                         b = true;
12939                     }
12940                 }
12941             }
12942
12943             a.push("}");
12944             return  a.join("");
12945         }
12946     };
12947     
12948     /**
12949      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12950      * @param {String} json The JSON string
12951      * @return {Object} The resulting object
12952      */
12953     this.decode = function(F){
12954         /**
12955          * eval:var:json
12956          */
12957         return  eval("(" + F + ')');
12958     };
12959 })();
12960 /** 
12961  * Shorthand for {@link Roo.util.JSON#encode}
12962  * @member Roo encode 
12963  * @method */
12964 Roo.encode = Roo.util.JSON.encode;
12965 /** 
12966  * Shorthand for {@link Roo.util.JSON#decode}
12967  * @member Roo decode 
12968  * @method */
12969 Roo.decode = Roo.util.JSON.decode;
12970
12971 /*
12972  * Based on:
12973  * Ext JS Library 1.1.1
12974  * Copyright(c) 2006-2007, Ext JS, LLC.
12975  *
12976  * Originally Released Under LGPL - original licence link has changed is not relivant.
12977  *
12978  * Fork - LGPL
12979  * <script type="text/javascript">
12980  */
12981  
12982 /**
12983  * @class Roo.util.Format
12984  * Reusable data formatting functions
12985  * @singleton
12986  */
12987 Roo.util.Format = function(){
12988     var  A = /^\s+|\s+$/g;
12989     return  {
12990         /**
12991          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12992          * @param {String} value The string to truncate
12993          * @param {Number} length The maximum length to allow before truncating
12994          * @return {String} The converted text
12995          */
12996         ellipsis : function(S, T){
12997             if(S && S.length > T){
12998                 return  S.substr(0, T-3)+"...";
12999             }
13000             return  S;
13001         },
13002
13003         /**
13004          * Checks a reference and converts it to empty string if it is undefined
13005          * @param {Mixed} value Reference to check
13006          * @return {Mixed} Empty string if converted, otherwise the original value
13007          */
13008         undef : function(U){
13009             return  typeof  U != "undefined" ? U : "";
13010         },
13011
13012         /**
13013          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13014          * @param {String} value The string to encode
13015          * @return {String} The encoded text
13016          */
13017         htmlEncode : function(V){
13018             return  !V ? V : String(V).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13019         },
13020
13021         /**
13022          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13023          * @param {String} value The string to decode
13024          * @return {String} The decoded text
13025          */
13026         htmlDecode : function(W){
13027             return  !W ? W : String(W).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13028         },
13029
13030         /**
13031          * Trims any whitespace from either side of a string
13032          * @param {String} value The text to trim
13033          * @return {String} The trimmed text
13034          */
13035         trim : function(X){
13036             return  String(X).replace(A, "");
13037         },
13038
13039         /**
13040          * Returns a substring from within an original string
13041          * @param {String} value The original text
13042          * @param {Number} start The start index of the substring
13043          * @param {Number} length The length of the substring
13044          * @return {String} The substring
13045          */
13046         substr : function(Y, Z, a){
13047             return  String(Y).substr(Z, a);
13048         },
13049
13050         /**
13051          * Converts a string to all lower case letters
13052          * @param {String} value The text to convert
13053          * @return {String} The converted text
13054          */
13055         lowercase : function(b){
13056             return  String(b).toLowerCase();
13057         },
13058
13059         /**
13060          * Converts a string to all upper case letters
13061          * @param {String} value The text to convert
13062          * @return {String} The converted text
13063          */
13064         uppercase : function(c){
13065             return  String(c).toUpperCase();
13066         },
13067
13068         /**
13069          * Converts the first character only of a string to upper case
13070          * @param {String} value The text to convert
13071          * @return {String} The converted text
13072          */
13073         capitalize : function(d){
13074             return  !d ? d : d.charAt(0).toUpperCase() + d.substr(1).toLowerCase();
13075         },
13076
13077         // private
13078         call : function(e, fn){
13079             if(arguments.length > 2){
13080                 var  args = Array.prototype.slice.call(arguments, 2);
13081                 args.unshift(e);
13082                  
13083                 return  /** eval:var:value */  eval(fn).apply(window, args);
13084             }else {
13085                 /** eval:var:value */
13086                 return  /** eval:var:value */ eval(fn).call(window, e);
13087             }
13088         },
13089
13090         /**
13091          * Format a number as US currency
13092          * @param {Number/String} value The numeric value to format
13093          * @return {String} The formatted currency string
13094          */
13095         usMoney : function(v){
13096             v = (Math.round((v-0)*100))/100;
13097             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13098             v = String(v);
13099             var  ps = v.split('.');
13100             var  f = ps[0];
13101             var  g = ps[1] ? '.'+ ps[1] : '.00';
13102             var  r = /(\d+)(\d{3})/;
13103             while (r.test(f)) {
13104                 f = f.replace(r, '$1' + ',' + '$2');
13105             }
13106             return  "$" + f + g ;
13107         },
13108
13109         /**
13110          * Parse a value into a formatted date using the specified format pattern.
13111          * @param {Mixed} value The value to format
13112          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13113          * @return {String} The formatted date string
13114          */
13115         date : function(v, h){
13116             if(!v){
13117                 return  "";
13118             }
13119             if(!(v  instanceof  Date)){
13120                 v = new  Date(Date.parse(v));
13121             }
13122             return  v.dateFormat(h || "m/d/Y");
13123         },
13124
13125         /**
13126          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13127          * @param {String} format Any valid date format string
13128          * @return {Function} The date formatting function
13129          */
13130         dateRenderer : function(i){
13131             return  function(v){
13132                 return  Roo.util.Format.date(v, i);  
13133             };
13134         },
13135
13136         // private
13137         stripTagsRE : /<\/?[^>]+>/gi,
13138         
13139         /**
13140          * Strips all HTML tags
13141          * @param {Mixed} value The text from which to strip tags
13142          * @return {String} The stripped text
13143          */
13144         stripTags : function(v){
13145             return  !v ? v : String(v).replace(this.stripTagsRE, "");
13146         }
13147     };
13148 }();
13149 /*
13150  * Based on:
13151  * Ext JS Library 1.1.1
13152  * Copyright(c) 2006-2007, Ext JS, LLC.
13153  *
13154  * Originally Released Under LGPL - original licence link has changed is not relivant.
13155  *
13156  * Fork - LGPL
13157  * <script type="text/javascript">
13158  */
13159
13160
13161  
13162
13163 /**
13164  * @class Roo.MasterTemplate
13165  * @extends Roo.Template
13166  * Provides a template that can have child templates. The syntax is:
13167 <pre><code>
13168 var t = new Roo.MasterTemplate(
13169         '&lt;select name="{name}"&gt;',
13170                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13171         '&lt;/select&gt;'
13172 );
13173 t.add('options', {value: 'foo', text: 'bar'});
13174 // or you can add multiple child elements in one shot
13175 t.addAll('options', [
13176     {value: 'foo', text: 'bar'},
13177     {value: 'foo2', text: 'bar2'},
13178     {value: 'foo3', text: 'bar3'}
13179 ]);
13180 // then append, applying the master template values
13181 t.append('my-form', {name: 'my-select'});
13182 </code></pre>
13183 * A name attribute for the child template is not required if you have only one child
13184 * template or you want to refer to them by index.
13185  */
13186 Roo.MasterTemplate = function(){
13187     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13188     this.originalHtml = this.html;
13189     var  st = {};
13190     var  m, re = this.subTemplateRe;
13191     re.lastIndex = 0;
13192     var  A = 0;
13193     while(m = re.exec(this.html)){
13194         var  name = m[1], content = m[2];
13195         st[A] = {
13196             name: name,
13197             index: A,
13198             buffer: [],
13199             tpl : new  Roo.Template(content)
13200         };
13201         if(name){
13202             st[name] = st[A];
13203         }
13204
13205         st[A].tpl.compile();
13206         st[A].tpl.call = this.call.createDelegate(this);
13207         A++;
13208     }
13209
13210     this.subCount = A;
13211     this.subs = st;
13212 };
13213 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13214     /**
13215     * The regular expression used to match sub templates
13216     * @type RegExp
13217     * @property
13218     */
13219     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13220
13221     /**
13222      * Applies the passed values to a child template.
13223      * @param {String/Number} name (optional) The name or index of the child template
13224      * @param {Array/Object} values The values to be applied to the template
13225      * @return {MasterTemplate} this
13226      */
13227      add : function(B, C){
13228         if(arguments.length == 1){
13229             C = arguments[0];
13230             B = 0;
13231         }
13232         var  s = this.subs[B];
13233         s.buffer[s.buffer.length] = s.tpl.apply(C);
13234         return  this;
13235     },
13236
13237     /**
13238      * Applies all the passed values to a child template.
13239      * @param {String/Number} name (optional) The name or index of the child template
13240      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13241      * @param {Boolean} reset (optional) True to reset the template first
13242      * @return {MasterTemplate} this
13243      */
13244     fill : function(D, E, F){
13245         var  a = arguments;
13246         if(a.length == 1 || (a.length == 2 && typeof  a[1] == "boolean")){
13247             E = a[0];
13248             D = 0;
13249             F = a[1];
13250         }
13251         if(F){
13252             this.reset();
13253         }
13254         for(var  i = 0, len = E.length; i < len; i++){
13255             this.add(D, E[i]);
13256         }
13257         return  this;
13258     },
13259
13260     /**
13261      * Resets the template for reuse
13262      * @return {MasterTemplate} this
13263      */
13264      reset : function(){
13265         var  s = this.subs;
13266         for(var  i = 0; i < this.subCount; i++){
13267             s[i].buffer = [];
13268         }
13269         return  this;
13270     },
13271
13272     applyTemplate : function(G){
13273         var  s = this.subs;
13274         var  H = -1;
13275         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, I){
13276             return  s[++H].buffer.join("");
13277         });
13278         return  Roo.MasterTemplate.superclass.applyTemplate.call(this, G);
13279     },
13280
13281     apply : function(){
13282         return  this.applyTemplate.apply(this, arguments);
13283     },
13284
13285     compile : function(){return  this;}
13286 });
13287
13288 /**
13289  * Alias for fill().
13290  * @method
13291  */
13292 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13293  /**
13294  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13295  * var tpl = Roo.MasterTemplate.from('element-id');
13296  * @param {String/HTMLElement} el
13297  * @param {Object} config
13298  * @static
13299  */
13300 Roo.MasterTemplate.from = function(el, I){
13301     el = Roo.getDom(el);
13302     return  new  Roo.MasterTemplate(el.value || el.innerHTML, I || '');
13303 };
13304 /*
13305  * Based on:
13306  * Ext JS Library 1.1.1
13307  * Copyright(c) 2006-2007, Ext JS, LLC.
13308  *
13309  * Originally Released Under LGPL - original licence link has changed is not relivant.
13310  *
13311  * Fork - LGPL
13312  * <script type="text/javascript">
13313  */
13314
13315  
13316 /**
13317  * @class Roo.util.CSS
13318  * Utility class for manipulating CSS rules
13319  * @singleton
13320  */
13321 Roo.util.CSS = function(){
13322         var  A = null;
13323         var  B = document;
13324
13325     var  C = /(-[a-z])/gi;
13326     var  D = function(m, a){ return  a.charAt(1).toUpperCase(); };
13327
13328    return  {
13329    /**
13330     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13331     * tag and appended to the HEAD of the document.
13332     * @param {String} cssText The text containing the css rules
13333     * @param {String} id An id to add to the stylesheet for later removal
13334     * @return {StyleSheet}
13335     */
13336    createStyleSheet : function(P, id){
13337        var  ss;
13338        var  Q = B.getElementsByTagName("head")[0];
13339        var  R = B.createElement("style");
13340        R.setAttribute("type", "text/css");
13341        if(id){
13342            R.setAttribute("id", id);
13343        }
13344        if(Roo.isIE){
13345            Q.appendChild(R);
13346            ss = R.styleSheet;
13347            ss.cssText = P;
13348        }else {
13349            try{
13350                 R.appendChild(B.createTextNode(P));
13351            }catch(e){
13352                R.cssText = P; 
13353            }
13354
13355            Q.appendChild(R);
13356            ss = R.styleSheet ? R.styleSheet : (R.sheet || B.styleSheets[B.styleSheets.length-1]);
13357        }
13358
13359        this.cacheStyleSheet(ss);
13360        return  ss;
13361    },
13362
13363    /**
13364     * Removes a style or link tag by id
13365     * @param {String} id The id of the tag
13366     */
13367    removeStyleSheet : function(id){
13368        var  S = B.getElementById(id);
13369        if(S){
13370            S.parentNode.removeChild(S);
13371        }
13372    },
13373
13374    /**
13375     * Dynamically swaps an existing stylesheet reference for a new one
13376     * @param {String} id The id of an existing link tag to remove
13377     * @param {String} url The href of the new stylesheet to include
13378     */
13379    swapStyleSheet : function(id, T){
13380        this.removeStyleSheet(id);
13381        var  ss = B.createElement("link");
13382        ss.setAttribute("rel", "stylesheet");
13383        ss.setAttribute("type", "text/css");
13384        ss.setAttribute("id", id);
13385        ss.setAttribute("href", T);
13386        B.getElementsByTagName("head")[0].appendChild(ss);
13387    },
13388    
13389    /**
13390     * Refresh the rule cache if you have dynamically added stylesheets
13391     * @return {Object} An object (hash) of rules indexed by selector
13392     */
13393    refreshCache : function(){
13394        return  this.getRules(true);
13395    },
13396
13397    // private
13398    cacheStyleSheet : function(ss){
13399        if(!R){
13400            R = {};
13401        }
13402        try{// try catch for cross domain access issue
13403            var  ssRules = ss.cssRules || ss.rules;
13404            for(var  j = ssRules.length-1; j >= 0; --j){
13405                R[ssRules[j].selectorText] = ssRules[j];
13406            }
13407        }catch(e){}
13408    },
13409    
13410    /**
13411     * Gets all css rules for the document
13412     * @param {Boolean} refreshCache true to refresh the internal cache
13413     * @return {Object} An object (hash) of rules indexed by selector
13414     */
13415    getRules : function(U){
13416                 if(R == null || U){
13417                         R = {};
13418                         var  ds = B.styleSheets;
13419                         for(var  i =0, len = ds.length; i < len; i++){
13420                             try{
13421                         this.cacheStyleSheet(ds[i]);
13422                     }catch(e){} 
13423                 }
13424                 }
13425                 return  R;
13426         },
13427         
13428         /**
13429     * Gets an an individual CSS rule by selector(s)
13430     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13431     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13432     * @return {CSSRule} The CSS rule or null if one is not found
13433     */
13434    getRule : function(V, W){
13435                 var  rs = this.getRules(W);
13436                 if(!(V  instanceof  Array)){
13437                     return  rs[V];
13438                 }
13439                 for(var  i = 0; i < V.length; i++){
13440                         if(rs[V[i]]){
13441                                 return  rs[V[i]];
13442                         }
13443                 }
13444                 return  null;
13445         },
13446         
13447         
13448         /**
13449     * Updates a rule property
13450     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13451     * @param {String} property The css property
13452     * @param {String} value The new value for the property
13453     * @return {Boolean} true If a rule was found and updated
13454     */
13455    updateRule : function(X, Y, Z){
13456                 if(!(X  instanceof  Array)){
13457                         var  rule = this.getRule(X);
13458                         if(rule){
13459                                 rule.style[Y.replace(C, D)] = Z;
13460                                 return  true;
13461                         }
13462                 }else {
13463                         for(var  i = 0; i < X.length; i++){
13464                                 if(this.updateRule(X[i], Y, Z)){
13465                                         return  true;
13466                                 }
13467                         }
13468                 }
13469                 return  false;
13470         }
13471    };   
13472 }();
13473 /*
13474  * Based on:
13475  * Ext JS Library 1.1.1
13476  * Copyright(c) 2006-2007, Ext JS, LLC.
13477  *
13478  * Originally Released Under LGPL - original licence link has changed is not relivant.
13479  *
13480  * Fork - LGPL
13481  * <script type="text/javascript">
13482  */
13483
13484  
13485
13486 /**
13487  * @class Roo.util.ClickRepeater
13488  * @extends Roo.util.Observable
13489  * 
13490  * A wrapper class which can be applied to any element. Fires a "click" event while the
13491  * mouse is pressed. The interval between firings may be specified in the config but
13492  * defaults to 10 milliseconds.
13493  * 
13494  * Optionally, a CSS class may be applied to the element during the time it is pressed.
13495  * 
13496  * @cfg {String/HTMLElement/Element} el The element to act as a button.
13497  * @cfg {Number} delay The initial delay before the repeating event begins firing.
13498  * Similar to an autorepeat key delay.
13499  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13500  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13501  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13502  *           "interval" and "delay" are ignored. "immediate" is honored.
13503  * @cfg {Boolean} preventDefault True to prevent the default click event
13504  * @cfg {Boolean} stopDefault True to stop the default click event
13505  * 
13506  * @history
13507  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
13508  *     2007-02-02 jvs Renamed to ClickRepeater
13509  *   2007-02-03 jvs Modifications for FF Mac and Safari 
13510  *
13511  *  @constructor
13512  * @param {String/HTMLElement/Element} el The element to listen on
13513  * @param {Object} config
13514  **/
13515 Roo.util.ClickRepeater = function(el, A)
13516 {
13517     this.el = Roo.get(el);
13518     this.el.unselectable();
13519
13520     Roo.apply(this, A);
13521
13522     this.addEvents({
13523     /**
13524      * @event mousedown
13525      * Fires when the mouse button is depressed.
13526      * @param {Roo.util.ClickRepeater} this
13527      */
13528         "mousedown" : true,
13529     /**
13530      * @event click
13531      * Fires on a specified interval during the time the element is pressed.
13532      * @param {Roo.util.ClickRepeater} this
13533      */
13534         "click" : true,
13535     /**
13536      * @event mouseup
13537      * Fires when the mouse key is released.
13538      * @param {Roo.util.ClickRepeater} this
13539      */
13540         "mouseup" : true
13541     });
13542
13543     this.el.on("mousedown", this.handleMouseDown, this);
13544     if(this.preventDefault || this.stopDefault){
13545         this.el.on("click", function(e){
13546             if(this.preventDefault){
13547                 e.preventDefault();
13548             }
13549             if(this.stopDefault){
13550                 e.stopEvent();
13551             }
13552         }, this);
13553     }
13554
13555     // allow inline handler
13556     if(this.handler){
13557         this.on("click", this.handler,  this.scope || this);
13558     }
13559
13560
13561     Roo.util.ClickRepeater.superclass.constructor.call(this);
13562 };
13563
13564 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13565     interval : 20,
13566     delay: 250,
13567     preventDefault : true,
13568     stopDefault : false,
13569     timer : 0,
13570
13571     // private
13572     handleMouseDown : function(){
13573         clearTimeout(this.timer);
13574         this.el.blur();
13575         if(this.pressClass){
13576             this.el.addClass(this.pressClass);
13577         }
13578
13579         this.mousedownTime = new  Date();
13580
13581         Roo.get(document).on("mouseup", this.handleMouseUp, this);
13582         this.el.on("mouseout", this.handleMouseOut, this);
13583
13584         this.fireEvent("mousedown", this);
13585         this.fireEvent("click", this);
13586         
13587         this.timer = this.click.defer(this.delay || this.interval, this);
13588     },
13589
13590     // private
13591     click : function(){
13592         this.fireEvent("click", this);
13593         this.timer = this.click.defer(this.getInterval(), this);
13594     },
13595
13596     // private
13597     getInterval: function(){
13598         if(!this.accelerate){
13599             return  this.interval;
13600         }
13601         var  B = this.mousedownTime.getElapsed();
13602         if(B < 500){
13603             return  400;
13604         }else  if(B < 1700){
13605             return  320;
13606         }else  if(B < 2600){
13607             return  250;
13608         }else  if(B < 3500){
13609             return  180;
13610         }else  if(B < 4400){
13611             return  140;
13612         }else  if(B < 5300){
13613             return  80;
13614         }else  if(B < 6200){
13615             return  50;
13616         }else {
13617             return  10;
13618         }
13619     },
13620
13621     // private
13622     handleMouseOut : function(){
13623         clearTimeout(this.timer);
13624         if(this.pressClass){
13625             this.el.removeClass(this.pressClass);
13626         }
13627
13628         this.el.on("mouseover", this.handleMouseReturn, this);
13629     },
13630
13631     // private
13632     handleMouseReturn : function(){
13633         this.el.un("mouseover", this.handleMouseReturn);
13634         if(this.pressClass){
13635             this.el.addClass(this.pressClass);
13636         }
13637
13638         this.click();
13639     },
13640
13641     // private
13642     handleMouseUp : function(){
13643         clearTimeout(this.timer);
13644         this.el.un("mouseover", this.handleMouseReturn);
13645         this.el.un("mouseout", this.handleMouseOut);
13646         Roo.get(document).un("mouseup", this.handleMouseUp);
13647         this.el.removeClass(this.pressClass);
13648         this.fireEvent("mouseup", this);
13649     }
13650 });
13651 /*
13652  * Based on:
13653  * Ext JS Library 1.1.1
13654  * Copyright(c) 2006-2007, Ext JS, LLC.
13655  *
13656  * Originally Released Under LGPL - original licence link has changed is not relivant.
13657  *
13658  * Fork - LGPL
13659  * <script type="text/javascript">
13660  */
13661
13662  
13663 /**
13664  * @class Roo.KeyNav
13665  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13666  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13667  * way to implement custom navigation schemes for any UI component.</p>
13668  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13669  * pageUp, pageDown, del, home, end.  Usage:</p>
13670  <pre><code>
13671 var nav = new Roo.KeyNav("my-element", {
13672     "left" : function(e){
13673         this.moveLeft(e.ctrlKey);
13674     },
13675     "right" : function(e){
13676         this.moveRight(e.ctrlKey);
13677     },
13678     "enter" : function(e){
13679         this.save();
13680     },
13681     scope : this
13682 });
13683 </code></pre>
13684  * @constructor
13685  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13686  * @param {Object} config The config
13687  */
13688 Roo.KeyNav = function(el, A){
13689     this.el = Roo.get(el);
13690     Roo.apply(this, A);
13691     if(!this.disabled){
13692         this.disabled = true;
13693         this.enable();
13694     }
13695 };
13696
13697 Roo.KeyNav.prototype = {
13698     /**
13699      * @cfg {Boolean} disabled
13700      * True to disable this KeyNav instance (defaults to false)
13701      */
13702     disabled : false,
13703     /**
13704      * @cfg {String} defaultEventAction
13705      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
13706      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13707      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13708      */
13709     defaultEventAction: "stopEvent",
13710     /**
13711      * @cfg {Boolean} forceKeyDown
13712      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13713      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13714      * handle keydown instead of keypress.
13715      */
13716     forceKeyDown : false,
13717
13718     // private
13719     prepareEvent : function(e){
13720         var  k = e.getKey();
13721         var  h = this.keyToHandler[k];
13722         //if(h && this[h]){
13723         //    e.stopPropagation();
13724         //}
13725         if(Roo.isSafari && h && k >= 37 && k <= 40){
13726             e.stopEvent();
13727         }
13728     },
13729
13730     // private
13731     relay : function(e){
13732         var  k = e.getKey();
13733         var  h = this.keyToHandler[k];
13734         if(h && this[h]){
13735             if(this.doRelay(e, this[h], h) !== true){
13736                 e[this.defaultEventAction]();
13737             }
13738         }
13739     },
13740
13741     // private
13742     doRelay : function(e, h, B){
13743         return  h.call(this.scope || this, e);
13744     },
13745
13746     // possible handlers
13747     enter : false,
13748     left : false,
13749     right : false,
13750     up : false,
13751     down : false,
13752     tab : false,
13753     esc : false,
13754     pageUp : false,
13755     pageDown : false,
13756     del : false,
13757     home : false,
13758     end : false,
13759
13760     // quick lookup hash
13761     keyToHandler : {
13762         37 : "left",
13763         39 : "right",
13764         38 : "up",
13765         40 : "down",
13766         33 : "pageUp",
13767         34 : "pageDown",
13768         46 : "del",
13769         36 : "home",
13770         35 : "end",
13771         13 : "enter",
13772         27 : "esc",
13773         9  : "tab"
13774     },
13775
13776         /**
13777          * Enable this KeyNav
13778          */
13779         enable: function(){
13780                 if(this.disabled){
13781             // ie won't do special keys on keypress, no one else will repeat keys with keydown
13782             // the EventObject will normalize Safari automatically
13783             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13784                 this.el.on("keydown", this.relay,  this);
13785             }else {
13786                 this.el.on("keydown", this.prepareEvent,  this);
13787                 this.el.on("keypress", this.relay,  this);
13788             }
13789
13790                     this.disabled = false;
13791                 }
13792         },
13793
13794         /**
13795          * Disable this KeyNav
13796          */
13797         disable: function(){
13798                 if(!this.disabled){
13799                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13800                 this.el.un("keydown", this.relay);
13801             }else {
13802                 this.el.un("keydown", this.prepareEvent);
13803                 this.el.un("keypress", this.relay);
13804             }
13805
13806                     this.disabled = true;
13807                 }
13808         }
13809 };
13810 /*
13811  * Based on:
13812  * Ext JS Library 1.1.1
13813  * Copyright(c) 2006-2007, Ext JS, LLC.
13814  *
13815  * Originally Released Under LGPL - original licence link has changed is not relivant.
13816  *
13817  * Fork - LGPL
13818  * <script type="text/javascript">
13819  */
13820
13821  
13822 /**
13823  * @class Roo.KeyMap
13824  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13825  * The constructor accepts the same config object as defined by {@link #addBinding}.
13826  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13827  * combination it will call the function with this signature (if the match is a multi-key
13828  * combination the callback will still be called only once): (String key, Roo.EventObject e)
13829  * A KeyMap can also handle a string representation of keys.<br />
13830  * Usage:
13831  <pre><code>
13832 // map one key by key code
13833 var map = new Roo.KeyMap("my-element", {
13834     key: 13, // or Roo.EventObject.ENTER
13835     fn: myHandler,
13836     scope: myObject
13837 });
13838
13839 // map multiple keys to one action by string
13840 var map = new Roo.KeyMap("my-element", {
13841     key: "a\r\n\t",
13842     fn: myHandler,
13843     scope: myObject
13844 });
13845
13846 // map multiple keys to multiple actions by strings and array of codes
13847 var map = new Roo.KeyMap("my-element", [
13848     {
13849         key: [10,13],
13850         fn: function(){ alert("Return was pressed"); }
13851     }, {
13852         key: "abc",
13853         fn: function(){ alert('a, b or c was pressed'); }
13854     }, {
13855         key: "\t",
13856         ctrl:true,
13857         shift:true,
13858         fn: function(){ alert('Control + shift + tab was pressed.'); }
13859     }
13860 ]);
13861 </code></pre>
13862  * <b>Note: A KeyMap starts enabled</b>
13863  * @constructor
13864  * @param {String/HTMLElement/Roo.Element} el The element to bind to
13865  * @param {Object} config The config (see {@link #addBinding})
13866  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13867  */
13868 Roo.KeyMap = function(el, A, B){
13869     this.el  = Roo.get(el);
13870     this.eventName = B || "keydown";
13871     this.bindings = [];
13872     if(A){
13873         this.addBinding(A);
13874     }
13875
13876     this.enable();
13877 };
13878
13879 Roo.KeyMap.prototype = {
13880     /**
13881      * True to stop the event from bubbling and prevent the default browser action if the
13882      * key was handled by the KeyMap (defaults to false)
13883      * @type Boolean
13884      */
13885     stopEvent : false,
13886
13887     /**
13888      * Add a new binding to this KeyMap. The following config object properties are supported:
13889      * <pre>
13890 Property    Type             Description
13891 ----------  ---------------  ----------------------------------------------------------------------
13892 key         String/Array     A single keycode or an array of keycodes to handle
13893 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
13894 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
13895 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
13896 fn          Function         The function to call when KeyMap finds the expected key combination
13897 scope       Object           The scope of the callback function
13898 </pre>
13899      *
13900      * Usage:
13901      * <pre><code>
13902 // Create a KeyMap
13903 var map = new Roo.KeyMap(document, {
13904     key: Roo.EventObject.ENTER,
13905     fn: handleKey,
13906     scope: this
13907 });
13908
13909 //Add a new binding to the existing KeyMap later
13910 map.addBinding({
13911     key: 'abc',
13912     shift: true,
13913     fn: handleKey,
13914     scope: this
13915 });
13916 </code></pre>
13917      * @param {Object/Array} config A single KeyMap config or an array of configs
13918      */
13919         addBinding : function(C){
13920         if(C  instanceof  Array){
13921             for(var  i = 0, len = C.length; i < len; i++){
13922                 this.addBinding(C[i]);
13923             }
13924             return;
13925         }
13926         var  D = C.key,
13927             E = C.shift, 
13928             F = C.ctrl, 
13929             G = C.alt,
13930             fn = C.fn,
13931             H = C.scope;
13932         if(typeof  D == "string"){
13933             var  ks = [];
13934             var  keyString = D.toUpperCase();
13935             for(var  j = 0, len = keyString.length; j < len; j++){
13936                 ks.push(keyString.charCodeAt(j));
13937             }
13938
13939             D = ks;
13940         }
13941         var  I = D  instanceof  Array;
13942         var  J = function(e){
13943             if((!E || e.shiftKey) && (!F || e.ctrlKey) &&  (!G || e.altKey)){
13944                 var  k = e.getKey();
13945                 if(I){
13946                     for(var  i = 0, len = D.length; i < len; i++){
13947                         if(D[i] == k){
13948                           if(this.stopEvent){
13949                               e.stopEvent();
13950                           }
13951
13952                           fn.call(H || window, k, e);
13953                           return;
13954                         }
13955                     }
13956                 }else {
13957                     if(k == D){
13958                         if(this.stopEvent){
13959                            e.stopEvent();
13960                         }
13961
13962                         fn.call(H || window, k, e);
13963                     }
13964                 }
13965             }
13966         };
13967         this.bindings.push(J);  
13968         },
13969
13970     /**
13971      * Shorthand for adding a single key listener
13972      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13973      * following options:
13974      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13975      * @param {Function} fn The function to call
13976      * @param {Object} scope (optional) The scope of the function
13977      */
13978     on : function(K, fn, L){
13979         var  M, N, O, P;
13980         if(typeof  K == "object" && !(K  instanceof  Array)){
13981             M = K.key;
13982             N = K.shift;
13983             O = K.ctrl;
13984             P = K.alt;
13985         }else {
13986             M = K;
13987         }
13988
13989         this.addBinding({
13990             key: M,
13991             shift: N,
13992             ctrl: O,
13993             alt: P,
13994             fn: fn,
13995             scope: L
13996         })
13997     },
13998
13999     // private
14000     handleKeyDown : function(e){
14001             if(this.enabled){ //just in case
14002             var  b = this.bindings;
14003             for(var  i = 0, len = b.length; i < len; i++){
14004                 b[i].call(this, e);
14005             }
14006             }
14007         },
14008         
14009         /**
14010          * Returns true if this KeyMap is enabled
14011          * @return {Boolean} 
14012          */
14013         isEnabled : function(){
14014             return  this.enabled;  
14015         },
14016         
14017         /**
14018          * Enables this KeyMap
14019          */
14020         enable: function(){
14021                 if(!this.enabled){
14022                     this.el.on(this.eventName, this.handleKeyDown, this);
14023                     this.enabled = true;
14024                 }
14025         },
14026
14027         /**
14028          * Disable this KeyMap
14029          */
14030         disable: function(){
14031                 if(this.enabled){
14032                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14033                     this.enabled = false;
14034                 }
14035         }
14036 };
14037 /*
14038  * Based on:
14039  * Ext JS Library 1.1.1
14040  * Copyright(c) 2006-2007, Ext JS, LLC.
14041  *
14042  * Originally Released Under LGPL - original licence link has changed is not relivant.
14043  *
14044  * Fork - LGPL
14045  * <script type="text/javascript">
14046  */
14047
14048  
14049 /**
14050  * @class Roo.util.TextMetrics
14051  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14052  * wide, in pixels, a given block of text will be.
14053  * @singleton
14054  */
14055 Roo.util.TextMetrics = function(){
14056     var  A;
14057     return  {
14058         /**
14059          * Measures the size of the specified text
14060          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14061          * that can affect the size of the rendered text
14062          * @param {String} text The text to measure
14063          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14064          * in order to accurately measure the text height
14065          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14066          */
14067         measure : function(el, E, F){
14068             if(!A){
14069                 A = Roo.util.TextMetrics.Instance(el, F);
14070             }
14071
14072             A.bind(el);
14073             A.setFixedWidth(F || 'auto');
14074             return  A.getSize(E);
14075         },
14076
14077         /**
14078          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14079          * the overhead of multiple calls to initialize the style properties on each measurement.
14080          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14081          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14082          * in order to accurately measure the text height
14083          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14084          */
14085         createInstance : function(el, G){
14086             return  Roo.util.TextMetrics.Instance(el, G);
14087         }
14088     };
14089 }();
14090
14091 Roo.util.TextMetrics.Instance = function(B, C){
14092     var  ml = new  Roo.Element(document.createElement('div'));
14093     document.body.appendChild(ml.dom);
14094     ml.position('absolute');
14095     ml.setLeftTop(-1000, -1000);
14096     ml.hide();
14097
14098     if(C){
14099         ml.setWidth(C);
14100     }
14101
14102     var  D = {
14103         /**
14104          * Returns the size of the specified text based on the internal element's style and width properties
14105          * @param {String} text The text to measure
14106          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14107          */
14108         getSize : function(E){
14109             ml.update(E);
14110             var  s = ml.getSize();
14111             ml.update('');
14112             return  s;
14113         },
14114
14115         /**
14116          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14117          * that can affect the size of the rendered text
14118          * @param {String/HTMLElement} el The element, dom node or id
14119          */
14120         bind : function(el){
14121             ml.setStyle(
14122                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14123             );
14124         },
14125
14126         /**
14127          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14128          * to set a fixed width in order to accurately measure the text height.
14129          * @param {Number} width The width to set on the element
14130          */
14131         setFixedWidth : function(F){
14132             ml.setWidth(F);
14133         },
14134
14135         /**
14136          * Returns the measured width of the specified text
14137          * @param {String} text The text to measure
14138          * @return {Number} width The width in pixels
14139          */
14140         getWidth : function(G){
14141             ml.dom.style.width = 'auto';
14142             return  this.getSize(G).width;
14143         },
14144
14145         /**
14146          * Returns the measured height of the specified text.  For multiline text, be sure to call
14147          * {@link #setFixedWidth} if necessary.
14148          * @param {String} text The text to measure
14149          * @return {Number} height The height in pixels
14150          */
14151         getHeight : function(H){
14152             return  this.getSize(H).height;
14153         }
14154     };
14155
14156     D.bind(B);
14157
14158     return  D;
14159 };
14160
14161 // backwards compat
14162 Roo.Element.measureText = Roo.util.TextMetrics.measure;
14163 /*
14164  * Based on:
14165  * Ext JS Library 1.1.1
14166  * Copyright(c) 2006-2007, Ext JS, LLC.
14167  *
14168  * Originally Released Under LGPL - original licence link has changed is not relivant.
14169  *
14170  * Fork - LGPL
14171  * <script type="text/javascript">
14172  */
14173
14174 /**
14175  * @class Roo.state.Provider
14176  * Abstract base class for state provider implementations. This class provides methods
14177  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14178  * Provider interface.
14179  */
14180 Roo.state.Provider = function(){
14181     /**
14182      * @event statechange
14183      * Fires when a state change occurs.
14184      * @param {Provider} this This state provider
14185      * @param {String} key The state key which was changed
14186      * @param {String} value The encoded value for the state
14187      */
14188     this.addEvents({
14189         "statechange": true
14190     });
14191     this.state = {};
14192     Roo.state.Provider.superclass.constructor.call(this);
14193 };
14194 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14195     /**
14196      * Returns the current value for a key
14197      * @param {String} name The key name
14198      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14199      * @return {Mixed} The state data
14200      */
14201     get : function(A, B){
14202         return  typeof  this.state[A] == "undefined" ?
14203             B : this.state[A];
14204     },
14205     
14206     /**
14207      * Clears a value from the state
14208      * @param {String} name The key name
14209      */
14210     clear : function(C){
14211         delete  this.state[C];
14212         this.fireEvent("statechange", this, C, null);
14213     },
14214     
14215     /**
14216      * Sets the value for a key
14217      * @param {String} name The key name
14218      * @param {Mixed} value The value to set
14219      */
14220     set : function(D, E){
14221         this.state[D] = E;
14222         this.fireEvent("statechange", this, D, E);
14223     },
14224     
14225     /**
14226      * Decodes a string previously encoded with {@link #encodeValue}.
14227      * @param {String} value The value to decode
14228      * @return {Mixed} The decoded value
14229      */
14230     decodeValue : function(F){
14231         var  re = /^(a|n|d|b|s|o)\:(.*)$/;
14232         var  G = re.exec(unescape(F));
14233         if(!G || !G[1]) return; // non state cookie
14234         var  H = G[1];
14235         var  v = G[2];
14236         switch(H){
14237             case  "n":
14238                 return  parseFloat(v);
14239             case  "d":
14240                 return  new  Date(Date.parse(v));
14241             case  "b":
14242                 return  (v == "1");
14243             case  "a":
14244                 var  all = [];
14245                 var  values = v.split("^");
14246                 for(var  i = 0, len = values.length; i < len; i++){
14247                     all.push(this.decodeValue(values[i]));
14248                 }
14249                 return  all;
14250            case  "o":
14251                 var  all = {};
14252                 var  values = v.split("^");
14253                 for(var  i = 0, len = values.length; i < len; i++){
14254                     var  kv = values[i].split("=");
14255                     all[kv[0]] = this.decodeValue(kv[1]);
14256                 }
14257                 return  all;
14258            default:
14259                 return  v;
14260         }
14261     },
14262     
14263     /**
14264      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14265      * @param {Mixed} value The value to encode
14266      * @return {String} The encoded value
14267      */
14268     encodeValue : function(v){
14269         var  I;
14270         if(typeof  v == "number"){
14271             I = "n:" + v;
14272         }else  if(typeof  v == "boolean"){
14273             I = "b:" + (v ? "1" : "0");
14274         }else  if(v  instanceof  Date){
14275             I = "d:" + v.toGMTString();
14276         }else  if(v  instanceof  Array){
14277             var  flat = "";
14278             for(var  i = 0, len = v.length; i < len; i++){
14279                 flat += this.encodeValue(v[i]);
14280                 if(i != len-1) flat += "^";
14281             }
14282
14283             I = "a:" + flat;
14284         }else  if(typeof  v == "object"){
14285             var  flat = "";
14286             for(var  key  in  v){
14287                 if(typeof  v[key] != "function"){
14288                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14289                 }
14290             }
14291
14292             I = "o:" + flat.substring(0, flat.length-1);
14293         }else {
14294             I = "s:" + v;
14295         }
14296         return  escape(I);        
14297     }
14298 });
14299
14300
14301 /*
14302  * Based on:
14303  * Ext JS Library 1.1.1
14304  * Copyright(c) 2006-2007, Ext JS, LLC.
14305  *
14306  * Originally Released Under LGPL - original licence link has changed is not relivant.
14307  *
14308  * Fork - LGPL
14309  * <script type="text/javascript">
14310  */
14311 /**
14312  * @class Roo.state.Manager
14313  * This is the global state manager. By default all components that are "state aware" check this class
14314  * for state information if you don't pass them a custom state provider. In order for this class
14315  * to be useful, it must be initialized with a provider when your application initializes.
14316  <pre><code>
14317 // in your initialization function
14318 init : function(){
14319    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14320    ...
14321    // supposed you have a {@link Roo.BorderLayout}
14322    var layout = new Roo.BorderLayout(...);
14323    layout.restoreState();
14324    // or a {Roo.BasicDialog}
14325    var dialog = new Roo.BasicDialog(...);
14326    dialog.restoreState();
14327  </code></pre>
14328  * @singleton
14329  */
14330 Roo.state.Manager = function(){
14331     var  A = new  Roo.state.Provider();
14332     
14333     return  {
14334         /**
14335          * Configures the default state provider for your application
14336          * @param {Provider} stateProvider The state provider to set
14337          */
14338         setProvider : function(H){
14339             A = H;
14340         },
14341         
14342         /**
14343          * Returns the current value for a key
14344          * @param {String} name The key name
14345          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14346          * @return {Mixed} The state data
14347          */
14348         get : function(I, J){
14349             return  A.get(I, J);
14350         },
14351         
14352         /**
14353          * Sets the value for a key
14354          * @param {String} name The key name
14355          * @param {Mixed} value The state data
14356          */
14357          set : function(K, L){
14358             A.set(K, L);
14359         },
14360         
14361         /**
14362          * Clears a value from the state
14363          * @param {String} name The key name
14364          */
14365         clear : function(M){
14366             A.clear(M);
14367         },
14368         
14369         /**
14370          * Gets the currently configured state provider
14371          * @return {Provider} The state provider
14372          */
14373         getProvider : function(){
14374             return  A;
14375         }
14376     };
14377 }();
14378
14379 /*
14380  * Based on:
14381  * Ext JS Library 1.1.1
14382  * Copyright(c) 2006-2007, Ext JS, LLC.
14383  *
14384  * Originally Released Under LGPL - original licence link has changed is not relivant.
14385  *
14386  * Fork - LGPL
14387  * <script type="text/javascript">
14388  */
14389 /**
14390  * @class Roo.state.CookieProvider
14391  * @extends Roo.state.Provider
14392  * The default Provider implementation which saves state via cookies.
14393  * <br />Usage:
14394  <pre><code>
14395    var cp = new Roo.state.CookieProvider({
14396        path: "/cgi-bin/",
14397        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14398        domain: "roojs.com"
14399    })
14400    Roo.state.Manager.setProvider(cp);
14401  </code></pre>
14402  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14403  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14404  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14405  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14406  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14407  * domain the page is running on including the 'www' like 'www.roojs.com')
14408  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14409  * @constructor
14410  * Create a new CookieProvider
14411  * @param {Object} config The configuration object
14412  */
14413 Roo.state.CookieProvider = function(A){
14414     Roo.state.CookieProvider.superclass.constructor.call(this);
14415     this.path = "/";
14416     this.expires = new  Date(new  Date().getTime()+(1000*60*60*24*7)); //7 days
14417     this.domain = null;
14418     this.secure = false;
14419     Roo.apply(this, A);
14420     this.state = this.readCookies();
14421 };
14422
14423 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14424     // private
14425     set : function(B, C){
14426         if(typeof  C == "undefined" || C === null){
14427             this.clear(B);
14428             return;
14429         }
14430
14431         this.setCookie(B, C);
14432         Roo.state.CookieProvider.superclass.set.call(this, B, C);
14433     },
14434
14435     // private
14436     clear : function(D){
14437         this.clearCookie(D);
14438         Roo.state.CookieProvider.superclass.clear.call(this, D);
14439     },
14440
14441     // private
14442     readCookies : function(){
14443         var  E = {};
14444         var  c = document.cookie + ";";
14445         var  re = /\s?(.*?)=(.*?);/g;
14446         var  F;
14447         while((F = re.exec(c)) != null){
14448             var  D = F[1];
14449             var  C = F[2];
14450             if(D && D.substring(0,3) == "ys-"){
14451                 E[D.substr(3)] = this.decodeValue(C);
14452             }
14453         }
14454         return  E;
14455     },
14456
14457     // private
14458     setCookie : function(G, H){
14459         document.cookie = "ys-"+ G + "=" + this.encodeValue(H) +
14460            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14461            ((this.path == null) ? "" : ("; path=" + this.path)) +
14462            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14463            ((this.secure == true) ? "; secure" : "");
14464     },
14465
14466     // private
14467     clearCookie : function(I){
14468         document.cookie = "ys-" + I + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14469            ((this.path == null) ? "" : ("; path=" + this.path)) +
14470            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14471            ((this.secure == true) ? "; secure" : "");
14472     }
14473 });
14474 /*
14475  * Based on:
14476  * Ext JS Library 1.1.1
14477  * Copyright(c) 2006-2007, Ext JS, LLC.
14478  *
14479  * Originally Released Under LGPL - original licence link has changed is not relivant.
14480  *
14481  * Fork - LGPL
14482  * <script type="text/javascript">
14483  */
14484
14485
14486
14487 /*
14488  * These classes are derivatives of the similarly named classes in the YUI Library.
14489  * The original license:
14490  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14491  * Code licensed under the BSD License:
14492  * http://developer.yahoo.net/yui/license.txt
14493  */
14494
14495 (function() {
14496
14497 var  A=Roo.EventManager;
14498 var  B=Roo.lib.Dom;
14499
14500 /**
14501  * @class Roo.dd.DragDrop
14502  * Defines the interface and base operation of items that that can be
14503  * dragged or can be drop targets.  It was designed to be extended, overriding
14504  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14505  * Up to three html elements can be associated with a DragDrop instance:
14506  * <ul>
14507  * <li>linked element: the element that is passed into the constructor.
14508  * This is the element which defines the boundaries for interaction with
14509  * other DragDrop objects.</li>
14510  * <li>handle element(s): The drag operation only occurs if the element that
14511  * was clicked matches a handle element.  By default this is the linked
14512  * element, but there are times that you will want only a portion of the
14513  * linked element to initiate the drag operation, and the setHandleElId()
14514  * method provides a way to define this.</li>
14515  * <li>drag element: this represents the element that would be moved along
14516  * with the cursor during a drag operation.  By default, this is the linked
14517  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
14518  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14519  * </li>
14520  * </ul>
14521  * This class should not be instantiated until the onload event to ensure that
14522  * the associated elements are available.
14523  * The following would define a DragDrop obj that would interact with any
14524  * other DragDrop obj in the "group1" group:
14525  * <pre>
14526  *  dd = new Roo.dd.DragDrop("div1", "group1");
14527  * </pre>
14528  * Since none of the event handlers have been implemented, nothing would
14529  * actually happen if you were to run the code above.  Normally you would
14530  * override this class or one of the default implementations, but you can
14531  * also override the methods you want on an instance of the class...
14532  * <pre>
14533  *  dd.onDragDrop = function(e, id) {
14534  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
14535  *  }
14536  * </pre>
14537  * @constructor
14538  * @param {String} id of the element that is linked to this instance
14539  * @param {String} sGroup the group of related DragDrop objects
14540  * @param {object} config an object containing configurable attributes
14541  *                Valid properties for DragDrop:
14542  *                    padding, isTarget, maintainOffset, primaryButtonOnly
14543  */
14544 Roo.dd.DragDrop = function(id, C, D) {
14545     if (id) {
14546         this.init(id, C, D);
14547     }
14548 };
14549
14550 Roo.dd.DragDrop.prototype = {
14551
14552     /**
14553      * The id of the element associated with this object.  This is what we
14554      * refer to as the "linked element" because the size and position of
14555      * this element is used to determine when the drag and drop objects have
14556      * interacted.
14557      * @property id
14558      * @type String
14559      */
14560     id: null,
14561
14562     /**
14563      * Configuration attributes passed into the constructor
14564      * @property config
14565      * @type object
14566      */
14567     config: null,
14568
14569     /**
14570      * The id of the element that will be dragged.  By default this is same
14571      * as the linked element , but could be changed to another element. Ex:
14572      * Roo.dd.DDProxy
14573      * @property dragElId
14574      * @type String
14575      * @private
14576      */
14577     dragElId: null,
14578
14579     /**
14580      * the id of the element that initiates the drag operation.  By default
14581      * this is the linked element, but could be changed to be a child of this
14582      * element.  This lets us do things like only starting the drag when the
14583      * header element within the linked html element is clicked.
14584      * @property handleElId
14585      * @type String
14586      * @private
14587      */
14588     handleElId: null,
14589
14590     /**
14591      * An associative array of HTML tags that will be ignored if clicked.
14592      * @property invalidHandleTypes
14593      * @type {string: string}
14594      */
14595     invalidHandleTypes: null,
14596
14597     /**
14598      * An associative array of ids for elements that will be ignored if clicked
14599      * @property invalidHandleIds
14600      * @type {string: string}
14601      */
14602     invalidHandleIds: null,
14603
14604     /**
14605      * An indexted array of css class names for elements that will be ignored
14606      * if clicked.
14607      * @property invalidHandleClasses
14608      * @type string[]
14609      */
14610     invalidHandleClasses: null,
14611
14612     /**
14613      * The linked element's absolute X position at the time the drag was
14614      * started
14615      * @property startPageX
14616      * @type int
14617      * @private
14618      */
14619     startPageX: 0,
14620
14621     /**
14622      * The linked element's absolute X position at the time the drag was
14623      * started
14624      * @property startPageY
14625      * @type int
14626      * @private
14627      */
14628     startPageY: 0,
14629
14630     /**
14631      * The group defines a logical collection of DragDrop objects that are
14632      * related.  Instances only get events when interacting with other
14633      * DragDrop object in the same group.  This lets us define multiple
14634      * groups using a single DragDrop subclass if we want.
14635      * @property groups
14636      * @type {string: string}
14637      */
14638     groups: null,
14639
14640     /**
14641      * Individual drag/drop instances can be locked.  This will prevent
14642      * onmousedown start drag.
14643      * @property locked
14644      * @type boolean
14645      * @private
14646      */
14647     locked: false,
14648
14649     /**
14650      * Lock this instance
14651      * @method lock
14652      */
14653     lock: function() { this.locked = true; },
14654
14655     /**
14656      * Unlock this instace
14657      * @method unlock
14658      */
14659     unlock: function() { this.locked = false; },
14660
14661     /**
14662      * By default, all insances can be a drop target.  This can be disabled by
14663      * setting isTarget to false.
14664      * @method isTarget
14665      * @type boolean
14666      */
14667     isTarget: true,
14668
14669     /**
14670      * The padding configured for this drag and drop object for calculating
14671      * the drop zone intersection with this object.
14672      * @method padding
14673      * @type int[]
14674      */
14675     padding: null,
14676
14677     /**
14678      * Cached reference to the linked element
14679      * @property _domRef
14680      * @private
14681      */
14682     _domRef: null,
14683
14684     /**
14685      * Internal typeof flag
14686      * @property __ygDragDrop
14687      * @private
14688      */
14689     __ygDragDrop: true,
14690
14691     /**
14692      * Set to true when horizontal contraints are applied
14693      * @property constrainX
14694      * @type boolean
14695      * @private
14696      */
14697     constrainX: false,
14698
14699     /**
14700      * Set to true when vertical contraints are applied
14701      * @property constrainY
14702      * @type boolean
14703      * @private
14704      */
14705     constrainY: false,
14706
14707     /**
14708      * The left constraint
14709      * @property minX
14710      * @type int
14711      * @private
14712      */
14713     minX: 0,
14714
14715     /**
14716      * The right constraint
14717      * @property maxX
14718      * @type int
14719      * @private
14720      */
14721     maxX: 0,
14722
14723     /**
14724      * The up constraint
14725      * @property minY
14726      * @type int
14727      * @type int
14728      * @private
14729      */
14730     minY: 0,
14731
14732     /**
14733      * The down constraint
14734      * @property maxY
14735      * @type int
14736      * @private
14737      */
14738     maxY: 0,
14739
14740     /**
14741      * Maintain offsets when we resetconstraints.  Set to true when you want
14742      * the position of the element relative to its parent to stay the same
14743      * when the page changes
14744      *
14745      * @property maintainOffset
14746      * @type boolean
14747      */
14748     maintainOffset: false,
14749
14750     /**
14751      * Array of pixel locations the element will snap to if we specified a
14752      * horizontal graduation/interval.  This array is generated automatically
14753      * when you define a tick interval.
14754      * @property xTicks
14755      * @type int[]
14756      */
14757     xTicks: null,
14758
14759     /**
14760      * Array of pixel locations the element will snap to if we specified a
14761      * vertical graduation/interval.  This array is generated automatically
14762      * when you define a tick interval.
14763      * @property yTicks
14764      * @type int[]
14765      */
14766     yTicks: null,
14767
14768     /**
14769      * By default the drag and drop instance will only respond to the primary
14770      * button click (left button for a right-handed mouse).  Set to true to
14771      * allow drag and drop to start with any mouse click that is propogated
14772      * by the browser
14773      * @property primaryButtonOnly
14774      * @type boolean
14775      */
14776     primaryButtonOnly: true,
14777
14778     /**
14779      * The availabe property is false until the linked dom element is accessible.
14780      * @property available
14781      * @type boolean
14782      */
14783     available: false,
14784
14785     /**
14786      * By default, drags can only be initiated if the mousedown occurs in the
14787      * region the linked element is.  This is done in part to work around a
14788      * bug in some browsers that mis-report the mousedown if the previous
14789      * mouseup happened outside of the window.  This property is set to true
14790      * if outer handles are defined.
14791      *
14792      * @property hasOuterHandles
14793      * @type boolean
14794      * @default false
14795      */
14796     hasOuterHandles: false,
14797
14798     /**
14799      * Code that executes immediately before the startDrag event
14800      * @method b4StartDrag
14801      * @private
14802      */
14803     b4StartDrag: function(x, y) { },
14804
14805     /**
14806      * Abstract method called after a drag/drop object is clicked
14807      * and the drag or mousedown time thresholds have beeen met.
14808      * @method startDrag
14809      * @param {int} X click location
14810      * @param {int} Y click location
14811      */
14812     startDrag: function(x, y) { /* override this */ },
14813
14814     /**
14815      * Code that executes immediately before the onDrag event
14816      * @method b4Drag
14817      * @private
14818      */
14819     b4Drag: function(e) { },
14820
14821     /**
14822      * Abstract method called during the onMouseMove event while dragging an
14823      * object.
14824      * @method onDrag
14825      * @param {Event} e the mousemove event
14826      */
14827     onDrag: function(e) { /* override this */ },
14828
14829     /**
14830      * Abstract method called when this element fist begins hovering over
14831      * another DragDrop obj
14832      * @method onDragEnter
14833      * @param {Event} e the mousemove event
14834      * @param {String|DragDrop[]} id In POINT mode, the element
14835      * id this is hovering over.  In INTERSECT mode, an array of one or more
14836      * dragdrop items being hovered over.
14837      */
14838     onDragEnter: function(e, id) { /* override this */ },
14839
14840     /**
14841      * Code that executes immediately before the onDragOver event
14842      * @method b4DragOver
14843      * @private
14844      */
14845     b4DragOver: function(e) { },
14846
14847     /**
14848      * Abstract method called when this element is hovering over another
14849      * DragDrop obj
14850      * @method onDragOver
14851      * @param {Event} e the mousemove event
14852      * @param {String|DragDrop[]} id In POINT mode, the element
14853      * id this is hovering over.  In INTERSECT mode, an array of dd items
14854      * being hovered over.
14855      */
14856     onDragOver: function(e, id) { /* override this */ },
14857
14858     /**
14859      * Code that executes immediately before the onDragOut event
14860      * @method b4DragOut
14861      * @private
14862      */
14863     b4DragOut: function(e) { },
14864
14865     /**
14866      * Abstract method called when we are no longer hovering over an element
14867      * @method onDragOut
14868      * @param {Event} e the mousemove event
14869      * @param {String|DragDrop[]} id In POINT mode, the element
14870      * id this was hovering over.  In INTERSECT mode, an array of dd items
14871      * that the mouse is no longer over.
14872      */
14873     onDragOut: function(e, id) { /* override this */ },
14874
14875     /**
14876      * Code that executes immediately before the onDragDrop event
14877      * @method b4DragDrop
14878      * @private
14879      */
14880     b4DragDrop: function(e) { },
14881
14882     /**
14883      * Abstract method called when this item is dropped on another DragDrop
14884      * obj
14885      * @method onDragDrop
14886      * @param {Event} e the mouseup event
14887      * @param {String|DragDrop[]} id In POINT mode, the element
14888      * id this was dropped on.  In INTERSECT mode, an array of dd items this
14889      * was dropped on.
14890      */
14891     onDragDrop: function(e, id) { /* override this */ },
14892
14893     /**
14894      * Abstract method called when this item is dropped on an area with no
14895      * drop target
14896      * @method onInvalidDrop
14897      * @param {Event} e the mouseup event
14898      */
14899     onInvalidDrop: function(e) { /* override this */ },
14900
14901     /**
14902      * Code that executes immediately before the endDrag event
14903      * @method b4EndDrag
14904      * @private
14905      */
14906     b4EndDrag: function(e) { },
14907
14908     /**
14909      * Fired when we are done dragging the object
14910      * @method endDrag
14911      * @param {Event} e the mouseup event
14912      */
14913     endDrag: function(e) { /* override this */ },
14914
14915     /**
14916      * Code executed immediately before the onMouseDown event
14917      * @method b4MouseDown
14918      * @param {Event} e the mousedown event
14919      * @private
14920      */
14921     b4MouseDown: function(e) {  },
14922
14923     /**
14924      * Event handler that fires when a drag/drop obj gets a mousedown
14925      * @method onMouseDown
14926      * @param {Event} e the mousedown event
14927      */
14928     onMouseDown: function(e) { /* override this */ },
14929
14930     /**
14931      * Event handler that fires when a drag/drop obj gets a mouseup
14932      * @method onMouseUp
14933      * @param {Event} e the mouseup event
14934      */
14935     onMouseUp: function(e) { /* override this */ },
14936
14937     /**
14938      * Override the onAvailable method to do what is needed after the initial
14939      * position was determined.
14940      * @method onAvailable
14941      */
14942     onAvailable: function () {
14943     },
14944
14945     /*
14946      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14947      * @type Object
14948      */
14949     defaultPadding : {left:0, right:0, top:0, bottom:0},
14950
14951     /*
14952      * Initializes the drag drop object's constraints to restrict movement to a certain element.
14953  *
14954  * Usage:
14955  <pre><code>
14956  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14957                 { dragElId: "existingProxyDiv" });
14958  dd.startDrag = function(){
14959      this.constrainTo("parent-id");
14960  };
14961  </code></pre>
14962  * Or you can initalize it using the {@link Roo.Element} object:
14963  <pre><code>
14964  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14965      startDrag : function(){
14966          this.constrainTo("parent-id");
14967      }
14968  });
14969  </code></pre>
14970      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14971      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14972      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14973      * an object containing the sides to pad. For example: {right:10, bottom:10}
14974      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14975      */
14976     constrainTo : function(C, D, E){
14977         if(typeof  D == "number"){
14978             D = {left: D, right:D, top:D, bottom:D};
14979         }
14980
14981         D = D || this.defaultPadding;
14982         var  b = Roo.get(this.getEl()).getBox();
14983         var  ce = Roo.get(C);
14984         var  s = ce.getScroll();
14985         var  c, cd = ce.dom;
14986         if(cd == document.body){
14987             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14988         }else {
14989             xy = ce.getXY();
14990             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14991         }
14992
14993
14994         var  F = b.y - c.y;
14995         var  G = b.x - c.x;
14996
14997         this.resetConstraints();
14998         this.setXConstraint(G - (D.left||0), // left
14999                 c.width - G - b.width - (D.right||0) //right
15000         );
15001         this.setYConstraint(F - (D.top||0), //top
15002                 c.height - F - b.height - (D.bottom||0) //bottom
15003         );
15004     },
15005
15006     /**
15007      * Returns a reference to the linked element
15008      * @method getEl
15009      * @return {HTMLElement} the html element
15010      */
15011     getEl: function() {
15012         if (!this._domRef) {
15013             this._domRef = Roo.getDom(this.id);
15014         }
15015
15016         return  this._domRef;
15017     },
15018
15019     /**
15020      * Returns a reference to the actual element to drag.  By default this is
15021      * the same as the html element, but it can be assigned to another
15022      * element. An example of this can be found in Roo.dd.DDProxy
15023      * @method getDragEl
15024      * @return {HTMLElement} the html element
15025      */
15026     getDragEl: function() {
15027         return  Roo.getDom(this.dragElId);
15028     },
15029
15030     /**
15031      * Sets up the DragDrop object.  Must be called in the constructor of any
15032      * Roo.dd.DragDrop subclass
15033      * @method init
15034      * @param id the id of the linked element
15035      * @param {String} sGroup the group of related items
15036      * @param {object} config configuration attributes
15037      */
15038     init: function(id, H, I) {
15039         this.initTarget(id, H, I);
15040         A.on(this.id, "mousedown", this.handleMouseDown, this);
15041         // Event.on(this.id, "selectstart", Event.preventDefault);
15042     },
15043
15044     /**
15045      * Initializes Targeting functionality only... the object does not
15046      * get a mousedown handler.
15047      * @method initTarget
15048      * @param id the id of the linked element
15049      * @param {String} sGroup the group of related items
15050      * @param {object} config configuration attributes
15051      */
15052     initTarget: function(id, J, K) {
15053
15054         // configuration attributes
15055         this.config = K || {};
15056
15057         // create a local reference to the drag and drop manager
15058         this.DDM = Roo.dd.DDM;
15059         // initialize the groups array
15060         this.groups = {};
15061
15062         // assume that we have an element reference instead of an id if the
15063         // parameter is not a string
15064         if (typeof  id !== "string") {
15065             id = Roo.id(id);
15066         }
15067
15068
15069         // set the id
15070         this.id = id;
15071
15072         // add to an interaction group
15073         this.addToGroup((J) ? J : "default");
15074
15075         // We don't want to register this as the handle with the manager
15076         // so we just set the id rather than calling the setter.
15077         this.handleElId = id;
15078
15079         // the linked element is the element that gets dragged by default
15080         this.setDragElId(id);
15081
15082         // by default, clicked anchors will not start drag operations.
15083         this.invalidHandleTypes = { A: "A" };
15084         this.invalidHandleIds = {};
15085         this.invalidHandleClasses = [];
15086
15087         this.applyConfig();
15088
15089         this.handleOnAvailable();
15090     },
15091
15092     /**
15093      * Applies the configuration parameters that were passed into the constructor.
15094      * This is supposed to happen at each level through the inheritance chain.  So
15095      * a DDProxy implentation will execute apply config on DDProxy, DD, and
15096      * DragDrop in order to get all of the parameters that are available in
15097      * each object.
15098      * @method applyConfig
15099      */
15100     applyConfig: function() {
15101
15102         // configurable properties:
15103         //    padding, isTarget, maintainOffset, primaryButtonOnly
15104         this.padding           = this.config.padding || [0, 0, 0, 0];
15105         this.isTarget          = (this.config.isTarget !== false);
15106         this.maintainOffset    = (this.config.maintainOffset);
15107         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15108
15109     },
15110
15111     /**
15112      * Executed when the linked element is available
15113      * @method handleOnAvailable
15114      * @private
15115      */
15116     handleOnAvailable: function() {
15117         this.available = true;
15118         this.resetConstraints();
15119         this.onAvailable();
15120     },
15121
15122      /**
15123      * Configures the padding for the target zone in px.  Effectively expands
15124      * (or reduces) the virtual object size for targeting calculations.
15125      * Supports css-style shorthand; if only one parameter is passed, all sides
15126      * will have that padding, and if only two are passed, the top and bottom
15127      * will have the first param, the left and right the second.
15128      * @method setPadding
15129      * @param {int} iTop    Top pad
15130      * @param {int} iRight  Right pad
15131      * @param {int} iBot    Bot pad
15132      * @param {int} iLeft   Left pad
15133      */
15134     setPadding: function(L, M, N, O) {
15135         // this.padding = [iLeft, iRight, iTop, iBot];
15136         if (!M && 0 !== M) {
15137             this.padding = [L, L, L, L];
15138         } else  if (!N && 0 !== N) {
15139             this.padding = [L, M, L, M];
15140         } else  {
15141             this.padding = [L, M, N, O];
15142         }
15143     },
15144
15145     /**
15146      * Stores the initial placement of the linked element.
15147      * @method setInitialPosition
15148      * @param {int} diffX   the X offset, default 0
15149      * @param {int} diffY   the Y offset, default 0
15150      */
15151     setInitPosition: function(P, Q) {
15152         var  el = this.getEl();
15153
15154         if (!this.DDM.verifyEl(el)) {
15155             return;
15156         }
15157
15158         var  dx = P || 0;
15159         var  dy = Q || 0;
15160
15161         var  p = B.getXY( el );
15162
15163         this.initPageX = p[0] - dx;
15164         this.initPageY = p[1] - dy;
15165
15166         this.lastPageX = p[0];
15167         this.lastPageY = p[1];
15168
15169
15170         this.setStartPosition(p);
15171     },
15172
15173     /**
15174      * Sets the start position of the element.  This is set when the obj
15175      * is initialized, the reset when a drag is started.
15176      * @method setStartPosition
15177      * @param pos current position (from previous lookup)
15178      * @private
15179      */
15180     setStartPosition: function(R) {
15181         var  p = R || B.getXY( this.getEl() );
15182         this.deltaSetXY = null;
15183
15184         this.startPageX = p[0];
15185         this.startPageY = p[1];
15186     },
15187
15188     /**
15189      * Add this instance to a group of related drag/drop objects.  All
15190      * instances belong to at least one group, and can belong to as many
15191      * groups as needed.
15192      * @method addToGroup
15193      * @param sGroup {string} the name of the group
15194      */
15195     addToGroup: function(S) {
15196         this.groups[S] = true;
15197         this.DDM.regDragDrop(this, S);
15198     },
15199
15200     /**
15201      * Remove's this instance from the supplied interaction group
15202      * @method removeFromGroup
15203      * @param {string}  sGroup  The group to drop
15204      */
15205     removeFromGroup: function(T) {
15206         if (this.groups[T]) {
15207             delete  this.groups[T];
15208         }
15209
15210
15211         this.DDM.removeDDFromGroup(this, T);
15212     },
15213
15214     /**
15215      * Allows you to specify that an element other than the linked element
15216      * will be moved with the cursor during a drag
15217      * @method setDragElId
15218      * @param id {string} the id of the element that will be used to initiate the drag
15219      */
15220     setDragElId: function(id) {
15221         this.dragElId = id;
15222     },
15223
15224     /**
15225      * Allows you to specify a child of the linked element that should be
15226      * used to initiate the drag operation.  An example of this would be if
15227      * you have a content div with text and links.  Clicking anywhere in the
15228      * content area would normally start the drag operation.  Use this method
15229      * to specify that an element inside of the content div is the element
15230      * that starts the drag operation.
15231      * @method setHandleElId
15232      * @param id {string} the id of the element that will be used to
15233      * initiate the drag.
15234      */
15235     setHandleElId: function(id) {
15236         if (typeof  id !== "string") {
15237             id = Roo.id(id);
15238         }
15239
15240         this.handleElId = id;
15241         this.DDM.regHandle(this.id, id);
15242     },
15243
15244     /**
15245      * Allows you to set an element outside of the linked element as a drag
15246      * handle
15247      * @method setOuterHandleElId
15248      * @param id the id of the element that will be used to initiate the drag
15249      */
15250     setOuterHandleElId: function(id) {
15251         if (typeof  id !== "string") {
15252             id = Roo.id(id);
15253         }
15254
15255         A.on(id, "mousedown",
15256                 this.handleMouseDown, this);
15257         this.setHandleElId(id);
15258
15259         this.hasOuterHandles = true;
15260     },
15261
15262     /**
15263      * Remove all drag and drop hooks for this element
15264      * @method unreg
15265      */
15266     unreg: function() {
15267         A.un(this.id, "mousedown",
15268                 this.handleMouseDown);
15269         this._domRef = null;
15270         this.DDM._remove(this);
15271     },
15272
15273     destroy : function(){
15274         this.unreg();
15275     },
15276
15277     /**
15278      * Returns true if this instance is locked, or the drag drop mgr is locked
15279      * (meaning that all drag/drop is disabled on the page.)
15280      * @method isLocked
15281      * @return {boolean} true if this obj or all drag/drop is locked, else
15282      * false
15283      */
15284     isLocked: function() {
15285         return  (this.DDM.isLocked() || this.locked);
15286     },
15287
15288     /**
15289      * Fired when this object is clicked
15290      * @method handleMouseDown
15291      * @param {Event} e
15292      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15293      * @private
15294      */
15295     handleMouseDown: function(e, U){
15296         if (this.primaryButtonOnly && e.button != 0) {
15297             return;
15298         }
15299
15300         if (this.isLocked()) {
15301             return;
15302         }
15303
15304
15305         this.DDM.refreshCache(this.groups);
15306
15307         var  pt = new  Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15308         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
15309         } else  {
15310             if (this.clickValidator(e)) {
15311
15312                 // set the initial element position
15313                 this.setStartPosition();
15314
15315
15316                 this.b4MouseDown(e);
15317                 this.onMouseDown(e);
15318
15319                 this.DDM.handleMouseDown(e, this);
15320
15321                 this.DDM.stopEvent(e);
15322             } else  {
15323
15324
15325             }
15326         }
15327     },
15328
15329     clickValidator: function(e) {
15330         var  V = e.getTarget();
15331         return  ( this.isValidHandleChild(V) &&
15332                     (this.id == this.handleElId ||
15333                         this.DDM.handleWasClicked(V, this.id)) );
15334     },
15335
15336     /**
15337      * Allows you to specify a tag name that should not start a drag operation
15338      * when clicked.  This is designed to facilitate embedding links within a
15339      * drag handle that do something other than start the drag.
15340      * @method addInvalidHandleType
15341      * @param {string} tagName the type of element to exclude
15342      */
15343     addInvalidHandleType: function(W) {
15344         var  X = W.toUpperCase();
15345         this.invalidHandleTypes[X] = X;
15346     },
15347
15348     /**
15349      * Lets you to specify an element id for a child of a drag handle
15350      * that should not initiate a drag
15351      * @method addInvalidHandleId
15352      * @param {string} id the element id of the element you wish to ignore
15353      */
15354     addInvalidHandleId: function(id) {
15355         if (typeof  id !== "string") {
15356             id = Roo.id(id);
15357         }
15358
15359         this.invalidHandleIds[id] = id;
15360     },
15361
15362     /**
15363      * Lets you specify a css class of elements that will not initiate a drag
15364      * @method addInvalidHandleClass
15365      * @param {string} cssClass the class of the elements you wish to ignore
15366      */
15367     addInvalidHandleClass: function(Y) {
15368         this.invalidHandleClasses.push(Y);
15369     },
15370
15371     /**
15372      * Unsets an excluded tag name set by addInvalidHandleType
15373      * @method removeInvalidHandleType
15374      * @param {string} tagName the type of element to unexclude
15375      */
15376     removeInvalidHandleType: function(Z) {
15377         var  a = Z.toUpperCase();
15378         // this.invalidHandleTypes[type] = null;
15379         delete  this.invalidHandleTypes[a];
15380     },
15381
15382     /**
15383      * Unsets an invalid handle id
15384      * @method removeInvalidHandleId
15385      * @param {string} id the id of the element to re-enable
15386      */
15387     removeInvalidHandleId: function(id) {
15388         if (typeof  id !== "string") {
15389             id = Roo.id(id);
15390         }
15391         delete  this.invalidHandleIds[id];
15392     },
15393
15394     /**
15395      * Unsets an invalid css class
15396      * @method removeInvalidHandleClass
15397      * @param {string} cssClass the class of the element(s) you wish to
15398      * re-enable
15399      */
15400     removeInvalidHandleClass: function(d) {
15401         for (var  i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15402             if (this.invalidHandleClasses[i] == d) {
15403                 delete  this.invalidHandleClasses[i];
15404             }
15405         }
15406     },
15407
15408     /**
15409      * Checks the tag exclusion list to see if this click should be ignored
15410      * @method isValidHandleChild
15411      * @param {HTMLElement} node the HTMLElement to evaluate
15412      * @return {boolean} true if this is a valid tag type, false if not
15413      */
15414     isValidHandleChild: function(f) {
15415
15416         var  g = true;
15417         // var n = (node.nodeName == "#text") ? node.parentNode : node;
15418         var  h;
15419         try {
15420             h = f.nodeName.toUpperCase();
15421         } catch(e) {
15422             nodeName = node.nodeName;
15423         }
15424
15425         g = g && !this.invalidHandleTypes[h];
15426         g = g && !this.invalidHandleIds[f.id];
15427
15428         for (var  i=0, len=this.invalidHandleClasses.length; g && i<len; ++i) {
15429             g = !B.hasClass(f, this.invalidHandleClasses[i]);
15430         }
15431
15432
15433         return  g;
15434
15435     },
15436
15437     /**
15438      * Create the array of horizontal tick marks if an interval was specified
15439      * in setXConstraint().
15440      * @method setXTicks
15441      * @private
15442      */
15443     setXTicks: function(j, k) {
15444         this.xTicks = [];
15445         this.xTickSize = k;
15446
15447         var  l = {};
15448
15449         for (var  i = this.initPageX; i >= this.minX; i = i - k) {
15450             if (!l[i]) {
15451                 this.xTicks[this.xTicks.length] = i;
15452                 l[i] = true;
15453             }
15454         }
15455
15456         for (i = this.initPageX; i <= this.maxX; i = i + k) {
15457             if (!l[i]) {
15458                 this.xTicks[this.xTicks.length] = i;
15459                 l[i] = true;
15460             }
15461         }
15462
15463
15464         this.xTicks.sort(this.DDM.numericSort) ;
15465     },
15466
15467     /**
15468      * Create the array of vertical tick marks if an interval was specified in
15469      * setYConstraint().
15470      * @method setYTicks
15471      * @private
15472      */
15473     setYTicks: function(m, n) {
15474         this.yTicks = [];
15475         this.yTickSize = n;
15476
15477         var  o = {};
15478
15479         for (var  i = this.initPageY; i >= this.minY; i = i - n) {
15480             if (!o[i]) {
15481                 this.yTicks[this.yTicks.length] = i;
15482                 o[i] = true;
15483             }
15484         }
15485
15486         for (i = this.initPageY; i <= this.maxY; i = i + n) {
15487             if (!o[i]) {
15488                 this.yTicks[this.yTicks.length] = i;
15489                 o[i] = true;
15490             }
15491         }
15492
15493
15494         this.yTicks.sort(this.DDM.numericSort) ;
15495     },
15496
15497     /**
15498      * By default, the element can be dragged any place on the screen.  Use
15499      * this method to limit the horizontal travel of the element.  Pass in
15500      * 0,0 for the parameters if you want to lock the drag to the y axis.
15501      * @method setXConstraint
15502      * @param {int} iLeft the number of pixels the element can move to the left
15503      * @param {int} iRight the number of pixels the element can move to the
15504      * right
15505      * @param {int} iTickSize optional parameter for specifying that the
15506      * element
15507      * should move iTickSize pixels at a time.
15508      */
15509     setXConstraint: function(q, r, t) {
15510         this.leftConstraint = q;
15511         this.rightConstraint = r;
15512
15513         this.minX = this.initPageX - q;
15514         this.maxX = this.initPageX + r;
15515         if (t) { this.setXTicks(this.initPageX, t); }
15516
15517
15518         this.constrainX = true;
15519     },
15520
15521     /**
15522      * Clears any constraints applied to this instance.  Also clears ticks
15523      * since they can't exist independent of a constraint at this time.
15524      * @method clearConstraints
15525      */
15526     clearConstraints: function() {
15527         this.constrainX = false;
15528         this.constrainY = false;
15529         this.clearTicks();
15530     },
15531
15532     /**
15533      * Clears any tick interval defined for this instance
15534      * @method clearTicks
15535      */
15536     clearTicks: function() {
15537         this.xTicks = null;
15538         this.yTicks = null;
15539         this.xTickSize = 0;
15540         this.yTickSize = 0;
15541     },
15542
15543     /**
15544      * By default, the element can be dragged any place on the screen.  Set
15545      * this to limit the vertical travel of the element.  Pass in 0,0 for the
15546      * parameters if you want to lock the drag to the x axis.
15547      * @method setYConstraint
15548      * @param {int} iUp the number of pixels the element can move up
15549      * @param {int} iDown the number of pixels the element can move down
15550      * @param {int} iTickSize optional parameter for specifying that the
15551      * element should move iTickSize pixels at a time.
15552      */
15553     setYConstraint: function(u, v, w) {
15554         this.topConstraint = u;
15555         this.bottomConstraint = v;
15556
15557         this.minY = this.initPageY - u;
15558         this.maxY = this.initPageY + v;
15559         if (w) { this.setYTicks(this.initPageY, w); }
15560
15561
15562         this.constrainY = true;
15563
15564     },
15565
15566     /**
15567      * resetConstraints must be called if you manually reposition a dd element.
15568      * @method resetConstraints
15569      * @param {boolean} maintainOffset
15570      */
15571     resetConstraints: function() {
15572
15573
15574         // Maintain offsets if necessary
15575         if (this.initPageX || this.initPageX === 0) {
15576             // figure out how much this thing has moved
15577             var  dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15578             var  dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15579
15580             this.setInitPosition(dx, dy);
15581
15582         // This is the first time we have detected the element's position
15583         } else  {
15584             this.setInitPosition();
15585         }
15586
15587         if (this.constrainX) {
15588             this.setXConstraint( this.leftConstraint,
15589                                  this.rightConstraint,
15590                                  this.xTickSize        );
15591         }
15592
15593         if (this.constrainY) {
15594             this.setYConstraint( this.topConstraint,
15595                                  this.bottomConstraint,
15596                                  this.yTickSize         );
15597         }
15598     },
15599
15600     /**
15601      * Normally the drag element is moved pixel by pixel, but we can specify
15602      * that it move a number of pixels at a time.  This method resolves the
15603      * location when we have it set up like this.
15604      * @method getTick
15605      * @param {int} val where we want to place the object
15606      * @param {int[]} tickArray sorted array of valid points
15607      * @return {int} the closest tick
15608      * @private
15609      */
15610     getTick: function(z, AA) {
15611
15612         if (!AA) {
15613             // If tick interval is not defined, it is effectively 1 pixel,
15614             // so we return the value passed to us.
15615             return  z;
15616         } else  if (AA[0] >= z) {
15617             // The value is lower than the first tick, so we return the first
15618             // tick.
15619             return  AA[0];
15620         } else  {
15621             for (var  i=0, len=AA.length; i<len; ++i) {
15622                 var  next = i + 1;
15623                 if (AA[next] && AA[next] >= z) {
15624                     var  diff1 = z - AA[i];
15625                     var  diff2 = AA[next] - z;
15626                     return  (diff2 > diff1) ? AA[i] : AA[next];
15627                 }
15628             }
15629
15630             // The value is larger than the last tick, so we return the last
15631             // tick.
15632             return  AA[AA.length - 1];
15633         }
15634     },
15635
15636     /**
15637      * toString method
15638      * @method toString
15639      * @return {string} string representation of the dd obj
15640      */
15641     toString: function() {
15642         return  ("DragDrop " + this.id);
15643     }
15644
15645 };
15646
15647 })();
15648
15649 /*
15650  * Based on:
15651  * Ext JS Library 1.1.1
15652  * Copyright(c) 2006-2007, Ext JS, LLC.
15653  *
15654  * Originally Released Under LGPL - original licence link has changed is not relivant.
15655  *
15656  * Fork - LGPL
15657  * <script type="text/javascript">
15658  */
15659
15660
15661 /**
15662  * The drag and drop utility provides a framework for building drag and drop
15663  * applications.  In addition to enabling drag and drop for specific elements,
15664  * the drag and drop elements are tracked by the manager class, and the
15665  * interactions between the various elements are tracked during the drag and
15666  * the implementing code is notified about these important moments.
15667  */
15668
15669 // Only load the library once.  Rewriting the manager class would orphan
15670 // existing drag and drop instances.
15671 if (!Roo.dd.DragDropMgr) {
15672
15673 /**
15674  * @class Roo.dd.DragDropMgr
15675  * DragDropMgr is a singleton that tracks the element interaction for
15676  * all DragDrop items in the window.  Generally, you will not call
15677  * this class directly, but it does have helper methods that could
15678  * be useful in your DragDrop implementations.
15679  * @singleton
15680  */
15681 Roo.dd.DragDropMgr = function() {
15682
15683     var  A = Roo.EventManager;
15684
15685     return  {
15686
15687         /**
15688          * Two dimensional Array of registered DragDrop objects.  The first
15689          * dimension is the DragDrop item group, the second the DragDrop
15690          * object.
15691          * @property ids
15692          * @type {string: string}
15693          * @private
15694          * @static
15695          */
15696         ids: {},
15697
15698         /**
15699          * Array of element ids defined as drag handles.  Used to determine
15700          * if the element that generated the mousedown event is actually the
15701          * handle and not the html element itself.
15702          * @property handleIds
15703          * @type {string: string}
15704          * @private
15705          * @static
15706          */
15707         handleIds: {},
15708
15709         /**
15710          * the DragDrop object that is currently being dragged
15711          * @property dragCurrent
15712          * @type DragDrop
15713          * @private
15714          * @static
15715          **/
15716         dragCurrent: null,
15717
15718         /**
15719          * the DragDrop object(s) that are being hovered over
15720          * @property dragOvers
15721          * @type Array
15722          * @private
15723          * @static
15724          */
15725         dragOvers: {},
15726
15727         /**
15728          * the X distance between the cursor and the object being dragged
15729          * @property deltaX
15730          * @type int
15731          * @private
15732          * @static
15733          */
15734         deltaX: 0,
15735
15736         /**
15737          * the Y distance between the cursor and the object being dragged
15738          * @property deltaY
15739          * @type int
15740          * @private
15741          * @static
15742          */
15743         deltaY: 0,
15744
15745         /**
15746          * Flag to determine if we should prevent the default behavior of the
15747          * events we define. By default this is true, but this can be set to
15748          * false if you need the default behavior (not recommended)
15749          * @property preventDefault
15750          * @type boolean
15751          * @static
15752          */
15753         preventDefault: true,
15754
15755         /**
15756          * Flag to determine if we should stop the propagation of the events
15757          * we generate. This is true by default but you may want to set it to
15758          * false if the html element contains other features that require the
15759          * mouse click.
15760          * @property stopPropagation
15761          * @type boolean
15762          * @static
15763          */
15764         stopPropagation: true,
15765
15766         /**
15767          * Internal flag that is set to true when drag and drop has been
15768          * intialized
15769          * @property initialized
15770          * @private
15771          * @static
15772          */
15773         initalized: false,
15774
15775         /**
15776          * All drag and drop can be disabled.
15777          * @property locked
15778          * @private
15779          * @static
15780          */
15781         locked: false,
15782
15783         /**
15784          * Called the first time an element is registered.
15785          * @method init
15786          * @private
15787          * @static
15788          */
15789         init: function() {
15790             this.initialized = true;
15791         },
15792
15793         /**
15794          * In point mode, drag and drop interaction is defined by the
15795          * location of the cursor during the drag/drop
15796          * @property POINT
15797          * @type int
15798          * @static
15799          */
15800         POINT: 0,
15801
15802         /**
15803          * In intersect mode, drag and drop interactio nis defined by the
15804          * overlap of two or more drag and drop objects.
15805          * @property INTERSECT
15806          * @type int
15807          * @static
15808          */
15809         INTERSECT: 1,
15810
15811         /**
15812          * The current drag and drop mode.  Default: POINT
15813          * @property mode
15814          * @type int
15815          * @static
15816          */
15817         mode: 0,
15818
15819         /**
15820          * Runs method on all drag and drop objects
15821          * @method _execOnAll
15822          * @private
15823          * @static
15824          */
15825         _execOnAll: function(AG, AH) {
15826             for (var  i  in  this.ids) {
15827                 for (var  j  in  this.ids[i]) {
15828                     var  h = this.ids[i][j];
15829                     if (! this.isTypeOfDD(h)) {
15830                         continue;
15831                     }
15832
15833                     h[AG].apply(h, AH);
15834                 }
15835             }
15836         },
15837
15838         /**
15839          * Drag and drop initialization.  Sets up the global event handlers
15840          * @method _onLoad
15841          * @private
15842          * @static
15843          */
15844         _onLoad: function() {
15845
15846             this.init();
15847
15848
15849             A.on(document, "mouseup",   this.handleMouseUp, this, true);
15850             A.on(document, "mousemove", this.handleMouseMove, this, true);
15851             A.on(window,   "unload",    this._onUnload, this, true);
15852             A.on(window,   "resize",    this._onResize, this, true);
15853             // Event.on(window,   "mouseout",    this._test);
15854
15855         },
15856
15857         /**
15858          * Reset constraints on all drag and drop objs
15859          * @method _onResize
15860          * @private
15861          * @static
15862          */
15863         _onResize: function(e) {
15864             this._execOnAll("resetConstraints", []);
15865         },
15866
15867         /**
15868          * Lock all drag and drop functionality
15869          * @method lock
15870          * @static
15871          */
15872         lock: function() { this.locked = true; },
15873
15874         /**
15875          * Unlock all drag and drop functionality
15876          * @method unlock
15877          * @static
15878          */
15879         unlock: function() { this.locked = false; },
15880
15881         /**
15882          * Is drag and drop locked?
15883          * @method isLocked
15884          * @return {boolean} True if drag and drop is locked, false otherwise.
15885          * @static
15886          */
15887         isLocked: function() { return  this.locked; },
15888
15889         /**
15890          * Location cache that is set for all drag drop objects when a drag is
15891          * initiated, cleared when the drag is finished.
15892          * @property locationCache
15893          * @private
15894          * @static
15895          */
15896         locationCache: {},
15897
15898         /**
15899          * Set useCache to false if you want to force object the lookup of each
15900          * drag and drop linked element constantly during a drag.
15901          * @property useCache
15902          * @type boolean
15903          * @static
15904          */
15905         useCache: true,
15906
15907         /**
15908          * The number of pixels that the mouse needs to move after the
15909          * mousedown before the drag is initiated.  Default=3;
15910          * @property clickPixelThresh
15911          * @type int
15912          * @static
15913          */
15914         clickPixelThresh: 3,
15915
15916         /**
15917          * The number of milliseconds after the mousedown event to initiate the
15918          * drag if we don't get a mouseup event. Default=1000
15919          * @property clickTimeThresh
15920          * @type int
15921          * @static
15922          */
15923         clickTimeThresh: 350,
15924
15925         /**
15926          * Flag that indicates that either the drag pixel threshold or the
15927          * mousdown time threshold has been met
15928          * @property dragThreshMet
15929          * @type boolean
15930          * @private
15931          * @static
15932          */
15933         dragThreshMet: false,
15934
15935         /**
15936          * Timeout used for the click time threshold
15937          * @property clickTimeout
15938          * @type Object
15939          * @private
15940          * @static
15941          */
15942         clickTimeout: null,
15943
15944         /**
15945          * The X position of the mousedown event stored for later use when a
15946          * drag threshold is met.
15947          * @property startX
15948          * @type int
15949          * @private
15950          * @static
15951          */
15952         startX: 0,
15953
15954         /**
15955          * The Y position of the mousedown event stored for later use when a
15956          * drag threshold is met.
15957          * @property startY
15958          * @type int
15959          * @private
15960          * @static
15961          */
15962         startY: 0,
15963
15964         /**
15965          * Each DragDrop instance must be registered with the DragDropMgr.
15966          * This is executed in DragDrop.init()
15967          * @method regDragDrop
15968          * @param {DragDrop} oDD the DragDrop object to register
15969          * @param {String} sGroup the name of the group this element belongs to
15970          * @static
15971          */
15972         regDragDrop: function(AI, AJ) {
15973             if (!this.initialized) { this.init(); }
15974
15975             if (!this.ids[AJ]) {
15976                 this.ids[AJ] = {};
15977             }
15978
15979             this.ids[AJ][AI.id] = AI;
15980         },
15981
15982         /**
15983          * Removes the supplied dd instance from the supplied group. Executed
15984          * by DragDrop.removeFromGroup, so don't call this function directly.
15985          * @method removeDDFromGroup
15986          * @private
15987          * @static
15988          */
15989         removeDDFromGroup: function(AK, AL) {
15990             if (!this.ids[AL]) {
15991                 this.ids[AL] = {};
15992             }
15993
15994             var  AM = this.ids[AL];
15995             if (AM && AM[AK.id]) {
15996                 delete  AM[AK.id];
15997             }
15998         },
15999
16000         /**
16001          * Unregisters a drag and drop item.  This is executed in
16002          * DragDrop.unreg, use that method instead of calling this directly.
16003          * @method _remove
16004          * @private
16005          * @static
16006          */
16007         _remove: function(AN) {
16008             for (var  g  in  AN.groups) {
16009                 if (g && this.ids[g][AN.id]) {
16010                     delete  this.ids[g][AN.id];
16011                 }
16012             }
16013             delete  this.handleIds[AN.id];
16014         },
16015
16016         /**
16017          * Each DragDrop handle element must be registered.  This is done
16018          * automatically when executing DragDrop.setHandleElId()
16019          * @method regHandle
16020          * @param {String} sDDId the DragDrop id this element is a handle for
16021          * @param {String} sHandleId the id of the element that is the drag
16022          * handle
16023          * @static
16024          */
16025         regHandle: function(AO, AP) {
16026             if (!this.handleIds[AO]) {
16027                 this.handleIds[AO] = {};
16028             }
16029
16030             this.handleIds[AO][AP] = AP;
16031         },
16032
16033         /**
16034          * Utility function to determine if a given element has been
16035          * registered as a drag drop item.
16036          * @method isDragDrop
16037          * @param {String} id the element id to check
16038          * @return {boolean} true if this element is a DragDrop item,
16039          * false otherwise
16040          * @static
16041          */
16042         isDragDrop: function(id) {
16043             return  ( this.getDDById(id) ) ? true : false;
16044         },
16045
16046         /**
16047          * Returns the drag and drop instances that are in all groups the
16048          * passed in instance belongs to.
16049          * @method getRelated
16050          * @param {DragDrop} p_oDD the obj to get related data for
16051          * @param {boolean} bTargetsOnly if true, only return targetable objs
16052          * @return {DragDrop[]} the related instances
16053          * @static
16054          */
16055         getRelated: function(AQ, AR) {
16056             var  AS = [];
16057             for (var  i  in  AQ.groups) {
16058                 for (j  in  this.ids[i]) {
16059                     var  dd = this.ids[i][j];
16060                     if (! this.isTypeOfDD(dd)) {
16061                         continue;
16062                     }
16063                     if (!AR || dd.isTarget) {
16064                         AS[AS.length] = dd;
16065                     }
16066                 }
16067             }
16068
16069             return  AS;
16070         },
16071
16072         /**
16073          * Returns true if the specified dd target is a legal target for
16074          * the specifice drag obj
16075          * @method isLegalTarget
16076          * @param {DragDrop} the drag obj
16077          * @param {DragDrop} the target
16078          * @return {boolean} true if the target is a legal target for the
16079          * dd obj
16080          * @static
16081          */
16082         isLegalTarget: function (AT, AU) {
16083             var  AV = this.getRelated(AT, true);
16084             for (var  i=0, d=AV.length;i<d;++i) {
16085                 if (AV[i].id == AU.id) {
16086                     return  true;
16087                 }
16088             }
16089
16090             return  false;
16091         },
16092
16093         /**
16094          * My goal is to be able to transparently determine if an object is
16095          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
16096          * returns "object", oDD.constructor.toString() always returns
16097          * "DragDrop" and not the name of the subclass.  So for now it just
16098          * evaluates a well-known variable in DragDrop.
16099          * @method isTypeOfDD
16100          * @param {Object} the object to evaluate
16101          * @return {boolean} true if typeof oDD = DragDrop
16102          * @static
16103          */
16104         isTypeOfDD: function (AW) {
16105             return  (AW && AW.__ygDragDrop);
16106         },
16107
16108         /**
16109          * Utility function to determine if a given element has been
16110          * registered as a drag drop handle for the given Drag Drop object.
16111          * @method isHandle
16112          * @param {String} id the element id to check
16113          * @return {boolean} true if this element is a DragDrop handle, false
16114          * otherwise
16115          * @static
16116          */
16117         isHandle: function(AX, AY) {
16118             return  ( this.handleIds[AX] &&
16119                             this.handleIds[AX][AY] );
16120         },
16121
16122         /**
16123          * Returns the DragDrop instance for a given id
16124          * @method getDDById
16125          * @param {String} id the id of the DragDrop object
16126          * @return {DragDrop} the drag drop object, null if it is not found
16127          * @static
16128          */
16129         getDDById: function(id) {
16130             for (var  i  in  this.ids) {
16131                 if (this.ids[i][id]) {
16132                     return  this.ids[i][id];
16133                 }
16134             }
16135             return  null;
16136         },
16137
16138         /**
16139          * Fired after a registered DragDrop object gets the mousedown event.
16140          * Sets up the events required to track the object being dragged
16141          * @method handleMouseDown
16142          * @param {Event} e the event
16143          * @param oDD the DragDrop object being dragged
16144          * @private
16145          * @static
16146          */
16147         handleMouseDown: function(e, AZ) {
16148             if(Roo.QuickTips){
16149                 Roo.QuickTips.disable();
16150             }
16151
16152             this.currentTarget = e.getTarget();
16153
16154             this.dragCurrent = AZ;
16155
16156             var  el = AZ.getEl();
16157
16158             // track start position
16159             this.startX = e.getPageX();
16160             this.startY = e.getPageY();
16161
16162             this.deltaX = this.startX - el.offsetLeft;
16163             this.deltaY = this.startY - el.offsetTop;
16164
16165             this.dragThreshMet = false;
16166
16167             this.clickTimeout = setTimeout(
16168                     function() {
16169                         var  Aa = Roo.dd.DDM;
16170                         Aa.startDrag(Aa.startX, Aa.startY);
16171                     },
16172                     this.clickTimeThresh );
16173         },
16174
16175         /**
16176          * Fired when either the drag pixel threshol or the mousedown hold
16177          * time threshold has been met.
16178          * @method startDrag
16179          * @param x {int} the X position of the original mousedown
16180          * @param y {int} the Y position of the original mousedown
16181          * @static
16182          */
16183         startDrag: function(x, y) {
16184             clearTimeout(this.clickTimeout);
16185             if (this.dragCurrent) {
16186                 this.dragCurrent.b4StartDrag(x, y);
16187                 this.dragCurrent.startDrag(x, y);
16188             }
16189
16190             this.dragThreshMet = true;
16191         },
16192
16193         /**
16194          * Internal function to handle the mouseup event.  Will be invoked
16195          * from the context of the document.
16196          * @method handleMouseUp
16197          * @param {Event} e the event
16198          * @private
16199          * @static
16200          */
16201         handleMouseUp: function(e) {
16202
16203             if(Roo.QuickTips){
16204                 Roo.QuickTips.enable();
16205             }
16206             if (! this.dragCurrent) {
16207                 return;
16208             }
16209
16210
16211             clearTimeout(this.clickTimeout);
16212
16213             if (this.dragThreshMet) {
16214                 this.fireEvents(e, true);
16215             } else  {
16216             }
16217
16218
16219             this.stopDrag(e);
16220
16221             this.stopEvent(e);
16222         },
16223
16224         /**
16225          * Utility to stop event propagation and event default, if these
16226          * features are turned on.
16227          * @method stopEvent
16228          * @param {Event} e the event as returned by this.getEvent()
16229          * @static
16230          */
16231         stopEvent: function(e){
16232             if(this.stopPropagation) {
16233                 e.stopPropagation();
16234             }
16235
16236             if (this.preventDefault) {
16237                 e.preventDefault();
16238             }
16239         },
16240
16241         /**
16242          * Internal function to clean up event handlers after the drag
16243          * operation is complete
16244          * @method stopDrag
16245          * @param {Event} e the event
16246          * @private
16247          * @static
16248          */
16249         stopDrag: function(e) {
16250             // Fire the drag end event for the item that was dragged
16251             if (this.dragCurrent) {
16252                 if (this.dragThreshMet) {
16253                     this.dragCurrent.b4EndDrag(e);
16254                     this.dragCurrent.endDrag(e);
16255                 }
16256
16257
16258                 this.dragCurrent.onMouseUp(e);
16259             }
16260
16261
16262             this.dragCurrent = null;
16263             this.dragOvers = {};
16264         },
16265
16266         /**
16267          * Internal function to handle the mousemove event.  Will be invoked
16268          * from the context of the html element.
16269          *
16270          * @TODO figure out what we can do about mouse events lost when the
16271          * user drags objects beyond the window boundary.  Currently we can
16272          * detect this in internet explorer by verifying that the mouse is
16273          * down during the mousemove event.  Firefox doesn't give us the
16274          * button state on the mousemove event.
16275          * @method handleMouseMove
16276          * @param {Event} e the event
16277          * @private
16278          * @static
16279          */
16280         handleMouseMove: function(e) {
16281             if (! this.dragCurrent) {
16282                 return  true;
16283             }
16284
16285             // var button = e.which || e.button;
16286
16287             // check for IE mouseup outside of page boundary
16288             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16289                 this.stopEvent(e);
16290                 return  this.handleMouseUp(e);
16291             }
16292
16293             if (!this.dragThreshMet) {
16294                 var  diffX = Math.abs(this.startX - e.getPageX());
16295                 var  diffY = Math.abs(this.startY - e.getPageY());
16296                 if (diffX > this.clickPixelThresh ||
16297                             diffY > this.clickPixelThresh) {
16298                     this.startDrag(this.startX, this.startY);
16299                 }
16300             }
16301
16302             if (this.dragThreshMet) {
16303                 this.dragCurrent.b4Drag(e);
16304                 this.dragCurrent.onDrag(e);
16305                 if(!this.dragCurrent.moveOnly){
16306                     this.fireEvents(e, false);
16307                 }
16308             }
16309
16310
16311             this.stopEvent(e);
16312
16313             return  true;
16314         },
16315
16316         /**
16317          * Iterates over all of the DragDrop elements to find ones we are
16318          * hovering over or dropping on
16319          * @method fireEvents
16320          * @param {Event} e the event
16321          * @param {boolean} isDrop is this a drop op or a mouseover op?
16322          * @private
16323          * @static
16324          */
16325         fireEvents: function(e, Aa) {
16326             var  dc = this.dragCurrent;
16327
16328             // If the user did the mouse up outside of the window, we could
16329             // get here even though we have ended the drag.
16330             if (!dc || dc.isLocked()) {
16331                 return;
16332             }
16333
16334             var  pt = e.getPoint();
16335
16336             // cache the previous dragOver array
16337             var  Ab = [];
16338
16339             var  Ac   = [];
16340             var  Ad  = [];
16341             var  Ae  = [];
16342             var  Af = [];
16343
16344             // Check to see if the object(s) we were hovering over is no longer
16345             // being hovered over so we can fire the onDragOut event
16346             for (var  i  in  this.dragOvers) {
16347
16348                 var  ddo = this.dragOvers[i];
16349
16350                 if (! this.isTypeOfDD(ddo)) {
16351                     continue;
16352                 }
16353
16354                 if (! this.isOverTarget(pt, ddo, this.mode)) {
16355                     Ac.push( ddo );
16356                 }
16357
16358
16359                 Ab[i] = true;
16360                 delete  this.dragOvers[i];
16361             }
16362
16363             for (var  AL  in  dc.groups) {
16364
16365                 if ("string" != typeof  AL) {
16366                     continue;
16367                 }
16368
16369                 for (i  in  this.ids[AL]) {
16370                     var  AZ = this.ids[AL][i];
16371                     if (! this.isTypeOfDD(AZ)) {
16372                         continue;
16373                     }
16374
16375                     if (AZ.isTarget && !AZ.isLocked() && AZ != dc) {
16376                         if (this.isOverTarget(pt, AZ, this.mode)) {
16377                             // look for drop interactions
16378                             if (Aa) {
16379                                 Ae.push( AZ );
16380                             // look for drag enter and drag over interactions
16381                             } else  {
16382
16383                                 // initial drag over: dragEnter fires
16384                                 if (!Ab[AZ.id]) {
16385                                     Af.push( AZ );
16386                                 // subsequent drag overs: dragOver fires
16387                                 } else  {
16388                                     Ad.push( AZ );
16389                                 }
16390
16391
16392                                 this.dragOvers[AZ.id] = AZ;
16393                             }
16394                         }
16395                     }
16396                 }
16397             }
16398
16399             if (this.mode) {
16400                 if (Ac.length) {
16401                     dc.b4DragOut(e, Ac);
16402                     dc.onDragOut(e, Ac);
16403                 }
16404
16405                 if (Af.length) {
16406                     dc.onDragEnter(e, Af);
16407                 }
16408
16409                 if (Ad.length) {
16410                     dc.b4DragOver(e, Ad);
16411                     dc.onDragOver(e, Ad);
16412                 }
16413
16414                 if (Ae.length) {
16415                     dc.b4DragDrop(e, Ae);
16416                     dc.onDragDrop(e, Ae);
16417                 }
16418
16419             } else  {
16420                 // fire dragout events
16421                 var  d = 0;
16422                 for (i=0, d=Ac.length; i<d; ++i) {
16423                     dc.b4DragOut(e, Ac[i].id);
16424                     dc.onDragOut(e, Ac[i].id);
16425                 }
16426
16427                 // fire enter events
16428                 for (i=0,d=Af.length; i<d; ++i) {
16429                     // dc.b4DragEnter(e, oDD.id);
16430                     dc.onDragEnter(e, Af[i].id);
16431                 }
16432
16433                 // fire over events
16434                 for (i=0,d=Ad.length; i<d; ++i) {
16435                     dc.b4DragOver(e, Ad[i].id);
16436                     dc.onDragOver(e, Ad[i].id);
16437                 }
16438
16439                 // fire drop events
16440                 for (i=0, d=Ae.length; i<d; ++i) {
16441                     dc.b4DragDrop(e, Ae[i].id);
16442                     dc.onDragDrop(e, Ae[i].id);
16443                 }
16444
16445             }
16446
16447             // notify about a drop that did not find a target
16448             if (Aa && !Ae.length) {
16449                 dc.onInvalidDrop(e);
16450             }
16451
16452         },
16453
16454         /**
16455          * Helper function for getting the best match from the list of drag
16456          * and drop objects returned by the drag and drop events when we are
16457          * in INTERSECT mode.  It returns either the first object that the
16458          * cursor is over, or the object that has the greatest overlap with
16459          * the dragged element.
16460          * @method getBestMatch
16461          * @param  {DragDrop[]} dds The array of drag and drop objects
16462          * targeted
16463          * @return {DragDrop}       The best single match
16464          * @static
16465          */
16466         getBestMatch: function(Ag) {
16467             var  Ah = null;
16468             // Return null if the input is not what we expect
16469             //if (!dds || !dds.length || dds.length == 0) {
16470                // winner = null;
16471             // If there is only one item, it wins
16472             //} else if (dds.length == 1) {
16473
16474             var  Ai = Ag.length;
16475
16476             if (Ai == 1) {
16477                 Ah = Ag[0];
16478             } else  {
16479                 // Loop through the targeted items
16480                 for (var  i=0; i<Ai; ++i) {
16481                     var  dd = Ag[i];
16482                     // If the cursor is over the object, it wins.  If the
16483                     // cursor is over multiple matches, the first one we come
16484                     // to wins.
16485                     if (dd.cursorIsOver) {
16486                         Ah = dd;
16487                         break;
16488                     // Otherwise the object with the most overlap wins
16489                     } else  {
16490                         if (!Ah ||
16491                             Ah.overlap.getArea() < dd.overlap.getArea()) {
16492                             Ah = dd;
16493                         }
16494                     }
16495                 }
16496             }
16497
16498             return  Ah;
16499         },
16500
16501         /**
16502          * Refreshes the cache of the top-left and bottom-right points of the
16503          * drag and drop objects in the specified group(s).  This is in the
16504          * format that is stored in the drag and drop instance, so typical
16505          * usage is:
16506          * <code>
16507          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16508          * </code>
16509          * Alternatively:
16510          * <code>
16511          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16512          * </code>
16513          * @TODO this really should be an indexed array.  Alternatively this
16514          * method could accept both.
16515          * @method refreshCache
16516          * @param {Object} groups an associative array of groups to refresh
16517          * @static
16518          */
16519         refreshCache: function(Aj) {
16520             for (var  AL  in  Aj) {
16521                 if ("string" != typeof  AL) {
16522                     continue;
16523                 }
16524                 for (var  i  in  this.ids[AL]) {
16525                     var  AZ = this.ids[AL][i];
16526
16527                     if (this.isTypeOfDD(AZ)) {
16528                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16529                         var  o = this.getLocation(AZ);
16530                         if (o) {
16531                             this.locationCache[AZ.id] = o;
16532                         } else  {
16533                             delete  this.locationCache[AZ.id];
16534                             // this will unregister the drag and drop object if
16535                             // the element is not in a usable state
16536                             // oDD.unreg();
16537                         }
16538                     }
16539                 }
16540             }
16541         },
16542
16543         /**
16544          * This checks to make sure an element exists and is in the DOM.  The
16545          * main purpose is to handle cases where innerHTML is used to remove
16546          * drag and drop objects from the DOM.  IE provides an 'unspecified
16547          * error' when trying to access the offsetParent of such an element
16548          * @method verifyEl
16549          * @param {HTMLElement} el the element to check
16550          * @return {boolean} true if the element looks usable
16551          * @static
16552          */
16553         verifyEl: function(el) {
16554             if (el) {
16555                 var  parent;
16556                 if(Roo.isIE){
16557                     try{
16558                         parent = el.offsetParent;
16559                     }catch(e){}
16560                 }else {
16561                     parent = el.offsetParent;
16562                 }
16563                 if (parent) {
16564                     return  true;
16565                 }
16566             }
16567
16568             return  false;
16569         },
16570
16571         /**
16572          * Returns a Region object containing the drag and drop element's position
16573          * and size, including the padding configured for it
16574          * @method getLocation
16575          * @param {DragDrop} oDD the drag and drop object to get the
16576          *                       location for
16577          * @return {Roo.lib.Region} a Region object representing the total area
16578          *                             the element occupies, including any padding
16579          *                             the instance is configured for.
16580          * @static
16581          */
16582         getLocation: function(Ak) {
16583             if (! this.isTypeOfDD(Ak)) {
16584                 return  null;
16585             }
16586
16587             var  el = Ak.getEl(), Al, x1, x2, y1, y2, t, r, b, l;
16588
16589             try {
16590                 Al= Roo.lib.Dom.getXY(el);
16591             } catch (e) { }
16592
16593             if (!Al) {
16594                 return  null;
16595             }
16596
16597
16598             x1 = Al[0];
16599             x2 = x1 + el.offsetWidth;
16600             y1 = Al[1];
16601             y2 = y1 + el.offsetHeight;
16602
16603             t = y1 - Ak.padding[0];
16604             r = x2 + Ak.padding[1];
16605             b = y2 + Ak.padding[2];
16606             l = x1 - Ak.padding[3];
16607
16608             return  new  Roo.lib.Region( t, r, b, l );
16609         },
16610
16611         /**
16612          * Checks the cursor location to see if it over the target
16613          * @method isOverTarget
16614          * @param {Roo.lib.Point} pt The point to evaluate
16615          * @param {DragDrop} oTarget the DragDrop object we are inspecting
16616          * @return {boolean} true if the mouse is over the target
16617          * @private
16618          * @static
16619          */
16620         isOverTarget: function(pt, Am, An) {
16621             // use cache if available
16622             var  Ao = this.locationCache[Am.id];
16623             if (!Ao || !this.useCache) {
16624                 Ao = this.getLocation(Am);
16625                 this.locationCache[Am.id] = Ao;
16626
16627             }
16628
16629             if (!Ao) {
16630                 return  false;
16631             }
16632
16633
16634             Am.cursorIsOver = Ao.contains( pt );
16635
16636             // DragDrop is using this as a sanity check for the initial mousedown
16637             // in this case we are done.  In POINT mode, if the drag obj has no
16638             // contraints, we are also done. Otherwise we need to evaluate the
16639             // location of the target as related to the actual location of the
16640             // dragged element.
16641             var  dc = this.dragCurrent;
16642             if (!dc || !dc.getTargetCoord ||
16643                     (!An && !dc.constrainX && !dc.constrainY)) {
16644                 return  Am.cursorIsOver;
16645             }
16646
16647
16648             Am.overlap = null;
16649
16650             // Get the current location of the drag element, this is the
16651             // location of the mouse event less the delta that represents
16652             // where the original mousedown happened on the element.  We
16653             // need to consider constraints and ticks as well.
16654             var  Ap = dc.getTargetCoord(pt.x, pt.y);
16655
16656             var  el = dc.getDragEl();
16657             var  Aq = new  Roo.lib.Region( Ap.y,
16658                                                    Ap.x + el.offsetWidth,
16659                                                    Ap.y + el.offsetHeight,
16660                                                    Ap.x );
16661
16662             var  Ar = Aq.intersect(Ao);
16663
16664             if (Ar) {
16665                 Am.overlap = Ar;
16666                 return  (An) ? true : Am.cursorIsOver;
16667             } else  {
16668                 return  false;
16669             }
16670         },
16671
16672         /**
16673          * unload event handler
16674          * @method _onUnload
16675          * @private
16676          * @static
16677          */
16678         _onUnload: function(e, me) {
16679             Roo.dd.DragDropMgr.unregAll();
16680         },
16681
16682         /**
16683          * Cleans up the drag and drop events and objects.
16684          * @method unregAll
16685          * @private
16686          * @static
16687          */
16688         unregAll: function() {
16689
16690             if (this.dragCurrent) {
16691                 this.stopDrag();
16692                 this.dragCurrent = null;
16693             }
16694
16695
16696             this._execOnAll("unreg", []);
16697
16698             for (i  in  this.elementCache) {
16699                 delete  this.elementCache[i];
16700             }
16701
16702
16703             this.elementCache = {};
16704             this.ids = {};
16705         },
16706
16707         /**
16708          * A cache of DOM elements
16709          * @property elementCache
16710          * @private
16711          * @static
16712          */
16713         elementCache: {},
16714
16715         /**
16716          * Get the wrapper for the DOM element specified
16717          * @method getElWrapper
16718          * @param {String} id the id of the element to get
16719          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16720          * @private
16721          * @deprecated This wrapper isn't that useful
16722          * @static
16723          */
16724         getElWrapper: function(id) {
16725             var  As = this.elementCache[id];
16726             if (!As || !As.el) {
16727                 As = this.elementCache[id] =
16728                     new  this.ElementWrapper(Roo.getDom(id));
16729             }
16730             return  As;
16731         },
16732
16733         /**
16734          * Returns the actual DOM element
16735          * @method getElement
16736          * @param {String} id the id of the elment to get
16737          * @return {Object} The element
16738          * @deprecated use Roo.getDom instead
16739          * @static
16740          */
16741         getElement: function(id) {
16742             return  Roo.getDom(id);
16743         },
16744
16745         /**
16746          * Returns the style property for the DOM element (i.e.,
16747          * document.getElById(id).style)
16748          * @method getCss
16749          * @param {String} id the id of the elment to get
16750          * @return {Object} The style property of the element
16751          * @deprecated use Roo.getDom instead
16752          * @static
16753          */
16754         getCss: function(id) {
16755             var  el = Roo.getDom(id);
16756             return  (el) ? el.style : null;
16757         },
16758
16759         /**
16760          * Inner class for cached elements
16761          * @class DragDropMgr.ElementWrapper
16762          * @for DragDropMgr
16763          * @private
16764          * @deprecated
16765          */
16766         ElementWrapper: function(el) {
16767                 /**
16768                  * The element
16769                  * @property el
16770                  */
16771                 this.el = el || null;
16772                 /**
16773                  * The element id
16774                  * @property id
16775                  */
16776                 this.id = this.el && el.id;
16777                 /**
16778                  * A reference to the style property
16779                  * @property css
16780                  */
16781                 this.css = this.el && el.style;
16782             },
16783
16784         /**
16785          * Returns the X position of an html element
16786          * @method getPosX
16787          * @param el the element for which to get the position
16788          * @return {int} the X coordinate
16789          * @for DragDropMgr
16790          * @deprecated use Roo.lib.Dom.getX instead
16791          * @static
16792          */
16793         getPosX: function(el) {
16794             return  Roo.lib.Dom.getX(el);
16795         },
16796
16797         /**
16798          * Returns the Y position of an html element
16799          * @method getPosY
16800          * @param el the element for which to get the position
16801          * @return {int} the Y coordinate
16802          * @deprecated use Roo.lib.Dom.getY instead
16803          * @static
16804          */
16805         getPosY: function(el) {
16806             return  Roo.lib.Dom.getY(el);
16807         },
16808
16809         /**
16810          * Swap two nodes.  In IE, we use the native method, for others we
16811          * emulate the IE behavior
16812          * @method swapNode
16813          * @param n1 the first node to swap
16814          * @param n2 the other node to swap
16815          * @static
16816          */
16817         swapNode: function(n1, n2) {
16818             if (n1.swapNode) {
16819                 n1.swapNode(n2);
16820             } else  {
16821                 var  p = n2.parentNode;
16822                 var  s = n2.nextSibling;
16823
16824                 if (s == n1) {
16825                     p.insertBefore(n1, n2);
16826                 } else  if (n2 == n1.nextSibling) {
16827                     p.insertBefore(n2, n1);
16828                 } else  {
16829                     n1.parentNode.replaceChild(n2, n1);
16830                     p.insertBefore(n1, s);
16831                 }
16832             }
16833         },
16834
16835         /**
16836          * Returns the current scroll position
16837          * @method getScroll
16838          * @private
16839          * @static
16840          */
16841         getScroll: function () {
16842             var  t, l, At=document.documentElement, db=document.body;
16843             if (At && (At.scrollTop || At.scrollLeft)) {
16844                 t = At.scrollTop;
16845                 l = At.scrollLeft;
16846             } else  if (db) {
16847                 t = db.scrollTop;
16848                 l = db.scrollLeft;
16849             } else  {
16850
16851             }
16852             return  { top: t, left: l };
16853         },
16854
16855         /**
16856          * Returns the specified element style property
16857          * @method getStyle
16858          * @param {HTMLElement} el          the element
16859          * @param {string}      styleProp   the style property
16860          * @return {string} The value of the style property
16861          * @deprecated use Roo.lib.Dom.getStyle
16862          * @static
16863          */
16864         getStyle: function(el, Au) {
16865             return  Roo.fly(el).getStyle(Au);
16866         },
16867
16868         /**
16869          * Gets the scrollTop
16870          * @method getScrollTop
16871          * @return {int} the document's scrollTop
16872          * @static
16873          */
16874         getScrollTop: function () { return  this.getScroll().top; },
16875
16876         /**
16877          * Gets the scrollLeft
16878          * @method getScrollLeft
16879          * @return {int} the document's scrollTop
16880          * @static
16881          */
16882         getScrollLeft: function () { return  this.getScroll().left; },
16883
16884         /**
16885          * Sets the x/y position of an element to the location of the
16886          * target element.
16887          * @method moveToEl
16888          * @param {HTMLElement} moveEl      The element to move
16889          * @param {HTMLElement} targetEl    The position reference element
16890          * @static
16891          */
16892         moveToEl: function (Av, Aw) {
16893             var  Ax = Roo.lib.Dom.getXY(Aw);
16894             Roo.lib.Dom.setXY(Av, Ax);
16895         },
16896
16897         /**
16898          * Numeric array sort function
16899          * @method numericSort
16900          * @static
16901          */
16902         numericSort: function(a, b) { return  (a - b); },
16903
16904         /**
16905          * Internal counter
16906          * @property _timeoutCount
16907          * @private
16908          * @static
16909          */
16910         _timeoutCount: 0,
16911
16912         /**
16913          * Trying to make the load order less important.  Without this we get
16914          * an error if this file is loaded before the Event Utility.
16915          * @method _addListeners
16916          * @private
16917          * @static
16918          */
16919         _addListeners: function() {
16920             var  Ay = Roo.dd.DDM;
16921             if ( Roo.lib.Event && document ) {
16922                 Ay._onLoad();
16923             } else  {
16924                 if (Ay._timeoutCount > 2000) {
16925                 } else  {
16926                     setTimeout(Ay._addListeners, 10);
16927                     if (document && document.body) {
16928                         Ay._timeoutCount += 1;
16929                     }
16930                 }
16931             }
16932         },
16933
16934         /**
16935          * Recursively searches the immediate parent and all child nodes for
16936          * the handle element in order to determine wheter or not it was
16937          * clicked.
16938          * @method handleWasClicked
16939          * @param node the html element to inspect
16940          * @static
16941          */
16942         handleWasClicked: function(Az, id) {
16943             if (this.isHandle(id, Az.id)) {
16944                 return  true;
16945             } else  {
16946                 // check to see if this is a text node child of the one we want
16947                 var  p = Az.parentNode;
16948
16949                 while (p) {
16950                     if (this.isHandle(id, p.id)) {
16951                         return  true;
16952                     } else  {
16953                         p = p.parentNode;
16954                     }
16955                 }
16956             }
16957
16958             return  false;
16959         }
16960
16961     };
16962
16963 }();
16964
16965 // shorter alias, save a few bytes
16966 Roo.dd.DDM = Roo.dd.DragDropMgr;
16967 Roo.dd.DDM._addListeners();
16968
16969 }
16970 /*
16971  * Based on:
16972  * Ext JS Library 1.1.1
16973  * Copyright(c) 2006-2007, Ext JS, LLC.
16974  *
16975  * Originally Released Under LGPL - original licence link has changed is not relivant.
16976  *
16977  * Fork - LGPL
16978  * <script type="text/javascript">
16979  */
16980
16981 /**
16982  * @class Roo.dd.DD
16983  * A DragDrop implementation where the linked element follows the
16984  * mouse cursor during a drag.
16985  * @extends Roo.dd.DragDrop
16986  * @constructor
16987  * @param {String} id the id of the linked element
16988  * @param {String} sGroup the group of related DragDrop items
16989  * @param {object} config an object containing configurable attributes
16990  *                Valid properties for DD:
16991  *                    scroll
16992  */
16993 Roo.dd.DD = function(id, A, B) {
16994     if (id) {
16995         this.init(id, A, B);
16996     }
16997 };
16998
16999 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17000
17001     /**
17002      * When set to true, the utility automatically tries to scroll the browser
17003      * window wehn a drag and drop element is dragged near the viewport boundary.
17004      * Defaults to true.
17005      * @property scroll
17006      * @type boolean
17007      */
17008     scroll: true,
17009
17010     /**
17011      * Sets the pointer offset to the distance between the linked element's top
17012      * left corner and the location the element was clicked
17013      * @method autoOffset
17014      * @param {int} iPageX the X coordinate of the click
17015      * @param {int} iPageY the Y coordinate of the click
17016      */
17017     autoOffset: function(C, D) {
17018         var  x = C - this.startPageX;
17019         var  y = D - this.startPageY;
17020         this.setDelta(x, y);
17021     },
17022
17023     /**
17024      * Sets the pointer offset.  You can call this directly to force the
17025      * offset to be in a particular location (e.g., pass in 0,0 to set it
17026      * to the center of the object)
17027      * @method setDelta
17028      * @param {int} iDeltaX the distance from the left
17029      * @param {int} iDeltaY the distance from the top
17030      */
17031     setDelta: function(E, F) {
17032         this.deltaX = E;
17033         this.deltaY = F;
17034     },
17035
17036     /**
17037      * Sets the drag element to the location of the mousedown or click event,
17038      * maintaining the cursor location relative to the location on the element
17039      * that was clicked.  Override this if you want to place the element in a
17040      * location other than where the cursor is.
17041      * @method setDragElPos
17042      * @param {int} iPageX the X coordinate of the mousedown or drag event
17043      * @param {int} iPageY the Y coordinate of the mousedown or drag event
17044      */
17045     setDragElPos: function(G, H) {
17046         // the first time we do this, we are going to check to make sure
17047         // the element has css positioning
17048
17049         var  el = this.getDragEl();
17050         this.alignElWithMouse(el, G, H);
17051     },
17052
17053     /**
17054      * Sets the element to the location of the mousedown or click event,
17055      * maintaining the cursor location relative to the location on the element
17056      * that was clicked.  Override this if you want to place the element in a
17057      * location other than where the cursor is.
17058      * @method alignElWithMouse
17059      * @param {HTMLElement} el the element to move
17060      * @param {int} iPageX the X coordinate of the mousedown or drag event
17061      * @param {int} iPageY the Y coordinate of the mousedown or drag event
17062      */
17063     alignElWithMouse: function(el, I, J) {
17064         var  K = this.getTargetCoord(I, J);
17065         var  L = el.dom ? el : Roo.fly(el);
17066         if (!this.deltaSetXY) {
17067             var  aCoord = [K.x, K.y];
17068             L.setXY(aCoord);
17069             var  newLeft = L.getLeft(true);
17070             var  newTop  = L.getTop(true);
17071             this.deltaSetXY = [ newLeft - K.x, newTop - K.y ];
17072         } else  {
17073             L.setLeftTop(K.x + this.deltaSetXY[0], K.y + this.deltaSetXY[1]);
17074         }
17075
17076
17077         this.cachePosition(K.x, K.y);
17078         this.autoScroll(K.x, K.y, el.offsetHeight, el.offsetWidth);
17079         return  K;
17080     },
17081
17082     /**
17083      * Saves the most recent position so that we can reset the constraints and
17084      * tick marks on-demand.  We need to know this so that we can calculate the
17085      * number of pixels the element is offset from its original position.
17086      * @method cachePosition
17087      * @param iPageX the current x position (optional, this just makes it so we
17088      * don't have to look it up again)
17089      * @param iPageY the current y position (optional, this just makes it so we
17090      * don't have to look it up again)
17091      */
17092     cachePosition: function(M, N) {
17093         if (M) {
17094             this.lastPageX = M;
17095             this.lastPageY = N;
17096         } else  {
17097             var  aCoord = Roo.lib.Dom.getXY(this.getEl());
17098             this.lastPageX = aCoord[0];
17099             this.lastPageY = aCoord[1];
17100         }
17101     },
17102
17103     /**
17104      * Auto-scroll the window if the dragged object has been moved beyond the
17105      * visible window boundary.
17106      * @method autoScroll
17107      * @param {int} x the drag element's x position
17108      * @param {int} y the drag element's y position
17109      * @param {int} h the height of the drag element
17110      * @param {int} w the width of the drag element
17111      * @private
17112      */
17113     autoScroll: function(x, y, h, w) {
17114
17115         if (this.scroll) {
17116             // The client height
17117             var  clientH = Roo.lib.Dom.getViewWidth();
17118
17119             // The client width
17120             var  clientW = Roo.lib.Dom.getViewHeight();
17121
17122             // The amt scrolled down
17123             var  st = this.DDM.getScrollTop();
17124
17125             // The amt scrolled right
17126             var  sl = this.DDM.getScrollLeft();
17127
17128             // Location of the bottom of the element
17129             var  bot = h + y;
17130
17131             // Location of the right of the element
17132             var  right = w + x;
17133
17134             // The distance from the cursor to the bottom of the visible area,
17135             // adjusted so that we don't scroll if the cursor is beyond the
17136             // element drag constraints
17137             var  toBot = (clientH + st - y - this.deltaY);
17138
17139             // The distance from the cursor to the right of the visible area
17140             var  toRight = (clientW + sl - x - this.deltaX);
17141
17142
17143             // How close to the edge the cursor must be before we scroll
17144             // var thresh = (document.all) ? 100 : 40;
17145             var  thresh = 40;
17146
17147             // How many pixels to scroll per autoscroll op.  This helps to reduce
17148             // clunky scrolling. IE is more sensitive about this ... it needs this
17149             // value to be higher.
17150             var  scrAmt = (document.all) ? 80 : 30;
17151
17152             // Scroll down if we are near the bottom of the visible page and the
17153             // obj extends below the crease
17154             if ( bot > clientH && toBot < thresh ) {
17155                 window.scrollTo(sl, st + scrAmt);
17156             }
17157
17158             // Scroll up if the window is scrolled down and the top of the object
17159             // goes above the top border
17160             if ( y < st && st > 0 && y - st < thresh ) {
17161                 window.scrollTo(sl, st - scrAmt);
17162             }
17163
17164             // Scroll right if the obj is beyond the right border and the cursor is
17165             // near the border.
17166             if ( right > clientW && toRight < thresh ) {
17167                 window.scrollTo(sl + scrAmt, st);
17168             }
17169
17170             // Scroll left if the window has been scrolled to the right and the obj
17171             // extends past the left border
17172             if ( x < sl && sl > 0 && x - sl < thresh ) {
17173                 window.scrollTo(sl - scrAmt, st);
17174             }
17175         }
17176     },
17177
17178     /**
17179      * Finds the location the element should be placed if we want to move
17180      * it to where the mouse location less the click offset would place us.
17181      * @method getTargetCoord
17182      * @param {int} iPageX the X coordinate of the click
17183      * @param {int} iPageY the Y coordinate of the click
17184      * @return an object that contains the coordinates (Object.x and Object.y)
17185      * @private
17186      */
17187     getTargetCoord: function(O, P) {
17188
17189
17190         var  x = O - this.deltaX;
17191         var  y = P - this.deltaY;
17192
17193         if (this.constrainX) {
17194             if (x < this.minX) { x = this.minX; }
17195             if (x > this.maxX) { x = this.maxX; }
17196         }
17197
17198         if (this.constrainY) {
17199             if (y < this.minY) { y = this.minY; }
17200             if (y > this.maxY) { y = this.maxY; }
17201         }
17202
17203
17204         x = this.getTick(x, this.xTicks);
17205         y = this.getTick(y, this.yTicks);
17206
17207
17208         return  {x:x, y:y};
17209     },
17210
17211     /*
17212      * Sets up config options specific to this class. Overrides
17213      * Roo.dd.DragDrop, but all versions of this method through the
17214      * inheritance chain are called
17215      */
17216     applyConfig: function() {
17217         Roo.dd.DD.superclass.applyConfig.call(this);
17218         this.scroll = (this.config.scroll !== false);
17219     },
17220
17221     /*
17222      * Event that fires prior to the onMouseDown event.  Overrides
17223      * Roo.dd.DragDrop.
17224      */
17225     b4MouseDown: function(e) {
17226         // this.resetConstraints();
17227         this.autoOffset(e.getPageX(),
17228                             e.getPageY());
17229     },
17230
17231     /*
17232      * Event that fires prior to the onDrag event.  Overrides
17233      * Roo.dd.DragDrop.
17234      */
17235     b4Drag: function(e) {
17236         this.setDragElPos(e.getPageX(),
17237                             e.getPageY());
17238     },
17239
17240     toString: function() {
17241         return  ("DD " + this.id);
17242     }
17243
17244     //////////////////////////////////////////////////////////////////////////
17245     // Debugging ygDragDrop events that can be overridden
17246     //////////////////////////////////////////////////////////////////////////
17247     /*
17248     startDrag: function(x, y) {
17249     },
17250
17251     onDrag: function(e) {
17252     },
17253
17254     onDragEnter: function(e, id) {
17255     },
17256
17257     onDragOver: function(e, id) {
17258     },
17259
17260     onDragOut: function(e, id) {
17261     },
17262
17263     onDragDrop: function(e, id) {
17264     },
17265
17266     endDrag: function(e) {
17267     }
17268
17269     */
17270
17271 });
17272 /*
17273  * Based on:
17274  * Ext JS Library 1.1.1
17275  * Copyright(c) 2006-2007, Ext JS, LLC.
17276  *
17277  * Originally Released Under LGPL - original licence link has changed is not relivant.
17278  *
17279  * Fork - LGPL
17280  * <script type="text/javascript">
17281  */
17282
17283 /**
17284  * @class Roo.dd.DDProxy
17285  * A DragDrop implementation that inserts an empty, bordered div into
17286  * the document that follows the cursor during drag operations.  At the time of
17287  * the click, the frame div is resized to the dimensions of the linked html
17288  * element, and moved to the exact location of the linked element.
17289  *
17290  * References to the "frame" element refer to the single proxy element that
17291  * was created to be dragged in place of all DDProxy elements on the
17292  * page.
17293  *
17294  * @extends Roo.dd.DD
17295  * @constructor
17296  * @param {String} id the id of the linked html element
17297  * @param {String} sGroup the group of related DragDrop objects
17298  * @param {object} config an object containing configurable attributes
17299  *                Valid properties for DDProxy in addition to those in DragDrop:
17300  *                   resizeFrame, centerFrame, dragElId
17301  */
17302 Roo.dd.DDProxy = function(id, A, B) {
17303     if (id) {
17304         this.init(id, A, B);
17305         this.initFrame();
17306     }
17307 };
17308
17309 /**
17310  * The default drag frame div id
17311  * @property Roo.dd.DDProxy.dragElId
17312  * @type String
17313  * @static
17314  */
17315 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17316
17317 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17318
17319     /**
17320      * By default we resize the drag frame to be the same size as the element
17321      * we want to drag (this is to get the frame effect).  We can turn it off
17322      * if we want a different behavior.
17323      * @property resizeFrame
17324      * @type boolean
17325      */
17326     resizeFrame: true,
17327
17328     /**
17329      * By default the frame is positioned exactly where the drag element is, so
17330      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
17331      * you do not have constraints on the obj is to have the drag frame centered
17332      * around the cursor.  Set centerFrame to true for this effect.
17333      * @property centerFrame
17334      * @type boolean
17335      */
17336     centerFrame: false,
17337
17338     /**
17339      * Creates the proxy element if it does not yet exist
17340      * @method createFrame
17341      */
17342     createFrame: function() {
17343         var  C = this;
17344         var  D = document.body;
17345
17346         if (!D || !D.firstChild) {
17347             setTimeout( function() { C.createFrame(); }, 50 );
17348             return;
17349         }
17350
17351         var  E = this.getDragEl();
17352
17353         if (!E) {
17354             E    = document.createElement("div");
17355             E.id = this.dragElId;
17356             var  s  = E.style;
17357
17358             s.position   = "absolute";
17359             s.visibility = "hidden";
17360             s.cursor     = "move";
17361             s.border     = "2px solid #aaa";
17362             s.zIndex     = 999;
17363
17364             // appendChild can blow up IE if invoked prior to the window load event
17365             // while rendering a table.  It is possible there are other scenarios
17366             // that would cause this to happen as well.
17367             D.insertBefore(E, D.firstChild);
17368         }
17369     },
17370
17371     /**
17372      * Initialization for the drag frame element.  Must be called in the
17373      * constructor of all subclasses
17374      * @method initFrame
17375      */
17376     initFrame: function() {
17377         this.createFrame();
17378     },
17379
17380     applyConfig: function() {
17381         Roo.dd.DDProxy.superclass.applyConfig.call(this);
17382
17383         this.resizeFrame = (this.config.resizeFrame !== false);
17384         this.centerFrame = (this.config.centerFrame);
17385         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17386     },
17387
17388     /**
17389      * Resizes the drag frame to the dimensions of the clicked object, positions
17390      * it over the object, and finally displays it
17391      * @method showFrame
17392      * @param {int} iPageX X click position
17393      * @param {int} iPageY Y click position
17394      * @private
17395      */
17396     showFrame: function(F, G) {
17397         var  el = this.getEl();
17398         var  H = this.getDragEl();
17399         var  s = H.style;
17400
17401         this._resizeProxy();
17402
17403         if (this.centerFrame) {
17404             this.setDelta( Math.round(parseInt(s.width,  10)/2),
17405                            Math.round(parseInt(s.height, 10)/2) );
17406         }
17407
17408
17409         this.setDragElPos(F, G);
17410
17411         Roo.fly(H).show();
17412     },
17413
17414     /**
17415      * The proxy is automatically resized to the dimensions of the linked
17416      * element when a drag is initiated, unless resizeFrame is set to false
17417      * @method _resizeProxy
17418      * @private
17419      */
17420     _resizeProxy: function() {
17421         if (this.resizeFrame) {
17422             var  el = this.getEl();
17423             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17424         }
17425     },
17426
17427     // overrides Roo.dd.DragDrop
17428     b4MouseDown: function(e) {
17429         var  x = e.getPageX();
17430         var  y = e.getPageY();
17431         this.autoOffset(x, y);
17432         this.setDragElPos(x, y);
17433     },
17434
17435     // overrides Roo.dd.DragDrop
17436     b4StartDrag: function(x, y) {
17437         // show the drag frame
17438         this.showFrame(x, y);
17439     },
17440
17441     // overrides Roo.dd.DragDrop
17442     b4EndDrag: function(e) {
17443         Roo.fly(this.getDragEl()).hide();
17444     },
17445
17446     // overrides Roo.dd.DragDrop
17447     // By default we try to move the element to the last location of the frame.
17448     // This is so that the default behavior mirrors that of Roo.dd.DD.
17449     endDrag: function(e) {
17450
17451         var  I = this.getEl();
17452         var  J = this.getDragEl();
17453
17454         // Show the drag frame briefly so we can get its position
17455         J.style.visibility = "";
17456
17457         this.beforeMove();
17458         // Hide the linked element before the move to get around a Safari
17459         // rendering bug.
17460         I.style.visibility = "hidden";
17461         Roo.dd.DDM.moveToEl(I, J);
17462         J.style.visibility = "hidden";
17463         I.style.visibility = "";
17464
17465         this.afterDrag();
17466     },
17467
17468     beforeMove : function(){
17469
17470     },
17471
17472     afterDrag : function(){
17473
17474     },
17475
17476     toString: function() {
17477         return  ("DDProxy " + this.id);
17478     }
17479
17480 });
17481
17482 /*
17483  * Based on:
17484  * Ext JS Library 1.1.1
17485  * Copyright(c) 2006-2007, Ext JS, LLC.
17486  *
17487  * Originally Released Under LGPL - original licence link has changed is not relivant.
17488  *
17489  * Fork - LGPL
17490  * <script type="text/javascript">
17491  */
17492
17493  /**
17494  * @class Roo.dd.DDTarget
17495  * A DragDrop implementation that does not move, but can be a drop
17496  * target.  You would get the same result by simply omitting implementation
17497  * for the event callbacks, but this way we reduce the processing cost of the
17498  * event listener and the callbacks.
17499  * @extends Roo.dd.DragDrop
17500  * @constructor
17501  * @param {String} id the id of the element that is a drop target
17502  * @param {String} sGroup the group of related DragDrop objects
17503  * @param {object} config an object containing configurable attributes
17504  *                 Valid properties for DDTarget in addition to those in
17505  *                 DragDrop:
17506  *                    none
17507  */
17508 Roo.dd.DDTarget = function(id, A, B) {
17509     if (id) {
17510         this.initTarget(id, A, B);
17511     }
17512 };
17513
17514 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17515 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17516     toString: function() {
17517         return  ("DDTarget " + this.id);
17518     }
17519 });
17520
17521 /*
17522  * Based on:
17523  * Ext JS Library 1.1.1
17524  * Copyright(c) 2006-2007, Ext JS, LLC.
17525  *
17526  * Originally Released Under LGPL - original licence link has changed is not relivant.
17527  *
17528  * Fork - LGPL
17529  * <script type="text/javascript">
17530  */
17531  
17532
17533 /**
17534  * @class Roo.dd.ScrollManager
17535  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17536  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17537  * @singleton
17538  */
17539 Roo.dd.ScrollManager = function(){
17540     var  A = Roo.dd.DragDropMgr;
17541     var  B = {};
17542     var  C = null;
17543     var  D = {};
17544     
17545     var  E = function(e){
17546         C = null;
17547         H();
17548     };
17549     
17550     var  F = function(){
17551         if(A.dragCurrent){
17552              A.refreshCache(A.dragCurrent.groups);
17553         }
17554     };
17555     
17556     var  G = function(){
17557         if(A.dragCurrent){
17558             var  dds = Roo.dd.ScrollManager;
17559             if(!dds.animate){
17560                 if(D.el.scroll(D.dir, dds.increment)){
17561                     F();
17562                 }
17563             }else {
17564                 D.el.scroll(D.dir, dds.increment, true, dds.animDuration, F);
17565             }
17566         }
17567     };
17568     
17569     var  H = function(){
17570         if(D.id){
17571             clearInterval(D.id);
17572         }
17573
17574         D.id = 0;
17575         D.el = null;
17576         D.dir = "";
17577     };
17578     
17579     var  I = function(el, K){
17580         H();
17581         D.el = el;
17582         D.dir = K;
17583         D.id = setInterval(G, Roo.dd.ScrollManager.frequency);
17584     };
17585     
17586     var  J = function(e, K){
17587         if(K || !A.dragCurrent){ return; }
17588         var  L = Roo.dd.ScrollManager;
17589         if(!C || C != A.dragCurrent){
17590             C = A.dragCurrent;
17591             // refresh regions on drag start
17592             L.refreshCache();
17593         }
17594         
17595         var  xy = Roo.lib.Event.getXY(e);
17596         var  pt = new  Roo.lib.Point(xy[0], xy[1]);
17597         for(var  id  in  B){
17598             var  el = B[id], r = el._region;
17599             if(r && r.contains(pt) && el.isScrollable()){
17600                 if(r.bottom - pt.y <= L.thresh){
17601                     if(D.el != el){
17602                         I(el, "down");
17603                     }
17604                     return;
17605                 }else  if(r.right - pt.x <= L.thresh){
17606                     if(D.el != el){
17607                         I(el, "left");
17608                     }
17609                     return;
17610                 }else  if(pt.y - r.top <= L.thresh){
17611                     if(D.el != el){
17612                         I(el, "up");
17613                     }
17614                     return;
17615                 }else  if(pt.x - r.left <= L.thresh){
17616                     if(D.el != el){
17617                         I(el, "right");
17618                     }
17619                     return;
17620                 }
17621             }
17622         }
17623
17624         H();
17625     };
17626     
17627     A.fireEvents = A.fireEvents.createSequence(J, A);
17628     A.stopDrag = A.stopDrag.createSequence(E, A);
17629     
17630     return  {
17631         /**
17632          * Registers new overflow element(s) to auto scroll
17633          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17634          */
17635         register : function(el){
17636             if(el  instanceof  Array){
17637                 for(var  i = 0, len = el.length; i < len; i++) {
17638                         this.register(el[i]);
17639                 }
17640             }else {
17641                 el = Roo.get(el);
17642                 B[el.id] = el;
17643             }
17644         },
17645         
17646         /**
17647          * Unregisters overflow element(s) so they are no longer scrolled
17648          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17649          */
17650         unregister : function(el){
17651             if(el  instanceof  Array){
17652                 for(var  i = 0, len = el.length; i < len; i++) {
17653                         this.unregister(el[i]);
17654                 }
17655             }else {
17656                 el = Roo.get(el);
17657                 delete  B[el.id];
17658             }
17659         },
17660         
17661         /**
17662          * The number of pixels from the edge of a container the pointer needs to be to 
17663          * trigger scrolling (defaults to 25)
17664          * @type Number
17665          */
17666         thresh : 25,
17667         
17668         /**
17669          * The number of pixels to scroll in each scroll increment (defaults to 50)
17670          * @type Number
17671          */
17672         increment : 100,
17673         
17674         /**
17675          * The frequency of scrolls in milliseconds (defaults to 500)
17676          * @type Number
17677          */
17678         frequency : 500,
17679         
17680         /**
17681          * True to animate the scroll (defaults to true)
17682          * @type Boolean
17683          */
17684         animate: true,
17685         
17686         /**
17687          * The animation duration in seconds - 
17688          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17689          * @type Number
17690          */
17691         animDuration: .4,
17692         
17693         /**
17694          * Manually trigger a cache refresh.
17695          */
17696         refreshCache : function(){
17697             for(var  id  in  B){
17698                 if(typeof  B[id] == 'object'){ // for people extending the object prototype
17699                     B[id]._region = B[id].getRegion();
17700                 }
17701             }
17702         }
17703     };
17704 }();
17705 /*
17706  * Based on:
17707  * Ext JS Library 1.1.1
17708  * Copyright(c) 2006-2007, Ext JS, LLC.
17709  *
17710  * Originally Released Under LGPL - original licence link has changed is not relivant.
17711  *
17712  * Fork - LGPL
17713  * <script type="text/javascript">
17714  */
17715  
17716
17717 /**
17718  * @class Roo.dd.Registry
17719  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
17720  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17721  * @singleton
17722  */
17723 Roo.dd.Registry = function(){
17724     var  A = {}; 
17725     var  B = {}; 
17726     var  C = 0;
17727
17728     var  D = function(el, E){
17729         if(typeof  el == "string"){
17730             return  el;
17731         }
17732         var  id = el.id;
17733         if(!id && E !== false){
17734             id = "roodd-" + (++C);
17735             el.id = id;
17736         }
17737         return  id;
17738     };
17739     
17740     return  {
17741     /**
17742      * Register a drag drop element
17743      * @param {String|HTMLElement} element The id or DOM node to register
17744      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17745      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
17746      * knows how to interpret, plus there are some specific properties known to the Registry that should be
17747      * populated in the data object (if applicable):
17748      * <pre>
17749 Value      Description<br />
17750 ---------  ------------------------------------------<br />
17751 handles    Array of DOM nodes that trigger dragging<br />
17752            for the element being registered<br />
17753 isHandle   True if the element passed in triggers<br />
17754            dragging itself, else false
17755 </pre>
17756      */
17757         register : function(el, G){
17758             G = G || {};
17759             if(typeof  el == "string"){
17760                 el = document.getElementById(el);
17761             }
17762
17763             G.ddel = el;
17764             A[D(el)] = G;
17765             if(G.isHandle !== false){
17766                 B[G.ddel.id] = G;
17767             }
17768             if(G.handles){
17769                 var  hs = G.handles;
17770                 for(var  i = 0, len = hs.length; i < len; i++){
17771                         B[D(hs[i])] = G;
17772                 }
17773             }
17774         },
17775
17776     /**
17777      * Unregister a drag drop element
17778      * @param {String|HTMLElement}  element The id or DOM node to unregister
17779      */
17780         unregister : function(el){
17781             var  id = D(el, false);
17782             var  H = A[id];
17783             if(H){
17784                 delete  A[id];
17785                 if(H.handles){
17786                     var  hs = H.handles;
17787                     for(var  i = 0, len = hs.length; i < len; i++){
17788                         delete  B[D(hs[i], false)];
17789                     }
17790                 }
17791             }
17792         },
17793
17794     /**
17795      * Returns the handle registered for a DOM Node by id
17796      * @param {String|HTMLElement} id The DOM node or id to look up
17797      * @return {Object} handle The custom handle data
17798      */
17799         getHandle : function(id){
17800             if(typeof  id != "string"){ // must be element?
17801                 id = id.id;
17802             }
17803             return  B[id];
17804         },
17805
17806     /**
17807      * Returns the handle that is registered for the DOM node that is the target of the event
17808      * @param {Event} e The event
17809      * @return {Object} handle The custom handle data
17810      */
17811         getHandleFromEvent : function(e){
17812             var  t = Roo.lib.Event.getTarget(e);
17813             return  t ? B[t.id] : null;
17814         },
17815
17816     /**
17817      * Returns a custom data object that is registered for a DOM node by id
17818      * @param {String|HTMLElement} id The DOM node or id to look up
17819      * @return {Object} data The custom data
17820      */
17821         getTarget : function(id){
17822             if(typeof  id != "string"){ // must be element?
17823                 id = id.id;
17824             }
17825             return  A[id];
17826         },
17827
17828     /**
17829      * Returns a custom data object that is registered for the DOM node that is the target of the event
17830      * @param {Event} e The event
17831      * @return {Object} data The custom data
17832      */
17833         getTargetFromEvent : function(e){
17834             var  t = Roo.lib.Event.getTarget(e);
17835             return  t ? A[t.id] || B[t.id] : null;
17836         }
17837     };
17838 }();
17839 /*
17840  * Based on:
17841  * Ext JS Library 1.1.1
17842  * Copyright(c) 2006-2007, Ext JS, LLC.
17843  *
17844  * Originally Released Under LGPL - original licence link has changed is not relivant.
17845  *
17846  * Fork - LGPL
17847  * <script type="text/javascript">
17848  */
17849  
17850
17851 /**
17852  * @class Roo.dd.StatusProxy
17853  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
17854  * default drag proxy used by all Roo.dd components.
17855  * @constructor
17856  * @param {Object} config
17857  */
17858 Roo.dd.StatusProxy = function(A){
17859     Roo.apply(this, A);
17860     this.id = this.id || Roo.id();
17861     this.el = new  Roo.Layer({
17862         dh: {
17863             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17864                 {tag: "div", cls: "x-dd-drop-icon"},
17865                 {tag: "div", cls: "x-dd-drag-ghost"}
17866             ]
17867         }, 
17868         shadow: !A || A.shadow !== false
17869     });
17870     this.ghost = Roo.get(this.el.dom.childNodes[1]);
17871     this.dropStatus = this.dropNotAllowed;
17872 };
17873
17874 Roo.dd.StatusProxy.prototype = {
17875     /**
17876      * @cfg {String} dropAllowed
17877      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17878      */
17879     dropAllowed : "x-dd-drop-ok",
17880     /**
17881      * @cfg {String} dropNotAllowed
17882      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17883      */
17884     dropNotAllowed : "x-dd-drop-nodrop",
17885
17886     /**
17887      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17888      * over the current target element.
17889      * @param {String} cssClass The css class for the new drop status indicator image
17890      */
17891     setStatus : function(B){
17892         B = B || this.dropNotAllowed;
17893         if(this.dropStatus != B){
17894             this.el.replaceClass(this.dropStatus, B);
17895             this.dropStatus = B;
17896         }
17897     },
17898
17899     /**
17900      * Resets the status indicator to the default dropNotAllowed value
17901      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17902      */
17903     reset : function(C){
17904         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17905         this.dropStatus = this.dropNotAllowed;
17906         if(C){
17907             this.ghost.update("");
17908         }
17909     },
17910
17911     /**
17912      * Updates the contents of the ghost element
17913      * @param {String} html The html that will replace the current innerHTML of the ghost element
17914      */
17915     update : function(D){
17916         if(typeof  D == "string"){
17917             this.ghost.update(D);
17918         }else {
17919             this.ghost.update("");
17920             D.style.margin = "0";
17921             this.ghost.dom.appendChild(D);
17922         }
17923         // ensure float = none set?? cant remember why though.
17924         var  el = this.ghost.dom.firstChild;
17925                 if(el){
17926                         Roo.fly(el).setStyle('float', 'none');
17927                 }
17928     },
17929     
17930     /**
17931      * Returns the underlying proxy {@link Roo.Layer}
17932      * @return {Roo.Layer} el
17933     */
17934     getEl : function(){
17935         return  this.el;
17936     },
17937
17938     /**
17939      * Returns the ghost element
17940      * @return {Roo.Element} el
17941      */
17942     getGhost : function(){
17943         return  this.ghost;
17944     },
17945
17946     /**
17947      * Hides the proxy
17948      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17949      */
17950     hide : function(E){
17951         this.el.hide();
17952         if(E){
17953             this.reset(true);
17954         }
17955     },
17956
17957     /**
17958      * Stops the repair animation if it's currently running
17959      */
17960     stop : function(){
17961         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17962             this.anim.stop();
17963         }
17964     },
17965
17966     /**
17967      * Displays this proxy
17968      */
17969     show : function(){
17970         this.el.show();
17971     },
17972
17973     /**
17974      * Force the Layer to sync its shadow and shim positions to the element
17975      */
17976     sync : function(){
17977         this.el.sync();
17978     },
17979
17980     /**
17981      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
17982      * invalid drop operation by the item being dragged.
17983      * @param {Array} xy The XY position of the element ([x, y])
17984      * @param {Function} callback The function to call after the repair is complete
17985      * @param {Object} scope The scope in which to execute the callback
17986      */
17987     repair : function(xy, F, G){
17988         this.callback = F;
17989         this.scope = G;
17990         if(xy && this.animRepair !== false){
17991             this.el.addClass("x-dd-drag-repair");
17992             this.el.hideUnders(true);
17993             this.anim = this.el.shift({
17994                 duration: this.repairDuration || .5,
17995                 easing: 'easeOut',
17996                 xy: xy,
17997                 stopFx: true,
17998                 callback: this.afterRepair,
17999                 scope: this
18000             });
18001         }else {
18002             this.afterRepair();
18003         }
18004     },
18005
18006     // private
18007     afterRepair : function(){
18008         this.hide(true);
18009         if(typeof  this.callback == "function"){
18010             this.callback.call(this.scope || this);
18011         }
18012
18013         this.callback = null;
18014         this.scope = null;
18015     }
18016 };
18017 /*
18018  * Based on:
18019  * Ext JS Library 1.1.1
18020  * Copyright(c) 2006-2007, Ext JS, LLC.
18021  *
18022  * Originally Released Under LGPL - original licence link has changed is not relivant.
18023  *
18024  * Fork - LGPL
18025  * <script type="text/javascript">
18026  */
18027
18028 /**
18029  * @class Roo.dd.DragSource
18030  * @extends Roo.dd.DDProxy
18031  * A simple class that provides the basic implementation needed to make any element draggable.
18032  * @constructor
18033  * @param {String/HTMLElement/Element} el The container element
18034  * @param {Object} config
18035  */
18036 Roo.dd.DragSource = function(el, A){
18037     this.el = Roo.get(el);
18038     this.dragData = {};
18039     
18040     Roo.apply(this, A);
18041     
18042     if(!this.proxy){
18043         this.proxy = new  Roo.dd.StatusProxy();
18044     }
18045
18046
18047     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18048           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18049     
18050     this.dragging = false;
18051 };
18052
18053 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18054     /**
18055      * @cfg {String} dropAllowed
18056      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18057      */
18058     dropAllowed : "x-dd-drop-ok",
18059     /**
18060      * @cfg {String} dropNotAllowed
18061      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18062      */
18063     dropNotAllowed : "x-dd-drop-nodrop",
18064
18065     /**
18066      * Returns the data object associated with this drag source
18067      * @return {Object} data An object containing arbitrary data
18068      */
18069     getDragData : function(e){
18070         return  this.dragData;
18071     },
18072
18073     // private
18074     onDragEnter : function(e, id){
18075         var  B = Roo.dd.DragDropMgr.getDDById(id);
18076         this.cachedTarget = B;
18077         if(this.beforeDragEnter(B, e, id) !== false){
18078             if(B.isNotifyTarget){
18079                 var  status = B.notifyEnter(this, e, this.dragData);
18080                 this.proxy.setStatus(status);
18081             }else {
18082                 this.proxy.setStatus(this.dropAllowed);
18083             }
18084             
18085             if(this.afterDragEnter){
18086                 /**
18087                  * An empty function by default, but provided so that you can perform a custom action
18088                  * when the dragged item enters the drop target by providing an implementation.
18089                  * @param {Roo.dd.DragDrop} target The drop target
18090                  * @param {Event} e The event object
18091                  * @param {String} id The id of the dragged element
18092                  * @method afterDragEnter
18093                  */
18094                 this.afterDragEnter(B, e, id);
18095             }
18096         }
18097     },
18098
18099     /**
18100      * An empty function by default, but provided so that you can perform a custom action
18101      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18102      * @param {Roo.dd.DragDrop} target The drop target
18103      * @param {Event} e The event object
18104      * @param {String} id The id of the dragged element
18105      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18106      */
18107     beforeDragEnter : function(C, e, id){
18108         return  true;
18109     },
18110
18111     // private
18112     alignElWithMouse: function() {
18113         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18114         this.proxy.sync();
18115     },
18116
18117     // private
18118     onDragOver : function(e, id){
18119         var  D = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18120         if(this.beforeDragOver(D, e, id) !== false){
18121             if(D.isNotifyTarget){
18122                 var  status = D.notifyOver(this, e, this.dragData);
18123                 this.proxy.setStatus(status);
18124             }
18125
18126             if(this.afterDragOver){
18127                 /**
18128                  * An empty function by default, but provided so that you can perform a custom action
18129                  * while the dragged item is over the drop target by providing an implementation.
18130                  * @param {Roo.dd.DragDrop} target The drop target
18131                  * @param {Event} e The event object
18132                  * @param {String} id The id of the dragged element
18133                  * @method afterDragOver
18134                  */
18135                 this.afterDragOver(D, e, id);
18136             }
18137         }
18138     },
18139
18140     /**
18141      * An empty function by default, but provided so that you can perform a custom action
18142      * while the dragged item is over the drop target and optionally cancel the onDragOver.
18143      * @param {Roo.dd.DragDrop} target The drop target
18144      * @param {Event} e The event object
18145      * @param {String} id The id of the dragged element
18146      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18147      */
18148     beforeDragOver : function(E, e, id){
18149         return  true;
18150     },
18151
18152     // private
18153     onDragOut : function(e, id){
18154         var  F = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18155         if(this.beforeDragOut(F, e, id) !== false){
18156             if(F.isNotifyTarget){
18157                 F.notifyOut(this, e, this.dragData);
18158             }
18159
18160             this.proxy.reset();
18161             if(this.afterDragOut){
18162                 /**
18163                  * An empty function by default, but provided so that you can perform a custom action
18164                  * after the dragged item is dragged out of the target without dropping.
18165                  * @param {Roo.dd.DragDrop} target The drop target
18166                  * @param {Event} e The event object
18167                  * @param {String} id The id of the dragged element
18168                  * @method afterDragOut
18169                  */
18170                 this.afterDragOut(F, e, id);
18171             }
18172         }
18173
18174         this.cachedTarget = null;
18175     },
18176
18177     /**
18178      * An empty function by default, but provided so that you can perform a custom action before the dragged
18179      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18180      * @param {Roo.dd.DragDrop} target The drop target
18181      * @param {Event} e The event object
18182      * @param {String} id The id of the dragged element
18183      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18184      */
18185     beforeDragOut : function(G, e, id){
18186         return  true;
18187     },
18188     
18189     // private
18190     onDragDrop : function(e, id){
18191         var  H = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18192         if(this.beforeDragDrop(H, e, id) !== false){
18193             if(H.isNotifyTarget){
18194                 if(H.notifyDrop(this, e, this.dragData)){ // valid drop?
18195                     this.onValidDrop(H, e, id);
18196                 }else {
18197                     this.onInvalidDrop(H, e, id);
18198                 }
18199             }else {
18200                 this.onValidDrop(H, e, id);
18201             }
18202             
18203             if(this.afterDragDrop){
18204                 /**
18205                  * An empty function by default, but provided so that you can perform a custom action
18206                  * after a valid drag drop has occurred by providing an implementation.
18207                  * @param {Roo.dd.DragDrop} target The drop target
18208                  * @param {Event} e The event object
18209                  * @param {String} id The id of the dropped element
18210                  * @method afterDragDrop
18211                  */
18212                 this.afterDragDrop(H, e, id);
18213             }
18214         }
18215         delete  this.cachedTarget;
18216     },
18217
18218     /**
18219      * An empty function by default, but provided so that you can perform a custom action before the dragged
18220      * item is dropped onto the target and optionally cancel the onDragDrop.
18221      * @param {Roo.dd.DragDrop} target The drop target
18222      * @param {Event} e The event object
18223      * @param {String} id The id of the dragged element
18224      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18225      */
18226     beforeDragDrop : function(I, e, id){
18227         return  true;
18228     },
18229
18230     // private
18231     onValidDrop : function(J, e, id){
18232         this.hideProxy();
18233         if(this.afterValidDrop){
18234             /**
18235              * An empty function by default, but provided so that you can perform a custom action
18236              * after a valid drop has occurred by providing an implementation.
18237              * @param {Object} target The target DD 
18238              * @param {Event} e The event object
18239              * @param {String} id The id of the dropped element
18240              * @method afterInvalidDrop
18241              */
18242             this.afterValidDrop(J, e, id);
18243         }
18244     },
18245
18246     // private
18247     getRepairXY : function(e, K){
18248         return  this.el.getXY();  
18249     },
18250
18251     // private
18252     onInvalidDrop : function(L, e, id){
18253         this.beforeInvalidDrop(L, e, id);
18254         if(this.cachedTarget){
18255             if(this.cachedTarget.isNotifyTarget){
18256                 this.cachedTarget.notifyOut(this, e, this.dragData);
18257             }
18258
18259             this.cacheTarget = null;
18260         }
18261
18262         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18263
18264         if(this.afterInvalidDrop){
18265             /**
18266              * An empty function by default, but provided so that you can perform a custom action
18267              * after an invalid drop has occurred by providing an implementation.
18268              * @param {Event} e The event object
18269              * @param {String} id The id of the dropped element
18270              * @method afterInvalidDrop
18271              */
18272             this.afterInvalidDrop(e, id);
18273         }
18274     },
18275
18276     // private
18277     afterRepair : function(){
18278         if(Roo.enableFx){
18279             this.el.highlight(this.hlColor || "c3daf9");
18280         }
18281
18282         this.dragging = false;
18283     },
18284
18285     /**
18286      * An empty function by default, but provided so that you can perform a custom action after an invalid
18287      * drop has occurred.
18288      * @param {Roo.dd.DragDrop} target The drop target
18289      * @param {Event} e The event object
18290      * @param {String} id The id of the dragged element
18291      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18292      */
18293     beforeInvalidDrop : function(M, e, id){
18294         return  true;
18295     },
18296
18297     // private
18298     handleMouseDown : function(e){
18299         if(this.dragging) {
18300             return;
18301         }
18302         var  N = this.getDragData(e);
18303         if(N && this.onBeforeDrag(N, e) !== false){
18304             this.dragData = N;
18305             this.proxy.stop();
18306             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18307         } 
18308     },
18309
18310     /**
18311      * An empty function by default, but provided so that you can perform a custom action before the initial
18312      * drag event begins and optionally cancel it.
18313      * @param {Object} data An object containing arbitrary data to be shared with drop targets
18314      * @param {Event} e The event object
18315      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18316      */
18317     onBeforeDrag : function(O, e){
18318         return  true;
18319     },
18320
18321     /**
18322      * An empty function by default, but provided so that you can perform a custom action once the initial
18323      * drag event has begun.  The drag cannot be canceled from this function.
18324      * @param {Number} x The x position of the click on the dragged object
18325      * @param {Number} y The y position of the click on the dragged object
18326      */
18327     onStartDrag : Roo.emptyFn,
18328
18329     // private - YUI override
18330     startDrag : function(x, y){
18331         this.proxy.reset();
18332         this.dragging = true;
18333         this.proxy.update("");
18334         this.onInitDrag(x, y);
18335         this.proxy.show();
18336     },
18337
18338     // private
18339     onInitDrag : function(x, y){
18340         var  P = this.el.dom.cloneNode(true);
18341         P.id = Roo.id(); // prevent duplicate ids
18342         this.proxy.update(P);
18343         this.onStartDrag(x, y);
18344         return  true;
18345     },
18346
18347     /**
18348      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18349      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18350      */
18351     getProxy : function(){
18352         return  this.proxy;  
18353     },
18354
18355     /**
18356      * Hides the drag source's {@link Roo.dd.StatusProxy}
18357      */
18358     hideProxy : function(){
18359         this.proxy.hide();  
18360         this.proxy.reset(true);
18361         this.dragging = false;
18362     },
18363
18364     // private
18365     triggerCacheRefresh : function(){
18366         Roo.dd.DDM.refreshCache(this.groups);
18367     },
18368
18369     // private - override to prevent hiding
18370     b4EndDrag: function(e) {
18371     },
18372
18373     // private - override to prevent moving
18374     endDrag : function(e){
18375         this.onEndDrag(this.dragData, e);
18376     },
18377
18378     // private
18379     onEndDrag : function(Q, e){
18380     },
18381     
18382     // private - pin to cursor
18383     autoOffset : function(x, y) {
18384         this.setDelta(-12, -20);
18385     }    
18386 });
18387 /*
18388  * Based on:
18389  * Ext JS Library 1.1.1
18390  * Copyright(c) 2006-2007, Ext JS, LLC.
18391  *
18392  * Originally Released Under LGPL - original licence link has changed is not relivant.
18393  *
18394  * Fork - LGPL
18395  * <script type="text/javascript">
18396  */
18397
18398
18399 /**
18400  * @class Roo.dd.DropTarget
18401  * @extends Roo.dd.DDTarget
18402  * A simple class that provides the basic implementation needed to make any element a drop target that can have
18403  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
18404  * @constructor
18405  * @param {String/HTMLElement/Element} el The container element
18406  * @param {Object} config
18407  */
18408 Roo.dd.DropTarget = function(el, A){
18409     this.el = Roo.get(el);
18410     
18411     Roo.apply(this, A);
18412     
18413     if(this.containerScroll){
18414         Roo.dd.ScrollManager.register(this.el);
18415     }
18416
18417     
18418     Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, 
18419           {isTarget: true});
18420
18421 };
18422
18423 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18424     /**
18425      * @cfg {String} overClass
18426      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18427      */
18428     /**
18429      * @cfg {String} dropAllowed
18430      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18431      */
18432     dropAllowed : "x-dd-drop-ok",
18433     /**
18434      * @cfg {String} dropNotAllowed
18435      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18436      */
18437     dropNotAllowed : "x-dd-drop-nodrop",
18438
18439     // private
18440     isTarget : true,
18441
18442     // private
18443     isNotifyTarget : true,
18444
18445     /**
18446      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18447      * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
18448      * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
18449      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18450      * @param {Event} e The event
18451      * @param {Object} data An object containing arbitrary data supplied by the drag source
18452      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18453      * underlying {@link Roo.dd.StatusProxy} can be updated
18454      */
18455     notifyEnter : function(dd, e, B){
18456         if(this.overClass){
18457             this.el.addClass(this.overClass);
18458         }
18459         return  this.dropAllowed;
18460     },
18461
18462     /**
18463      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18464      * This method will be called on every mouse movement while the drag source is over the drop target.
18465      * This default implementation simply returns the dropAllowed config value.
18466      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18467      * @param {Event} e The event
18468      * @param {Object} data An object containing arbitrary data supplied by the drag source
18469      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18470      * underlying {@link Roo.dd.StatusProxy} can be updated
18471      */
18472     notifyOver : function(dd, e, C){
18473         return  this.dropAllowed;
18474     },
18475
18476     /**
18477      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18478      * out of the target without dropping.  This default implementation simply removes the CSS class specified by
18479      * overClass (if any) from the drop element.
18480      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18481      * @param {Event} e The event
18482      * @param {Object} data An object containing arbitrary data supplied by the drag source
18483      */
18484     notifyOut : function(dd, e, D){
18485         if(this.overClass){
18486             this.el.removeClass(this.overClass);
18487         }
18488     },
18489
18490     /**
18491      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18492      * been dropped on it.  This method has no default implementation and returns false, so you must provide an
18493      * implementation that does something to process the drop event and returns true so that the drag source's
18494      * repair action does not run.
18495      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18496      * @param {Event} e The event
18497      * @param {Object} data An object containing arbitrary data supplied by the drag source
18498      * @return {Boolean} True if the drop was valid, else false
18499      */
18500     notifyDrop : function(dd, e, E){
18501         return  false;
18502     }
18503 });
18504 /*
18505  * Based on:
18506  * Ext JS Library 1.1.1
18507  * Copyright(c) 2006-2007, Ext JS, LLC.
18508  *
18509  * Originally Released Under LGPL - original licence link has changed is not relivant.
18510  *
18511  * Fork - LGPL
18512  * <script type="text/javascript">
18513  */
18514
18515
18516 /**
18517  * @class Roo.dd.DragZone
18518  * @extends Roo.dd.DragSource
18519  * This class provides a container DD instance that proxies for multiple child node sources.<br />
18520  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18521  * @constructor
18522  * @param {String/HTMLElement/Element} el The container element
18523  * @param {Object} config
18524  */
18525 Roo.dd.DragZone = function(el, A){
18526     Roo.dd.DragZone.superclass.constructor.call(this, el, A);
18527     if(this.containerScroll){
18528         Roo.dd.ScrollManager.register(this.el);
18529     }
18530 };
18531
18532 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18533     /**
18534      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18535      * for auto scrolling during drag operations.
18536      */
18537     /**
18538      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18539      * method after a failed drop (defaults to "c3daf9" - light blue)
18540      */
18541
18542     /**
18543      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18544      * for a valid target to drag based on the mouse down. Override this method
18545      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18546      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18547      * @param {EventObject} e The mouse down event
18548      * @return {Object} The dragData
18549      */
18550     getDragData : function(e){
18551         return  Roo.dd.Registry.getHandleFromEvent(e);
18552     },
18553     
18554     /**
18555      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18556      * this.dragData.ddel
18557      * @param {Number} x The x position of the click on the dragged object
18558      * @param {Number} y The y position of the click on the dragged object
18559      * @return {Boolean} true to continue the drag, false to cancel
18560      */
18561     onInitDrag : function(x, y){
18562         this.proxy.update(this.dragData.ddel.cloneNode(true));
18563         this.onStartDrag(x, y);
18564         return  true;
18565     },
18566     
18567     /**
18568      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
18569      */
18570     afterRepair : function(){
18571         if(Roo.enableFx){
18572             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18573         }
18574
18575         this.dragging = false;
18576     },
18577
18578     /**
18579      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18580      * the XY of this.dragData.ddel
18581      * @param {EventObject} e The mouse up event
18582      * @return {Array} The xy location (e.g. [100, 200])
18583      */
18584     getRepairXY : function(e){
18585         return  Roo.Element.fly(this.dragData.ddel).getXY();  
18586     }
18587 });
18588 /*
18589  * Based on:
18590  * Ext JS Library 1.1.1
18591  * Copyright(c) 2006-2007, Ext JS, LLC.
18592  *
18593  * Originally Released Under LGPL - original licence link has changed is not relivant.
18594  *
18595  * Fork - LGPL
18596  * <script type="text/javascript">
18597  */
18598 /**
18599  * @class Roo.dd.DropZone
18600  * @extends Roo.dd.DropTarget
18601  * This class provides a container DD instance that proxies for multiple child node targets.<br />
18602  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18603  * @constructor
18604  * @param {String/HTMLElement/Element} el The container element
18605  * @param {Object} config
18606  */
18607 Roo.dd.DropZone = function(el, A){
18608     Roo.dd.DropZone.superclass.constructor.call(this, el, A);
18609 };
18610
18611 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18612     /**
18613      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
18614      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18615      * provide your own custom lookup.
18616      * @param {Event} e The event
18617      * @return {Object} data The custom data
18618      */
18619     getTargetFromEvent : function(e){
18620         return  Roo.dd.Registry.getTargetFromEvent(e);
18621     },
18622
18623     /**
18624      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18625      * that it has registered.  This method has no default implementation and should be overridden to provide
18626      * node-specific processing if necessary.
18627      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
18628      * {@link #getTargetFromEvent} for this node)
18629      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18630      * @param {Event} e The event
18631      * @param {Object} data An object containing arbitrary data supplied by the drag source
18632      */
18633     onNodeEnter : function(n, dd, e, B){
18634         
18635     },
18636
18637     /**
18638      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18639      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
18640      * overridden to provide the proper feedback.
18641      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18642      * {@link #getTargetFromEvent} for this node)
18643      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18644      * @param {Event} e The event
18645      * @param {Object} data An object containing arbitrary data supplied by the drag source
18646      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18647      * underlying {@link Roo.dd.StatusProxy} can be updated
18648      */
18649     onNodeOver : function(n, dd, e, C){
18650         return  this.dropAllowed;
18651     },
18652
18653     /**
18654      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18655      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
18656      * node-specific processing if necessary.
18657      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18658      * {@link #getTargetFromEvent} for this node)
18659      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18660      * @param {Event} e The event
18661      * @param {Object} data An object containing arbitrary data supplied by the drag source
18662      */
18663     onNodeOut : function(n, dd, e, D){
18664         
18665     },
18666
18667     /**
18668      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18669      * the drop node.  The default implementation returns false, so it should be overridden to provide the
18670      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18671      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18672      * {@link #getTargetFromEvent} for this node)
18673      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18674      * @param {Event} e The event
18675      * @param {Object} data An object containing arbitrary data supplied by the drag source
18676      * @return {Boolean} True if the drop was valid, else false
18677      */
18678     onNodeDrop : function(n, dd, e, E){
18679         return  false;
18680     },
18681
18682     /**
18683      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18684      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
18685      * it should be overridden to provide the proper feedback if necessary.
18686      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18687      * @param {Event} e The event
18688      * @param {Object} data An object containing arbitrary data supplied by the drag source
18689      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18690      * underlying {@link Roo.dd.StatusProxy} can be updated
18691      */
18692     onContainerOver : function(dd, e, F){
18693         return  this.dropNotAllowed;
18694     },
18695
18696     /**
18697      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18698      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
18699      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18700      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
18701      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18702      * @param {Event} e The event
18703      * @param {Object} data An object containing arbitrary data supplied by the drag source
18704      * @return {Boolean} True if the drop was valid, else false
18705      */
18706     onContainerDrop : function(dd, e, G){
18707         return  false;
18708     },
18709
18710     /**
18711      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18712      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
18713      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18714      * you should override this method and provide a custom implementation.
18715      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18716      * @param {Event} e The event
18717      * @param {Object} data An object containing arbitrary data supplied by the drag source
18718      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18719      * underlying {@link Roo.dd.StatusProxy} can be updated
18720      */
18721     notifyEnter : function(dd, e, H){
18722         return  this.dropNotAllowed;
18723     },
18724
18725     /**
18726      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18727      * This method will be called on every mouse movement while the drag source is over the drop zone.
18728      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18729      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18730      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18731      * registered node, it will call {@link #onContainerOver}.
18732      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18733      * @param {Event} e The event
18734      * @param {Object} data An object containing arbitrary data supplied by the drag source
18735      * @return {String} status The CSS class that communicates the drop status back to the source so that the
18736      * underlying {@link Roo.dd.StatusProxy} can be updated
18737      */
18738     notifyOver : function(dd, e, I){
18739         var  n = this.getTargetFromEvent(e);
18740         if(!n){ // not over valid drop target
18741             if(this.lastOverNode){
18742                 this.onNodeOut(this.lastOverNode, dd, e, I);
18743                 this.lastOverNode = null;
18744             }
18745             return  this.onContainerOver(dd, e, I);
18746         }
18747         if(this.lastOverNode != n){
18748             if(this.lastOverNode){
18749                 this.onNodeOut(this.lastOverNode, dd, e, I);
18750             }
18751
18752             this.onNodeEnter(n, dd, e, I);
18753             this.lastOverNode = n;
18754         }
18755         return  this.onNodeOver(n, dd, e, I);
18756     },
18757
18758     /**
18759      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18760      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
18761      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18762      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18763      * @param {Event} e The event
18764      * @param {Object} data An object containing arbitrary data supplied by the drag zone
18765      */
18766     notifyOut : function(dd, e, J){
18767         if(this.lastOverNode){
18768             this.onNodeOut(this.lastOverNode, dd, e, J);
18769             this.lastOverNode = null;
18770         }
18771     },
18772
18773     /**
18774      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18775      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
18776      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18777      * otherwise it will call {@link #onContainerDrop}.
18778      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18779      * @param {Event} e The event
18780      * @param {Object} data An object containing arbitrary data supplied by the drag source
18781      * @return {Boolean} True if the drop was valid, else false
18782      */
18783     notifyDrop : function(dd, e, K){
18784         if(this.lastOverNode){
18785             this.onNodeOut(this.lastOverNode, dd, e, K);
18786             this.lastOverNode = null;
18787         }
18788         var  n = this.getTargetFromEvent(e);
18789         return  n ?
18790             this.onNodeDrop(n, dd, e, K) :
18791             this.onContainerDrop(dd, e, K);
18792     },
18793
18794     // private
18795     triggerCacheRefresh : function(){
18796         Roo.dd.DDM.refreshCache(this.groups);
18797     }  
18798 });
18799 /*
18800  * Based on:
18801  * Ext JS Library 1.1.1
18802  * Copyright(c) 2006-2007, Ext JS, LLC.
18803  *
18804  * Originally Released Under LGPL - original licence link has changed is not relivant.
18805  *
18806  * Fork - LGPL
18807  * <script type="text/javascript">
18808  */
18809
18810
18811 /**
18812  * @class Roo.data.SortTypes
18813  * @singleton
18814  * Defines the default sorting (casting?) comparison functions used when sorting data.
18815  */
18816 Roo.data.SortTypes = {
18817     /**
18818      * Default sort that does nothing
18819      * @param {Mixed} s The value being converted
18820      * @return {Mixed} The comparison value
18821      */
18822     none : function(s){
18823         return  s;
18824     },
18825     
18826     /**
18827      * The regular expression used to strip tags
18828      * @type {RegExp}
18829      * @property
18830      */
18831     stripTagsRE : /<\/?[^>]+>/gi,
18832     
18833     /**
18834      * Strips all HTML tags to sort on text only
18835      * @param {Mixed} s The value being converted
18836      * @return {String} The comparison value
18837      */
18838     asText : function(s){
18839         return  String(s).replace(this.stripTagsRE, "");
18840     },
18841     
18842     /**
18843      * Strips all HTML tags to sort on text only - Case insensitive
18844      * @param {Mixed} s The value being converted
18845      * @return {String} The comparison value
18846      */
18847     asUCText : function(s){
18848         return  String(s).toUpperCase().replace(this.stripTagsRE, "");
18849     },
18850     
18851     /**
18852      * Case insensitive string
18853      * @param {Mixed} s The value being converted
18854      * @return {String} The comparison value
18855      */
18856     asUCString : function(s) {
18857         return  String(s).toUpperCase();
18858     },
18859     
18860     /**
18861      * Date sorting
18862      * @param {Mixed} s The value being converted
18863      * @return {Number} The comparison value
18864      */
18865     asDate : function(s) {
18866         if(!s){
18867             return  0;
18868         }
18869         if(s  instanceof  Date){
18870             return  s.getTime();
18871         }
18872         return  Date.parse(String(s));
18873     },
18874     
18875     /**
18876      * Float sorting
18877      * @param {Mixed} s The value being converted
18878      * @return {Float} The comparison value
18879      */
18880     asFloat : function(s) {
18881         var  A = parseFloat(String(s).replace(/,/g, ""));
18882         if(isNaN(A)) A = 0;
18883         return  A;
18884     },
18885     
18886     /**
18887      * Integer sorting
18888      * @param {Mixed} s The value being converted
18889      * @return {Number} The comparison value
18890      */
18891     asInt : function(s) {
18892         var  B = parseInt(String(s).replace(/,/g, ""));
18893         if(isNaN(B)) B = 0;
18894         return  B;
18895     }
18896 };
18897 /*
18898  * Based on:
18899  * Ext JS Library 1.1.1
18900  * Copyright(c) 2006-2007, Ext JS, LLC.
18901  *
18902  * Originally Released Under LGPL - original licence link has changed is not relivant.
18903  *
18904  * Fork - LGPL
18905  * <script type="text/javascript">
18906  */
18907
18908 /**
18909 * @class Roo.data.Record
18910  * Instances of this class encapsulate both record <em>definition</em> information, and record
18911  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18912  * to access Records cached in an {@link Roo.data.Store} object.<br>
18913  * <p>
18914  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18915  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18916  * objects.<br>
18917  * <p>
18918  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18919  * @constructor
18920  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18921  * {@link #create}. The parameters are the same.
18922  * @param {Array} data An associative Array of data values keyed by the field name.
18923  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18924  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18925  * not specified an integer id is generated.
18926  */
18927 Roo.data.Record = function(A, id){
18928     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18929     this.data = A;
18930 };
18931
18932 /**
18933  * Generate a constructor for a specific record layout.
18934  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18935  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18936  * Each field definition object may contain the following properties: <ul>
18937  * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18938  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18939  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18940  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18941  * is being used, then this is a string containing the javascript expression to reference the data relative to 
18942  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18943  * to the data item relative to the record element. If the mapping expression is the same as the field name,
18944  * this may be omitted.</p></li>
18945  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18946  * <ul><li>auto (Default, implies no conversion)</li>
18947  * <li>string</li>
18948  * <li>int</li>
18949  * <li>float</li>
18950  * <li>boolean</li>
18951  * <li>date</li></ul></p></li>
18952  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18953  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18954  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18955  * by the Reader into an object that will be stored in the Record. It is passed the
18956  * following parameters:<ul>
18957  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18958  * </ul></p></li>
18959  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18960  * </ul>
18961  * <br>usage:<br><pre><code>
18962 var TopicRecord = Roo.data.Record.create(
18963     {name: 'title', mapping: 'topic_title'},
18964     {name: 'author', mapping: 'username'},
18965     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18966     {name: 'lastPost', mapping: 'post_time', type: 'date'},
18967     {name: 'lastPoster', mapping: 'user2'},
18968     {name: 'excerpt', mapping: 'post_text'}
18969 );
18970
18971 var myNewRecord = new TopicRecord({
18972     title: 'Do my job please',
18973     author: 'noobie',
18974     totalPosts: 1,
18975     lastPost: new Date(),
18976     lastPoster: 'Animal',
18977     excerpt: 'No way dude!'
18978 });
18979 myStore.add(myNewRecord);
18980 </code></pre>
18981  * @method create
18982  * @static
18983  */
18984 Roo.data.Record.create = function(o){
18985     var  f = function(){
18986         f.superclass.constructor.apply(this, arguments);
18987     };
18988     Roo.extend(f, Roo.data.Record);
18989     var  p = f.prototype;
18990     p.fields = new  Roo.util.MixedCollection(false, function(B){
18991         return  B.name;
18992     });
18993     for(var  i = 0, len = o.length; i < len; i++){
18994         p.fields.add(new  Roo.data.Field(o[i]));
18995     }
18996
18997     f.getField = function(B){
18998         return  p.fields.get(B);  
18999     };
19000     return  f;
19001 };
19002
19003 Roo.data.Record.AUTO_ID = 1000;
19004 Roo.data.Record.EDIT = 'edit';
19005 Roo.data.Record.REJECT = 'reject';
19006 Roo.data.Record.COMMIT = 'commit';
19007
19008 Roo.data.Record.prototype = {
19009     /**
19010      * Readonly flag - true if this record has been modified.
19011      * @type Boolean
19012      */
19013     dirty : false,
19014     editing : false,
19015     error: null,
19016     modified: null,
19017
19018     // private
19019     join : function(B){
19020         this.store = B;
19021     },
19022
19023     /**
19024      * Set the named field to the specified value.
19025      * @param {String} name The name of the field to set.
19026      * @param {Object} value The value to set the field to.
19027      */
19028     set : function(C, D){
19029         if(this.data[C] == D){
19030             return;
19031         }
19032
19033         this.dirty = true;
19034         if(!this.modified){
19035             this.modified = {};
19036         }
19037         if(typeof  this.modified[C] == 'undefined'){
19038             this.modified[C] = this.data[C];
19039         }
19040
19041         this.data[C] = D;
19042         if(!this.editing){
19043             this.store.afterEdit(this);
19044         }       
19045     },
19046
19047     /**
19048      * Get the value of the named field.
19049      * @param {String} name The name of the field to get the value of.
19050      * @return {Object} The value of the field.
19051      */
19052     get : function(E){
19053         return  this.data[E]; 
19054     },
19055
19056     // private
19057     beginEdit : function(){
19058         this.editing = true;
19059         this.modified = {}; 
19060     },
19061
19062     // private
19063     cancelEdit : function(){
19064         this.editing = false;
19065         delete  this.modified;
19066     },
19067
19068     // private
19069     endEdit : function(){
19070         this.editing = false;
19071         if(this.dirty && this.store){
19072             this.store.afterEdit(this);
19073         }
19074     },
19075
19076     /**
19077      * Usually called by the {@link Roo.data.Store} which owns the Record.
19078      * Rejects all changes made to the Record since either creation, or the last commit operation.
19079      * Modified fields are reverted to their original values.
19080      * <p>
19081      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19082      * of reject operations.
19083      */
19084     reject : function(){
19085         var  m = this.modified;
19086         for(var  n  in  m){
19087             if(typeof  m[n] != "function"){
19088                 this.data[n] = m[n];
19089             }
19090         }
19091
19092         this.dirty = false;
19093         delete  this.modified;
19094         this.editing = false;
19095         if(this.store){
19096             this.store.afterReject(this);
19097         }
19098     },
19099
19100     /**
19101      * Usually called by the {@link Roo.data.Store} which owns the Record.
19102      * Commits all changes made to the Record since either creation, or the last commit operation.
19103      * <p>
19104      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19105      * of commit operations.
19106      */
19107     commit : function(){
19108         this.dirty = false;
19109         delete  this.modified;
19110         this.editing = false;
19111         if(this.store){
19112             this.store.afterCommit(this);
19113         }
19114     },
19115
19116     // private
19117     hasError : function(){
19118         return  this.error != null;
19119     },
19120
19121     // private
19122     clearError : function(){
19123         this.error = null;
19124     },
19125
19126     /**
19127      * Creates a copy of this record.
19128      * @param {String} id (optional) A new record id if you don't want to use this record's id
19129      * @return {Record}
19130      */
19131     copy : function(F) {
19132         return  new  this.constructor(Roo.apply({}, this.data), F || this.id);
19133     }
19134 };
19135 /*
19136  * Based on:
19137  * Ext JS Library 1.1.1
19138  * Copyright(c) 2006-2007, Ext JS, LLC.
19139  *
19140  * Originally Released Under LGPL - original licence link has changed is not relivant.
19141  *
19142  * Fork - LGPL
19143  * <script type="text/javascript">
19144  */
19145
19146
19147
19148 /**
19149  * @class Roo.data.Store
19150  * @extends Roo.util.Observable
19151  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19152  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19153  * <p>
19154  * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
19155  * has no knowledge of the format of the data returned by the Proxy.<br>
19156  * <p>
19157  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19158  * instances from the data object. These records are cached and made available through accessor functions.
19159  * @constructor
19160  * Creates a new Store.
19161  * @param {Object} config A config object containing the objects needed for the Store to access data,
19162  * and read the data into Records.
19163  */
19164 Roo.data.Store = function(A){
19165     this.data = new  Roo.util.MixedCollection(false);
19166     this.data.getKey = function(o){
19167         return  o.id;
19168     };
19169     this.baseParams = {};
19170     // private
19171     this.paramNames = {
19172         "start" : "start",
19173         "limit" : "limit",
19174         "sort" : "sort",
19175         "dir" : "dir"
19176     };
19177
19178     if(A && A.data){
19179         this.inlineData = A.data;
19180         delete  A.data;
19181     }
19182
19183
19184     Roo.apply(this, A);
19185     
19186     if(this.reader){ // reader passed
19187         this.reader = Roo.factory(this.reader, Roo.data);
19188         this.reader.xmodule = this.xmodule || false;
19189         if(!this.recordType){
19190             this.recordType = this.reader.recordType;
19191         }
19192         if(this.reader.onMetaChange){
19193             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19194         }
19195     }
19196
19197     if(this.recordType){
19198         this.fields = this.recordType.prototype.fields;
19199     }
19200
19201     this.modified = [];
19202
19203     this.addEvents({
19204         /**
19205          * @event datachanged
19206          * Fires when the data cache has changed, and a widget which is using this Store
19207          * as a Record cache should refresh its view.
19208          * @param {Store} this
19209          */
19210         datachanged : true,
19211         /**
19212          * @event metachange
19213          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19214          * @param {Store} this
19215          * @param {Object} meta The JSON metadata
19216          */
19217         metachange : true,
19218         /**
19219          * @event add
19220          * Fires when Records have been added to the Store
19221          * @param {Store} this
19222          * @param {Roo.data.Record[]} records The array of Records added
19223          * @param {Number} index The index at which the record(s) were added
19224          */
19225         add : true,
19226         /**
19227          * @event remove
19228          * Fires when a Record has been removed from the Store
19229          * @param {Store} this
19230          * @param {Roo.data.Record} record The Record that was removed
19231          * @param {Number} index The index at which the record was removed
19232          */
19233         remove : true,
19234         /**
19235          * @event update
19236          * Fires when a Record has been updated
19237          * @param {Store} this
19238          * @param {Roo.data.Record} record The Record that was updated
19239          * @param {String} operation The update operation being performed.  Value may be one of:
19240          * <pre><code>
19241  Roo.data.Record.EDIT
19242  Roo.data.Record.REJECT
19243  Roo.data.Record.COMMIT
19244          * </code></pre>
19245          */
19246         update : true,
19247         /**
19248          * @event clear
19249          * Fires when the data cache has been cleared.
19250          * @param {Store} this
19251          */
19252         clear : true,
19253         /**
19254          * @event beforeload
19255          * Fires before a request is made for a new data object.  If the beforeload handler returns false
19256          * the load action will be canceled.
19257          * @param {Store} this
19258          * @param {Object} options The loading options that were specified (see {@link #load} for details)
19259          */
19260         beforeload : true,
19261         /**
19262          * @event load
19263          * Fires after a new set of Records has been loaded.
19264          * @param {Store} this
19265          * @param {Roo.data.Record[]} records The Records that were loaded
19266          * @param {Object} options The loading options that were specified (see {@link #load} for details)
19267          */
19268         load : true,
19269         /**
19270          * @event loadexception
19271          * Fires if an exception occurs in the Proxy during loading.
19272          * Called with the signature of the Proxy's "loadexception" event.
19273          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19274          * 
19275          * @param {Proxy} 
19276          * @param {Object} return from JsonData.reader() - success, totalRecords, records
19277          * @param {Object} load options 
19278          * @param {Object} jsonData from your request (normally this contains the Exception)
19279          */
19280         loadexception : true
19281     });
19282     
19283     if(this.proxy){
19284         this.proxy = Roo.factory(this.proxy, Roo.data);
19285         this.proxy.xmodule = this.xmodule || false;
19286         this.relayEvents(this.proxy,  ["loadexception"]);
19287     }
19288
19289     this.sortToggle = {};
19290
19291     Roo.data.Store.superclass.constructor.call(this);
19292
19293     if(this.inlineData){
19294         this.loadData(this.inlineData);
19295         delete  this.inlineData;
19296     }
19297 };
19298 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19299      /**
19300     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
19301     * without a remote query - used by combo/forms at present.
19302     */
19303     
19304     /**
19305     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19306     */
19307     /**
19308     * @cfg {Array} data Inline data to be loaded when the store is initialized.
19309     */
19310     /**
19311     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19312     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19313     */
19314     /**
19315     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19316     * on any HTTP request
19317     */
19318     /**
19319     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19320     */
19321     /**
19322     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19323     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19324     */
19325     remoteSort : false,
19326
19327     /**
19328     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19329      * loaded or when a record is removed. (defaults to false).
19330     */
19331     pruneModifiedRecords : false,
19332
19333     // private
19334     lastOptions : null,
19335
19336     /**
19337      * Add Records to the Store and fires the add event.
19338      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19339      */
19340     add : function(B){
19341         B = [].concat(B);
19342         for(var  i = 0, len = B.length; i < len; i++){
19343             B[i].join(this);
19344         }
19345         var  C = this.data.length;
19346         this.data.addAll(B);
19347         this.fireEvent("add", this, B, C);
19348     },
19349
19350     /**
19351      * Remove a Record from the Store and fires the remove event.
19352      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19353      */
19354     remove : function(D){
19355         var  E = this.data.indexOf(D);
19356         this.data.removeAt(E);
19357         if(this.pruneModifiedRecords){
19358             this.modified.remove(D);
19359         }
19360
19361         this.fireEvent("remove", this, D, E);
19362     },
19363
19364     /**
19365      * Remove all Records from the Store and fires the clear event.
19366      */
19367     removeAll : function(){
19368         this.data.clear();
19369         if(this.pruneModifiedRecords){
19370             this.modified = [];
19371         }
19372
19373         this.fireEvent("clear", this);
19374     },
19375
19376     /**
19377      * Inserts Records to the Store at the given index and fires the add event.
19378      * @param {Number} index The start index at which to insert the passed Records.
19379      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19380      */
19381     insert : function(F, G){
19382         G = [].concat(G);
19383         for(var  i = 0, len = G.length; i < len; i++){
19384             this.data.insert(F, G[i]);
19385             G[i].join(this);
19386         }
19387
19388         this.fireEvent("add", this, G, F);
19389     },
19390
19391     /**
19392      * Get the index within the cache of the passed Record.
19393      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19394      * @return {Number} The index of the passed Record. Returns -1 if not found.
19395      */
19396     indexOf : function(H){
19397         return  this.data.indexOf(H);
19398     },
19399
19400     /**
19401      * Get the index within the cache of the Record with the passed id.
19402      * @param {String} id The id of the Record to find.
19403      * @return {Number} The index of the Record. Returns -1 if not found.
19404      */
19405     indexOfId : function(id){
19406         return  this.data.indexOfKey(id);
19407     },
19408
19409     /**
19410      * Get the Record with the specified id.
19411      * @param {String} id The id of the Record to find.
19412      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19413      */
19414     getById : function(id){
19415         return  this.data.key(id);
19416     },
19417
19418     /**
19419      * Get the Record at the specified index.
19420      * @param {Number} index The index of the Record to find.
19421      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19422      */
19423     getAt : function(I){
19424         return  this.data.itemAt(I);
19425     },
19426
19427     /**
19428      * Returns a range of Records between specified indices.
19429      * @param {Number} startIndex (optional) The starting index (defaults to 0)
19430      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19431      * @return {Roo.data.Record[]} An array of Records
19432      */
19433     getRange : function(J, K){
19434         return  this.data.getRange(J, K);
19435     },
19436
19437     // private
19438     storeOptions : function(o){
19439         o = Roo.apply({}, o);
19440         delete  o.callback;
19441         delete  o.scope;
19442         this.lastOptions = o;
19443     },
19444
19445     /**
19446      * Loads the Record cache from the configured Proxy using the configured Reader.
19447      * <p>
19448      * If using remote paging, then the first load call must specify the <em>start</em>
19449      * and <em>limit</em> properties in the options.params property to establish the initial
19450      * position within the dataset, and the number of Records to cache on each read from the Proxy.
19451      * <p>
19452      * <strong>It is important to note that for remote data sources, loading is asynchronous,
19453      * and this call will return before the new data has been loaded. Perform any post-processing
19454      * in a callback function, or in a "load" event handler.</strong>
19455      * <p>
19456      * @param {Object} options An object containing properties which control loading options:<ul>
19457      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19458      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19459      * passed the following arguments:<ul>
19460      * <li>r : Roo.data.Record[]</li>
19461      * <li>options: Options object from the load call</li>
19462      * <li>success: Boolean success indicator</li></ul></li>
19463      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19464      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19465      * </ul>
19466      */
19467     load : function(L){
19468         L = L || {};
19469         if(this.fireEvent("beforeload", this, L) !== false){
19470             this.storeOptions(L);
19471             var  p = Roo.apply(L.params || {}, this.baseParams);
19472             if(this.sortInfo && this.remoteSort){
19473                 var  pn = this.paramNames;
19474                 p[pn["sort"]] = this.sortInfo.field;
19475                 p[pn["dir"]] = this.sortInfo.direction;
19476             }
19477
19478             this.proxy.load(p, this.reader, this.loadRecords, this, L);
19479         }
19480     },
19481
19482     /**
19483      * Reloads the Record cache from the configured Proxy using the configured Reader and
19484      * the options from the last load operation performed.
19485      * @param {Object} options (optional) An object containing properties which may override the options
19486      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19487      * the most recently used options are reused).
19488      */
19489     reload : function(M){
19490         this.load(Roo.applyIf(M||{}, this.lastOptions));
19491     },
19492
19493     // private
19494     // Called as a callback by the Reader during a load operation.
19495     loadRecords : function(o, N, O){
19496         if(!o || O === false){
19497             if(O !== false){
19498                 this.fireEvent("load", this, [], N);
19499             }
19500             if(N.callback){
19501                 N.callback.call(N.scope || this, [], N, false);
19502             }
19503             return;
19504         }
19505         // if data returned failure - throw an exception.
19506         if (o.success === false) {
19507             this.fireEvent("loadexception", this, o, N, this.reader.jsonData);
19508             return;
19509         }
19510         var  r = o.records, t = o.totalRecords || r.length;
19511         if(!N || N.add !== true){
19512             if(this.pruneModifiedRecords){
19513                 this.modified = [];
19514             }
19515             for(var  i = 0, len = r.length; i < len; i++){
19516                 r[i].join(this);
19517             }
19518             if(this.snapshot){
19519                 this.data = this.snapshot;
19520                 delete  this.snapshot;
19521             }
19522
19523             this.data.clear();
19524             this.data.addAll(r);
19525             this.totalLength = t;
19526             this.applySort();
19527             this.fireEvent("datachanged", this);
19528         }else {
19529             this.totalLength = Math.max(t, this.data.length+r.length);
19530             this.add(r);
19531         }
19532
19533         this.fireEvent("load", this, r, N);
19534         if(N.callback){
19535             N.callback.call(N.scope || this, r, N, true);
19536         }
19537     },
19538
19539     /**
19540      * Loads data from a passed data block. A Reader which understands the format of the data
19541      * must have been configured in the constructor.
19542      * @param {Object} data The data block from which to read the Records.  The format of the data expected
19543      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19544      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19545      */
19546     loadData : function(o, P){
19547         var  r = this.reader.readRecords(o);
19548         this.loadRecords(r, {add: P}, true);
19549     },
19550
19551     /**
19552      * Gets the number of cached records.
19553      * <p>
19554      * <em>If using paging, this may not be the total size of the dataset. If the data object
19555      * used by the Reader contains the dataset size, then the getTotalCount() function returns
19556      * the data set size</em>
19557      */
19558     getCount : function(){
19559         return  this.data.length || 0;
19560     },
19561
19562     /**
19563      * Gets the total number of records in the dataset as returned by the server.
19564      * <p>
19565      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19566      * the dataset size</em>
19567      */
19568     getTotalCount : function(){
19569         return  this.totalLength || 0;
19570     },
19571
19572     /**
19573      * Returns the sort state of the Store as an object with two properties:
19574      * <pre><code>
19575  field {String} The name of the field by which the Records are sorted
19576  direction {String} The sort order, "ASC" or "DESC"
19577      * </code></pre>
19578      */
19579     getSortState : function(){
19580         return  this.sortInfo;
19581     },
19582
19583     // private
19584     applySort : function(){
19585         if(this.sortInfo && !this.remoteSort){
19586             var  s = this.sortInfo, f = s.field;
19587             var  st = this.fields.get(f).sortType;
19588             var  fn = function(r1, r2){
19589                 var  v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19590                 return  v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19591             };
19592             this.data.sort(s.direction, fn);
19593             if(this.snapshot && this.snapshot != this.data){
19594                 this.snapshot.sort(s.direction, fn);
19595             }
19596         }
19597     },
19598
19599     /**
19600      * Sets the default sort column and order to be used by the next load operation.
19601      * @param {String} fieldName The name of the field to sort by.
19602      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19603      */
19604     setDefaultSort : function(Q, R){
19605         this.sortInfo = {field: Q, direction: R ? R.toUpperCase() : "ASC"};
19606     },
19607
19608     /**
19609      * Sort the Records.
19610      * If remote sorting is used, the sort is performed on the server, and the cache is
19611      * reloaded. If local sorting is used, the cache is sorted internally.
19612      * @param {String} fieldName The name of the field to sort by.
19613      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19614      */
19615     sort : function(S, T){
19616         var  f = this.fields.get(S);
19617         if(!T){
19618             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19619                 T = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19620             }else {
19621                 T = f.sortDir;
19622             }
19623         }
19624
19625         this.sortToggle[f.name] = T;
19626         this.sortInfo = {field: f.name, direction: T};
19627         if(!this.remoteSort){
19628             this.applySort();
19629             this.fireEvent("datachanged", this);
19630         }else {
19631             this.load(this.lastOptions);
19632         }
19633     },
19634
19635     /**
19636      * Calls the specified function for each of the Records in the cache.
19637      * @param {Function} fn The function to call. The Record is passed as the first parameter.
19638      * Returning <em>false</em> aborts and exits the iteration.
19639      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19640      */
19641     each : function(fn, U){
19642         this.data.each(fn, U);
19643     },
19644
19645     /**
19646      * Gets all records modified since the last commit.  Modified records are persisted across load operations
19647      * (e.g., during paging).
19648      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19649      */
19650     getModifiedRecords : function(){
19651         return  this.modified;
19652     },
19653
19654     // private
19655     createFilterFn : function(V, W, X){
19656         if(!W.exec){ // not a regex
19657             W = String(W);
19658             if(W.length == 0){
19659                 return  false;
19660             }
19661
19662             W = new  RegExp((X === true ? '' : '^') + Roo.escapeRe(W), "i");
19663         }
19664         return  function(r){
19665             return  W.test(r.data[V]);
19666         };
19667     },
19668
19669     /**
19670      * Sums the value of <i>property</i> for each record between start and end and returns the result.
19671      * @param {String} property A field on your records
19672      * @param {Number} start The record index to start at (defaults to 0)
19673      * @param {Number} end The last record index to include (defaults to length - 1)
19674      * @return {Number} The sum
19675      */
19676     sum : function(Y, Z, a){
19677         var  rs = this.data.items, v = 0;
19678         Z = Z || 0;
19679         a = (a || a === 0) ? a : rs.length-1;
19680
19681         for(var  i = Z; i <= a; i++){
19682             v += (rs[i].data[Y] || 0);
19683         }
19684         return  v;
19685     },
19686
19687     /**
19688      * Filter the records by a specified property.
19689      * @param {String} field A field on your records
19690      * @param {String/RegExp} value Either a string that the field
19691      * should start with or a RegExp to test against the field
19692      * @param {Boolean} anyMatch True to match any part not just the beginning
19693      */
19694     filter : function(b, c, d){
19695         var  fn = this.createFilterFn(b, c, d);
19696         return  fn ? this.filterBy(fn) : this.clearFilter();
19697     },
19698
19699     /**
19700      * Filter by a function. The specified function will be called with each
19701      * record in this data source. If the function returns true the record is included,
19702      * otherwise it is filtered.
19703      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19704      * @param {Object} scope (optional) The scope of the function (defaults to this)
19705      */
19706     filterBy : function(fn, e){
19707         this.snapshot = this.snapshot || this.data;
19708         this.data = this.queryBy(fn, e||this);
19709         this.fireEvent("datachanged", this);
19710     },
19711
19712     /**
19713      * Query the records by a specified property.
19714      * @param {String} field A field on your records
19715      * @param {String/RegExp} value Either a string that the field
19716      * should start with or a RegExp to test against the field
19717      * @param {Boolean} anyMatch True to match any part not just the beginning
19718      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19719      */
19720     query : function(g, h, j){
19721         var  fn = this.createFilterFn(g, h, j);
19722         return  fn ? this.queryBy(fn) : this.data.clone();
19723     },
19724
19725     /**
19726      * Query by a function. The specified function will be called with each
19727      * record in this data source. If the function returns true the record is included
19728      * in the results.
19729      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19730      * @param {Object} scope (optional) The scope of the function (defaults to this)
19731       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19732      **/
19733     queryBy : function(fn, k){
19734         var  l = this.snapshot || this.data;
19735         return  l.filterBy(fn, k||this);
19736     },
19737
19738     /**
19739      * Collects unique values for a particular dataIndex from this store.
19740      * @param {String} dataIndex The property to collect
19741      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19742      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19743      * @return {Array} An array of the unique values
19744      **/
19745     collect : function(m, n, q){
19746         var  d = (q === true && this.snapshot) ?
19747                 this.snapshot.items : this.data.items;
19748         var  v, sv, r = [], l = {};
19749         for(var  i = 0, len = d.length; i < len; i++){
19750             v = d[i].data[m];
19751             sv = String(v);
19752             if((n || !Roo.isEmpty(v)) && !l[sv]){
19753                 l[sv] = true;
19754                 r[r.length] = v;
19755             }
19756         }
19757         return  r;
19758     },
19759
19760     /**
19761      * Revert to a view of the Record cache with no filtering applied.
19762      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19763      */
19764     clearFilter : function(u){
19765         if(this.snapshot && this.snapshot != this.data){
19766             this.data = this.snapshot;
19767             delete  this.snapshot;
19768             if(u !== true){
19769                 this.fireEvent("datachanged", this);
19770             }
19771         }
19772     },
19773
19774     // private
19775     afterEdit : function(w){
19776         if(this.modified.indexOf(w) == -1){
19777             this.modified.push(w);
19778         }
19779
19780         this.fireEvent("update", this, w, Roo.data.Record.EDIT);
19781     },
19782
19783     // private
19784     afterReject : function(x){
19785         this.modified.remove(x);
19786         this.fireEvent("update", this, x, Roo.data.Record.REJECT);
19787     },
19788
19789     // private
19790     afterCommit : function(y){
19791         this.modified.remove(y);
19792         this.fireEvent("update", this, y, Roo.data.Record.COMMIT);
19793     },
19794
19795     /**
19796      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19797      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19798      */
19799     commitChanges : function(){
19800         var  m = this.modified.slice(0);
19801         this.modified = [];
19802         for(var  i = 0, len = m.length; i < len; i++){
19803             m[i].commit();
19804         }
19805     },
19806
19807     /**
19808      * Cancel outstanding changes on all changed records.
19809      */
19810     rejectChanges : function(){
19811         var  m = this.modified.slice(0);
19812         this.modified = [];
19813         for(var  i = 0, len = m.length; i < len; i++){
19814             m[i].reject();
19815         }
19816     },
19817
19818     onMetaChange : function(z, AA, o){
19819         this.recordType = AA;
19820         this.fields = AA.prototype.fields;
19821         delete  this.snapshot;
19822         this.sortInfo = z.sortInfo;
19823         this.modified = [];
19824         this.fireEvent('metachange', this, this.reader.meta);
19825     }
19826 });
19827 /*
19828  * Based on:
19829  * Ext JS Library 1.1.1
19830  * Copyright(c) 2006-2007, Ext JS, LLC.
19831  *
19832  * Originally Released Under LGPL - original licence link has changed is not relivant.
19833  *
19834  * Fork - LGPL
19835  * <script type="text/javascript">
19836  */
19837
19838 /**
19839  * @class Roo.data.SimpleStore
19840  * @extends Roo.data.Store
19841  * Small helper class to make creating Stores from Array data easier.
19842  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19843  * @cfg {Array} fields An array of field definition objects, or field name strings.
19844  * @cfg {Array} data The multi-dimensional array of data
19845  * @constructor
19846  * @param {Object} config
19847  */
19848 Roo.data.SimpleStore = function(A){
19849     Roo.data.SimpleStore.superclass.constructor.call(this, {
19850         isLocal : true,
19851         reader: new  Roo.data.ArrayReader({
19852                 id: A.id
19853             },
19854             Roo.data.Record.create(A.fields)
19855         ),
19856         proxy : new  Roo.data.MemoryProxy(A.data)
19857     });
19858     this.load();
19859 };
19860 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);
19861 /*
19862  * Based on:
19863  * Ext JS Library 1.1.1
19864  * Copyright(c) 2006-2007, Ext JS, LLC.
19865  *
19866  * Originally Released Under LGPL - original licence link has changed is not relivant.
19867  *
19868  * Fork - LGPL
19869  * <script type="text/javascript">
19870  */
19871
19872 /**
19873 /**
19874  * @extends Roo.data.Store
19875  * @class Roo.data.JsonStore
19876  * Small helper class to make creating Stores for JSON data easier. <br/>
19877 <pre><code>
19878 var store = new Roo.data.JsonStore({
19879     url: 'get-images.php',
19880     root: 'images',
19881     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19882 });
19883 </code></pre>
19884  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19885  * JsonReader and HttpProxy (unless inline data is provided).</b>
19886  * @cfg {Array} fields An array of field definition objects, or field name strings.
19887  * @constructor
19888  * @param {Object} config
19889  */
19890 Roo.data.JsonStore = function(c){
19891     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19892         proxy: !c.data ? new  Roo.data.HttpProxy({url: c.url}) : undefined,
19893         reader: new  Roo.data.JsonReader(c, c.fields)
19894     }));
19895 };
19896 Roo.extend(Roo.data.JsonStore, Roo.data.Store);
19897 /*
19898  * Based on:
19899  * Ext JS Library 1.1.1
19900  * Copyright(c) 2006-2007, Ext JS, LLC.
19901  *
19902  * Originally Released Under LGPL - original licence link has changed is not relivant.
19903  *
19904  * Fork - LGPL
19905  * <script type="text/javascript">
19906  */
19907
19908  
19909 Roo.data.Field = function(A){
19910     if(typeof  A == "string"){
19911         A = {name: A};
19912     }
19913
19914     Roo.apply(this, A);
19915     
19916     if(!this.type){
19917         this.type = "auto";
19918     }
19919     
19920     var  st = Roo.data.SortTypes;
19921     // named sortTypes are supported, here we look them up
19922     if(typeof  this.sortType == "string"){
19923         this.sortType = st[this.sortType];
19924     }
19925     
19926     // set default sortType for strings and dates
19927     if(!this.sortType){
19928         switch(this.type){
19929             case  "string":
19930                 this.sortType = st.asUCString;
19931                 break;
19932             case  "date":
19933                 this.sortType = st.asDate;
19934                 break;
19935             default:
19936                 this.sortType = st.none;
19937         }
19938     }
19939
19940     // define once
19941     var  B = /[\$,%]/g;
19942
19943     // prebuilt conversion function for this field, instead of
19944     // switching every time we're reading a value
19945     if(!this.convert){
19946         var  cv, dateFormat = this.dateFormat;
19947         switch(this.type){
19948             case  "":
19949             case  "auto":
19950             case  undefined:
19951                 cv = function(v){ return  v; };
19952                 break;
19953             case  "string":
19954                 cv = function(v){ return  (v === undefined || v === null) ? '' : String(v); };
19955                 break;
19956             case  "int":
19957                 cv = function(v){
19958                     return  v !== undefined && v !== null && v !== '' ?
19959                            parseInt(String(v).replace(B, ""), 10) : '';
19960                     };
19961                 break;
19962             case  "float":
19963                 cv = function(v){
19964                     return  v !== undefined && v !== null && v !== '' ?
19965                            parseFloat(String(v).replace(B, ""), 10) : ''; 
19966                     };
19967                 break;
19968             case  "bool":
19969             case  "boolean":
19970                 cv = function(v){ return  v === true || v === "true" || v == 1; };
19971                 break;
19972             case  "date":
19973                 cv = function(v){
19974                     if(!v){
19975                         return  '';
19976                     }
19977                     if(v  instanceof  Date){
19978                         return  v;
19979                     }
19980                     if(dateFormat){
19981                         if(dateFormat == "timestamp"){
19982                             return  new  Date(v*1000);
19983                         }
19984                         return  Date.parseDate(v, dateFormat);
19985                     }
19986                     var  C = Date.parse(v);
19987                     return  C ? new  Date(C) : null;
19988                 };
19989              break;
19990             
19991         }
19992
19993         this.convert = cv;
19994     }
19995 };
19996
19997 Roo.data.Field.prototype = {
19998     dateFormat: null,
19999     defaultValue: "",
20000     mapping: null,
20001     sortType : null,
20002     sortDir : "ASC"
20003 };
20004 /*
20005  * Based on:
20006  * Ext JS Library 1.1.1
20007  * Copyright(c) 2006-2007, Ext JS, LLC.
20008  *
20009  * Originally Released Under LGPL - original licence link has changed is not relivant.
20010  *
20011  * Fork - LGPL
20012  * <script type="text/javascript">
20013  */
20014  
20015 // Base class for reading structured data from a data source.  This class is intended to be
20016 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20017
20018 /**
20019  * @class Roo.data.DataReader
20020  * Base class for reading structured data from a data source.  This class is intended to be
20021  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20022  */
20023
20024 Roo.data.DataReader = function(A, B){
20025     
20026     this.meta = A;
20027     
20028     this.recordType = B  instanceof  Array ? 
20029         Roo.data.Record.create(B) : B;
20030 };
20031
20032 Roo.data.DataReader.prototype = {
20033      /**
20034      * Create an empty record
20035      * @param {Object} data (optional) - overlay some values
20036      * @return {Roo.data.Record} record created.
20037      */
20038     newRow :  function(d) {
20039         var  da =  {};
20040         this.recordType.prototype.fields.each(function(c) {
20041             switch( c.type) {
20042                 case  'int' : da[c.name] = 0; break;
20043                 case  'date' : da[c.name] = new  Date(); break;
20044                 case  'float' : da[c.name] = 0.0; break;
20045                 case  'boolean' : da[c.name] = false; break;
20046                 default : da[c.name] = ""; break;
20047             }
20048             
20049         });
20050         return  new  this.recordType(Roo.apply(da, d));
20051     }
20052     
20053 };
20054 /*
20055  * Based on:
20056  * Ext JS Library 1.1.1
20057  * Copyright(c) 2006-2007, Ext JS, LLC.
20058  *
20059  * Originally Released Under LGPL - original licence link has changed is not relivant.
20060  *
20061  * Fork - LGPL
20062  * <script type="text/javascript">
20063  */
20064
20065 /**
20066  * @class Roo.data.DataProxy
20067  * @extends Roo.data.Observable
20068  * This class is an abstract base class for implementations which provide retrieval of
20069  * unformatted data objects.<br>
20070  * <p>
20071  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20072  * (of the appropriate type which knows how to parse the data object) to provide a block of
20073  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20074  * <p>
20075  * Custom implementations must implement the load method as described in
20076  * {@link Roo.data.HttpProxy#load}.
20077  */
20078 Roo.data.DataProxy = function(){
20079     this.addEvents({
20080         /**
20081          * @event beforeload
20082          * Fires before a network request is made to retrieve a data object.
20083          * @param {Object} This DataProxy object.
20084          * @param {Object} params The params parameter to the load function.
20085          */
20086         beforeload : true,
20087         /**
20088          * @event load
20089          * Fires before the load method's callback is called.
20090          * @param {Object} This DataProxy object.
20091          * @param {Object} o The data object.
20092          * @param {Object} arg The callback argument object passed to the load function.
20093          */
20094         load : true,
20095         /**
20096          * @event loadexception
20097          * Fires if an Exception occurs during data retrieval.
20098          * @param {Object} This DataProxy object.
20099          * @param {Object} o The data object.
20100          * @param {Object} arg The callback argument object passed to the load function.
20101          * @param {Object} e The Exception.
20102          */
20103         loadexception : true
20104     });
20105     Roo.data.DataProxy.superclass.constructor.call(this);
20106 };
20107
20108 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20109
20110     /**
20111      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20112      */
20113
20114 /*
20115  * Based on:
20116  * Ext JS Library 1.1.1
20117  * Copyright(c) 2006-2007, Ext JS, LLC.
20118  *
20119  * Originally Released Under LGPL - original licence link has changed is not relivant.
20120  *
20121  * Fork - LGPL
20122  * <script type="text/javascript">
20123  */
20124 /**
20125  * @class Roo.data.MemoryProxy
20126  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20127  * to the Reader when its load method is called.
20128  * @constructor
20129  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20130  */
20131 Roo.data.MemoryProxy = function(A){
20132     if (A.data) {
20133         A = A.data;
20134     }
20135
20136     Roo.data.MemoryProxy.superclass.constructor.call(this);
20137     this.data = A;
20138 };
20139
20140 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20141     /**
20142      * Load data from the requested source (in this case an in-memory
20143      * data object passed to the constructor), read the data object into
20144      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20145      * process that block using the passed callback.
20146      * @param {Object} params This parameter is not used by the MemoryProxy class.
20147      * @param {Roo.data.DataReader} reader The Reader object which converts the data
20148      * object into a block of Roo.data.Records.
20149      * @param {Function} callback The function into which to pass the block of Roo.data.records.
20150      * The function must be passed <ul>
20151      * <li>The Record block object</li>
20152      * <li>The "arg" argument from the load function</li>
20153      * <li>A boolean success indicator</li>
20154      * </ul>
20155      * @param {Object} scope The scope in which to call the callback
20156      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20157      */
20158     load : function(B, C, D, E, F){
20159         B = B || {};
20160         var  G;
20161         try {
20162             G = C.readRecords(this.data);
20163         }catch(e){
20164             this.fireEvent("loadexception", this, arg, null, e);
20165             callback.call(scope, null, arg, false);
20166             return;
20167         }
20168
20169         D.call(E, G, F, true);
20170     },
20171     
20172     // private
20173     update : function(H, I){
20174         
20175     }
20176 });
20177 /*
20178  * Based on:
20179  * Ext JS Library 1.1.1
20180  * Copyright(c) 2006-2007, Ext JS, LLC.
20181  *
20182  * Originally Released Under LGPL - original licence link has changed is not relivant.
20183  *
20184  * Fork - LGPL
20185  * <script type="text/javascript">
20186  */
20187 /**
20188  * @class Roo.data.HttpProxy
20189  * @extends Roo.data.DataProxy
20190  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20191  * configured to reference a certain URL.<br><br>
20192  * <p>
20193  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20194  * from which the running page was served.<br><br>
20195  * <p>
20196  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20197  * <p>
20198  * Be aware that to enable the browser to parse an XML document, the server must set
20199  * the Content-Type header in the HTTP response to "text/xml".
20200  * @constructor
20201  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20202  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
20203  * will be used to make the request.
20204  */
20205 Roo.data.HttpProxy = function(A){
20206     Roo.data.HttpProxy.superclass.constructor.call(this);
20207     // is conn a conn config or a real conn?
20208     this.conn = A;
20209     this.useAjax = !A || !A.events;
20210   
20211 };
20212
20213 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20214     // thse are take from connection...
20215     
20216     /**
20217      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20218      */
20219     /**
20220      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20221      * extra parameters to each request made by this object. (defaults to undefined)
20222      */
20223     /**
20224      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20225      *  to each request made by this object. (defaults to undefined)
20226      */
20227     /**
20228      * @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)
20229      */
20230     /**
20231      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20232      */
20233      /**
20234      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20235      * @type Boolean
20236      */
20237   
20238
20239     /**
20240      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20241      * @type Boolean
20242      */
20243     /**
20244      * Return the {@link Roo.data.Connection} object being used by this Proxy.
20245      * @return {Connection} The Connection object. This object may be used to subscribe to events on
20246      * a finer-grained basis than the DataProxy events.
20247      */
20248     getConnection : function(){
20249         return  this.useAjax ? Roo.Ajax : this.conn;
20250     },
20251
20252     /**
20253      * Load data from the configured {@link Roo.data.Connection}, read the data object into
20254      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20255      * process that block using the passed callback.
20256      * @param {Object} params An object containing properties which are to be used as HTTP parameters
20257      * for the request to the remote server.
20258      * @param {Roo.data.DataReader} reader The Reader object which converts the data
20259      * object into a block of Roo.data.Records.
20260      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20261      * The function must be passed <ul>
20262      * <li>The Record block object</li>
20263      * <li>The "arg" argument from the load function</li>
20264      * <li>A boolean success indicator</li>
20265      * </ul>
20266      * @param {Object} scope The scope in which to call the callback
20267      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20268      */
20269     load : function(B, C, D, E, F){
20270         if(this.fireEvent("beforeload", this, B) !== false){
20271             var   o = {
20272                 params : B || {},
20273                 request: {
20274                     callback : D,
20275                     scope : E,
20276                     arg : F
20277                 },
20278                 reader: C,
20279                 callback : this.loadResponse,
20280                 scope: this
20281             };
20282             if(this.useAjax){
20283                 Roo.applyIf(o, this.conn);
20284                 if(this.activeRequest){
20285                     Roo.Ajax.abort(this.activeRequest);
20286                 }
20287
20288                 this.activeRequest = Roo.Ajax.request(o);
20289             }else {
20290                 this.conn.request(o);
20291             }
20292         }else {
20293             D.call(E||this, null, F, false);
20294         }
20295     },
20296
20297     // private
20298     loadResponse : function(o, G, H){
20299         delete  this.activeRequest;
20300         if(!G){
20301             this.fireEvent("loadexception", this, o, H);
20302             o.request.callback.call(o.request.scope, null, o.request.arg, false);
20303             return;
20304         }
20305         var  I;
20306         try {
20307             I = o.reader.read(H);
20308         }catch(e){
20309             this.fireEvent("loadexception", this, o, response, e);
20310             o.request.callback.call(o.request.scope, null, o.request.arg, false);
20311             return;
20312         }
20313
20314         
20315         this.fireEvent("load", this, o, o.request.arg);
20316         o.request.callback.call(o.request.scope, I, o.request.arg, true);
20317     },
20318
20319     // private
20320     update : function(J){
20321
20322     },
20323
20324     // private
20325     updateResponse : function(K){
20326
20327     }
20328 });
20329 /*
20330  * Based on:
20331  * Ext JS Library 1.1.1
20332  * Copyright(c) 2006-2007, Ext JS, LLC.
20333  *
20334  * Originally Released Under LGPL - original licence link has changed is not relivant.
20335  *
20336  * Fork - LGPL
20337  * <script type="text/javascript">
20338  */
20339
20340 /**
20341  * @class Roo.data.ScriptTagProxy
20342  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20343  * other than the originating domain of the running page.<br><br>
20344  * <p>
20345  * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
20346  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20347  * <p>
20348  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20349  * source code that is used as the source inside a &lt;script> tag.<br><br>
20350  * <p>
20351  * In order for the browser to process the returned data, the server must wrap the data object
20352  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20353  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20354  * depending on whether the callback name was passed:
20355  * <p>
20356  * <pre><code>
20357 boolean scriptTag = false;
20358 String cb = request.getParameter("callback");
20359 if (cb != null) {
20360     scriptTag = true;
20361     response.setContentType("text/javascript");
20362 } else {
20363     response.setContentType("application/x-json");
20364 }
20365 Writer out = response.getWriter();
20366 if (scriptTag) {
20367     out.write(cb + "(");
20368 }
20369 out.print(dataBlock.toJsonString());
20370 if (scriptTag) {
20371     out.write(");");
20372 }
20373 </pre></code>
20374  *
20375  * @constructor
20376  * @param {Object} config A configuration object.
20377  */
20378 Roo.data.ScriptTagProxy = function(A){
20379     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20380     Roo.apply(this, A);
20381     this.head = document.getElementsByTagName("head")[0];
20382 };
20383
20384 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20385
20386 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20387     /**
20388      * @cfg {String} url The URL from which to request the data object.
20389      */
20390     /**
20391      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20392      */
20393     timeout : 30000,
20394     /**
20395      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20396      * the server the name of the callback function set up by the load call to process the returned data object.
20397      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20398      * javascript output which calls this named function passing the data object as its only parameter.
20399      */
20400     callbackParam : "callback",
20401     /**
20402      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20403      * name to the request.
20404      */
20405     nocache : true,
20406
20407     /**
20408      * Load data from the configured URL, read the data object into
20409      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20410      * process that block using the passed callback.
20411      * @param {Object} params An object containing properties which are to be used as HTTP parameters
20412      * for the request to the remote server.
20413      * @param {Roo.data.DataReader} reader The Reader object which converts the data
20414      * object into a block of Roo.data.Records.
20415      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20416      * The function must be passed <ul>
20417      * <li>The Record block object</li>
20418      * <li>The "arg" argument from the load function</li>
20419      * <li>A boolean success indicator</li>
20420      * </ul>
20421      * @param {Object} scope The scope in which to call the callback
20422      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20423      */
20424     load : function(B, C, D, E, F){
20425         if(this.fireEvent("beforeload", this, B) !== false){
20426
20427             var  p = Roo.urlEncode(Roo.apply(B, this.extraParams));
20428
20429             var  url = this.url;
20430             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20431             if(this.nocache){
20432                 url += "&_dc=" + (new  Date().getTime());
20433             }
20434             var  transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20435             var  trans = {
20436                 id : transId,
20437                 cb : "stcCallback"+transId,
20438                 scriptId : "stcScript"+transId,
20439                 params : B,
20440                 arg : F,
20441                 url : url,
20442                 callback : D,
20443                 scope : E,
20444                 reader : C
20445             };
20446             var  conn = this;
20447
20448             window[trans.cb] = function(o){
20449                 conn.handleResponse(o, trans);
20450             };
20451
20452             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20453
20454             if(this.autoAbort !== false){
20455                 this.abort();
20456             }
20457
20458
20459             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20460
20461             var  script = document.createElement("script");
20462             script.setAttribute("src", url);
20463             script.setAttribute("type", "text/javascript");
20464             script.setAttribute("id", trans.scriptId);
20465             this.head.appendChild(script);
20466
20467             this.trans = trans;
20468         }else {
20469             D.call(E||this, null, F, false);
20470         }
20471     },
20472
20473     // private
20474     isLoading : function(){
20475         return  this.trans ? true : false;
20476     },
20477
20478     /**
20479      * Abort the current server request.
20480      */
20481     abort : function(){
20482         if(this.isLoading()){
20483             this.destroyTrans(this.trans);
20484         }
20485     },
20486
20487     // private
20488     destroyTrans : function(G, H){
20489         this.head.removeChild(document.getElementById(G.scriptId));
20490         clearTimeout(G.timeoutId);
20491         if(H){
20492             window[G.cb] = undefined;
20493             try{
20494                 delete  window[G.cb];
20495             }catch(e){}
20496         }else {
20497             // if hasn't been loaded, wait for load to remove it to prevent script error
20498             window[G.cb] = function(){
20499                 window[G.cb] = undefined;
20500                 try{
20501                     delete  window[G.cb];
20502                 }catch(e){}
20503             };
20504         }
20505     },
20506
20507     // private
20508     handleResponse : function(o, I){
20509         this.trans = false;
20510         this.destroyTrans(I, true);
20511         var  J;
20512         try {
20513             J = I.reader.readRecords(o);
20514         }catch(e){
20515             this.fireEvent("loadexception", this, o, trans.arg, e);
20516             trans.callback.call(trans.scope||window, null, trans.arg, false);
20517             return;
20518         }
20519
20520         this.fireEvent("load", this, o, I.arg);
20521         I.callback.call(I.scope||window, J, I.arg, true);
20522     },
20523
20524     // private
20525     handleFailure : function(K){
20526         this.trans = false;
20527         this.destroyTrans(K, false);
20528         this.fireEvent("loadexception", this, null, K.arg);
20529         K.callback.call(K.scope||window, null, K.arg, false);
20530     }
20531 });
20532 /*
20533  * Based on:
20534  * Ext JS Library 1.1.1
20535  * Copyright(c) 2006-2007, Ext JS, LLC.
20536  *
20537  * Originally Released Under LGPL - original licence link has changed is not relivant.
20538  *
20539  * Fork - LGPL
20540  * <script type="text/javascript">
20541  */
20542
20543 /**
20544  * @class Roo.data.JsonReader
20545  * @extends Roo.data.DataReader
20546  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20547  * based on mappings in a provided Roo.data.Record constructor.
20548  * <p>
20549  * Example code:
20550  * <pre><code>
20551 var RecordDef = Roo.data.Record.create([
20552     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
20553     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
20554 ]);
20555 var myReader = new Roo.data.JsonReader({
20556     totalProperty: "results",    // The property which contains the total dataset size (optional)
20557     root: "rows",                // The property which contains an Array of row objects
20558     id: "id"                     // The property within each row object that provides an ID for the record (optional)
20559 }, RecordDef);
20560 </code></pre>
20561  * <p>
20562  * This would consume a JSON file like this:
20563  * <pre><code>
20564 { 'results': 2, 'rows': [
20565     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20566     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20567 }
20568 </code></pre>
20569  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20570  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20571  * paged from the remote server.
20572  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20573  * @cfg {String} root name of the property which contains the Array of row objects.
20574  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20575  * @constructor
20576  * Create a new JsonReader
20577  * @param {Object} meta Metadata configuration options
20578  * @param {Object} recordType Either an Array of field definition objects,
20579  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20580  */
20581 Roo.data.JsonReader = function(A, B){
20582     
20583     A = A || {};
20584     // set some defaults:
20585     Roo.applyIf(A, {
20586         totalProperty: 'total',
20587         successProperty : 'success',
20588         root : 'data',
20589         id : 'id'
20590     });
20591     
20592     Roo.data.JsonReader.superclass.constructor.call(this, A, B||A.fields);
20593 };
20594 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20595     /**
20596      * This method is only used by a DataProxy which has retrieved data from a remote server.
20597      * @param {Object} response The XHR object which contains the JSON data in its responseText.
20598      * @return {Object} data A data block which is used by an Roo.data.Store object as
20599      * a cache of Roo.data.Records.
20600      */
20601     read : function(C){
20602         var  D = C.responseText;
20603         /* eval:var:o */
20604         var  o = eval("("+D+")");
20605         if(!o) {
20606             throw  {message: "JsonReader.read: Json object not found"};
20607         }
20608         
20609         if(o.metaData){
20610             delete  this.ef;
20611             this.meta = o.metaData;
20612             this.recordType = Roo.data.Record.create(o.metaData.fields);
20613             this.onMetaChange(this.meta, this.recordType, o);
20614         }
20615         return  this.readRecords(o);
20616     },
20617
20618     // private function a store will implement
20619     onMetaChange : function(E, F, o){
20620
20621     },
20622
20623     /**
20624          * @ignore
20625          */
20626     simpleAccess: function(G, H) {
20627         return  G[H];
20628     },
20629
20630         /**
20631          * @ignore
20632          */
20633     getJsonAccessor: function(){
20634         var  re = /[\[\.]/;
20635         return  function(I) {
20636             try {
20637                 return (re.test(I))
20638                     ? new  Function("obj", "return obj." + I)
20639                     : function(K){
20640                         return  K[I];
20641                     };
20642             } catch(e){}
20643             return  Roo.emptyFn;
20644         };
20645     }(),
20646
20647     /**
20648      * Create a data block containing Roo.data.Records from an XML document.
20649      * @param {Object} o An object which contains an Array of row objects in the property specified
20650      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20651      * which contains the total size of the dataset.
20652      * @return {Object} data A data block which is used by an Roo.data.Store object as
20653      * a cache of Roo.data.Records.
20654      */
20655     readRecords : function(o){
20656         /**
20657          * After any data loads, the raw JSON data is available for further custom processing.
20658          * @type Object
20659          */
20660         this.jsonData = o;
20661         var  s = this.meta, I = this.recordType,
20662             f = I.prototype.fields, fi = f.items, fl = f.length;
20663
20664 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
20665         if (!this.ef) {
20666             if(s.totalProperty) {
20667                     this.getTotal = this.getJsonAccessor(s.totalProperty);
20668                 }
20669                 if(s.successProperty) {
20670                     this.getSuccess = this.getJsonAccessor(s.successProperty);
20671                 }
20672
20673                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return  p;};
20674                 if (s.id) {
20675                         var  g = this.getJsonAccessor(s.id);
20676                         this.getId = function(N) {
20677                                 var  r = g(N);
20678                                 return  (r === undefined || r === "") ? null : r;
20679                         };
20680                 } else  {
20681                         this.getId = function(){return  null;};
20682                 }
20683
20684             this.ef = [];
20685             for(var  i = 0; i < fl; i++){
20686                 f = fi[i];
20687                 var  map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20688                 this.ef[i] = this.getJsonAccessor(map);
20689             }
20690         }
20691
20692         var  J = this.getRoot(o), c = J.length, K = c, L = true;
20693         if(s.totalProperty){
20694             var  v = parseInt(this.getTotal(o), 10);
20695             if(!isNaN(v)){
20696                 K = v;
20697             }
20698         }
20699         if(s.successProperty){
20700             var  v = this.getSuccess(o);
20701             if(v === false || v === 'false'){
20702                 L = false;
20703             }
20704         }
20705         var  M = [];
20706             for(var  i = 0; i < c; i++){
20707                     var  n = J[i];
20708                 var  values = {};
20709                 var  id = this.getId(n);
20710                 for(var  j = 0; j < fl; j++){
20711                     f = fi[j];
20712                 var  v = this.ef[j](n);
20713                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20714                 }
20715                 var  record = new  I(values, id);
20716                 record.json = n;
20717                 M[i] = record;
20718             }
20719             return  {
20720                 success : L,
20721                 records : M,
20722                 totalRecords : K
20723             };
20724     }
20725 });
20726 /*
20727  * Based on:
20728  * Ext JS Library 1.1.1
20729  * Copyright(c) 2006-2007, Ext JS, LLC.
20730  *
20731  * Originally Released Under LGPL - original licence link has changed is not relivant.
20732  *
20733  * Fork - LGPL
20734  * <script type="text/javascript">
20735  */
20736
20737 /**
20738  * @class Roo.data.XmlReader
20739  * @extends Roo.data.DataReader
20740  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20741  * based on mappings in a provided Roo.data.Record constructor.<br><br>
20742  * <p>
20743  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20744  * header in the HTTP response must be set to "text/xml".</em>
20745  * <p>
20746  * Example code:
20747  * <pre><code>
20748 var RecordDef = Roo.data.Record.create([
20749    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
20750    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
20751 ]);
20752 var myReader = new Roo.data.XmlReader({
20753    totalRecords: "results", // The element which contains the total dataset size (optional)
20754    record: "row",           // The repeated element which contains row information
20755    id: "id"                 // The element within the row that provides an ID for the record (optional)
20756 }, RecordDef);
20757 </code></pre>
20758  * <p>
20759  * This would consume an XML file like this:
20760  * <pre><code>
20761 &lt;?xml?>
20762 &lt;dataset>
20763  &lt;results>2&lt;/results>
20764  &lt;row>
20765    &lt;id>1&lt;/id>
20766    &lt;name>Bill&lt;/name>
20767    &lt;occupation>Gardener&lt;/occupation>
20768  &lt;/row>
20769  &lt;row>
20770    &lt;id>2&lt;/id>
20771    &lt;name>Ben&lt;/name>
20772    &lt;occupation>Horticulturalist&lt;/occupation>
20773  &lt;/row>
20774 &lt;/dataset>
20775 </code></pre>
20776  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20777  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20778  * paged from the remote server.
20779  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20780  * @cfg {String} success The DomQuery path to the success attribute used by forms.
20781  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20782  * a record identifier value.
20783  * @constructor
20784  * Create a new XmlReader
20785  * @param {Object} meta Metadata configuration options
20786  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
20787  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20788  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
20789  */
20790 Roo.data.XmlReader = function(A, B){
20791     A = A || {};
20792     Roo.data.XmlReader.superclass.constructor.call(this, A, B||A.fields);
20793 };
20794 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20795     /**
20796      * This method is only used by a DataProxy which has retrieved data from a remote server.
20797          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
20798          * to contain a method called 'responseXML' that returns an XML document object.
20799      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20800      * a cache of Roo.data.Records.
20801      */
20802     read : function(C){
20803         var  D = C.responseXML;
20804         if(!D) {
20805             throw  {message: "XmlReader.read: XML Document not available"};
20806         }
20807         return  this.readRecords(D);
20808     },
20809
20810     /**
20811      * Create a data block containing Roo.data.Records from an XML document.
20812          * @param {Object} doc A parsed XML document.
20813      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20814      * a cache of Roo.data.Records.
20815      */
20816     readRecords : function(E){
20817         /**
20818          * After any data loads/reads, the raw XML Document is available for further custom processing.
20819          * @type XMLDocument
20820          */
20821         this.xmlData = E;
20822         var  F = E.documentElement || E;
20823         var  q = Roo.DomQuery;
20824         var  G = this.recordType, H = G.prototype.fields;
20825         var  I = this.meta.id;
20826         var  J = 0, K = true;
20827         if(this.meta.totalRecords){
20828             J = q.selectNumber(this.meta.totalRecords, F, 0);
20829         }
20830         
20831         if(this.meta.success){
20832             var  sv = q.selectValue(this.meta.success, F, true);
20833             K = sv !== false && sv !== 'false';
20834         }
20835         var  L = [];
20836         var  ns = q.select(this.meta.record, F);
20837         for(var  i = 0, len = ns.length; i < len; i++) {
20838                 var  n = ns[i];
20839                 var  values = {};
20840                 var  id = I ? q.selectValue(I, n) : undefined;
20841                 for(var  j = 0, jlen = H.length; j < jlen; j++){
20842                     var  f = H.items[j];
20843                 var  v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20844                     v = f.convert(v);
20845                     values[f.name] = v;
20846                 }
20847                 var  record = new  G(values, id);
20848                 record.node = n;
20849                 L[L.length] = record;
20850             }
20851
20852             return  {
20853                 success : K,
20854                 records : L,
20855                 totalRecords : J || L.length
20856             };
20857     }
20858 });
20859 /*
20860  * Based on:
20861  * Ext JS Library 1.1.1
20862  * Copyright(c) 2006-2007, Ext JS, LLC.
20863  *
20864  * Originally Released Under LGPL - original licence link has changed is not relivant.
20865  *
20866  * Fork - LGPL
20867  * <script type="text/javascript">
20868  */
20869
20870 /**
20871  * @class Roo.data.ArrayReader
20872  * @extends Roo.data.DataReader
20873  * Data reader class to create an Array of Roo.data.Record objects from an Array.
20874  * Each element of that Array represents a row of data fields. The
20875  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20876  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20877  * <p>
20878  * Example code:.
20879  * <pre><code>
20880 var RecordDef = Roo.data.Record.create([
20881     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
20882     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
20883 ]);
20884 var myReader = new Roo.data.ArrayReader({
20885     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
20886 }, RecordDef);
20887 </code></pre>
20888  * <p>
20889  * This would consume an Array like this:
20890  * <pre><code>
20891 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20892   </code></pre>
20893  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20894  * @constructor
20895  * Create a new JsonReader
20896  * @param {Object} meta Metadata configuration options.
20897  * @param {Object} recordType Either an Array of field definition objects
20898  * as specified to {@link Roo.data.Record#create},
20899  * or an {@link Roo.data.Record} object
20900  * created using {@link Roo.data.Record#create}.
20901  */
20902 Roo.data.ArrayReader = function(A, B){
20903     Roo.data.ArrayReader.superclass.constructor.call(this, A, B);
20904 };
20905
20906 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20907     /**
20908      * Create a data block containing Roo.data.Records from an XML document.
20909      * @param {Object} o An Array of row objects which represents the dataset.
20910      * @return {Object} data A data block which is used by an Roo.data.Store object as
20911      * a cache of Roo.data.Records.
20912      */
20913     readRecords : function(o){
20914         var  C = this.meta ? this.meta.id : null;
20915         var  D = this.recordType, E = D.prototype.fields;
20916         var  F = [];
20917         var  G = o;
20918             for(var  i = 0; i < G.length; i++){
20919                     var  n = G[i];
20920                 var  values = {};
20921                 var  id = ((C || C === 0) && n[C] !== undefined && n[C] !== "" ? n[C] : null);
20922                 for(var  j = 0, jlen = E.length; j < jlen; j++){
20923                 var  f = E.items[j];
20924                 var  k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20925                 var  v = n[k] !== undefined ? n[k] : f.defaultValue;
20926                 v = f.convert(v);
20927                 values[f.name] = v;
20928             }
20929                 var  record = new  D(values, id);
20930                 record.json = n;
20931                 F[F.length] = record;
20932             }
20933             return  {
20934                 records : F,
20935                 totalRecords : F.length
20936             };
20937     }
20938 });
20939 /*
20940  * Based on:
20941  * Ext JS Library 1.1.1
20942  * Copyright(c) 2006-2007, Ext JS, LLC.
20943  *
20944  * Originally Released Under LGPL - original licence link has changed is not relivant.
20945  *
20946  * Fork - LGPL
20947  * <script type="text/javascript">
20948  */
20949
20950
20951 /**
20952  * @class Roo.data.Tree
20953  * @extends Roo.util.Observable
20954  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20955  * in the tree have most standard DOM functionality.
20956  * @constructor
20957  * @param {Node} root (optional) The root node
20958  */
20959 Roo.data.Tree = function(A){
20960    this.nodeHash = {};
20961    /**
20962     * The root node for this tree
20963     * @type Node
20964     */
20965    this.root = null;
20966    if(A){
20967        this.setRootNode(A);
20968    }
20969
20970    this.addEvents({
20971        /**
20972         * @event append
20973         * Fires when a new child node is appended to a node in this tree.
20974         * @param {Tree} tree The owner tree
20975         * @param {Node} parent The parent node
20976         * @param {Node} node The newly appended node
20977         * @param {Number} index The index of the newly appended node
20978         */
20979        "append" : true,
20980        /**
20981         * @event remove
20982         * Fires when a child node is removed from a node in this tree.
20983         * @param {Tree} tree The owner tree
20984         * @param {Node} parent The parent node
20985         * @param {Node} node The child node removed
20986         */
20987        "remove" : true,
20988        /**
20989         * @event move
20990         * Fires when a node is moved to a new location in the tree
20991         * @param {Tree} tree The owner tree
20992         * @param {Node} node The node moved
20993         * @param {Node} oldParent The old parent of this node
20994         * @param {Node} newParent The new parent of this node
20995         * @param {Number} index The index it was moved to
20996         */
20997        "move" : true,
20998        /**
20999         * @event insert
21000         * Fires when a new child node is inserted in a node in this tree.
21001         * @param {Tree} tree The owner tree
21002         * @param {Node} parent The parent node
21003         * @param {Node} node The child node inserted
21004         * @param {Node} refNode The child node the node was inserted before
21005         */
21006        "insert" : true,
21007        /**
21008         * @event beforeappend
21009         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21010         * @param {Tree} tree The owner tree
21011         * @param {Node} parent The parent node
21012         * @param {Node} node The child node to be appended
21013         */
21014        "beforeappend" : true,
21015        /**
21016         * @event beforeremove
21017         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21018         * @param {Tree} tree The owner tree
21019         * @param {Node} parent The parent node
21020         * @param {Node} node The child node to be removed
21021         */
21022        "beforeremove" : true,
21023        /**
21024         * @event beforemove
21025         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21026         * @param {Tree} tree The owner tree
21027         * @param {Node} node The node being moved
21028         * @param {Node} oldParent The parent of the node
21029         * @param {Node} newParent The new parent the node is moving to
21030         * @param {Number} index The index it is being moved to
21031         */
21032        "beforemove" : true,
21033        /**
21034         * @event beforeinsert
21035         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21036         * @param {Tree} tree The owner tree
21037         * @param {Node} parent The parent node
21038         * @param {Node} node The child node to be inserted
21039         * @param {Node} refNode The child node the node is being inserted before
21040         */
21041        "beforeinsert" : true
21042    });
21043
21044     Roo.data.Tree.superclass.constructor.call(this);
21045 };
21046
21047 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21048     pathSeparator: "/",
21049
21050     proxyNodeEvent : function(){
21051         return  this.fireEvent.apply(this, arguments);
21052     },
21053
21054     /**
21055      * Returns the root node for this tree.
21056      * @return {Node}
21057      */
21058     getRootNode : function(){
21059         return  this.root;
21060     },
21061
21062     /**
21063      * Sets the root node for this tree.
21064      * @param {Node} node
21065      * @return {Node}
21066      */
21067     setRootNode : function(B){
21068         this.root = B;
21069         B.ownerTree = this;
21070         B.isRoot = true;
21071         this.registerNode(B);
21072         return  B;
21073     },
21074
21075     /**
21076      * Gets a node in this tree by its id.
21077      * @param {String} id
21078      * @return {Node}
21079      */
21080     getNodeById : function(id){
21081         return  this.nodeHash[id];
21082     },
21083
21084     registerNode : function(C){
21085         this.nodeHash[C.id] = C;
21086     },
21087
21088     unregisterNode : function(D){
21089         delete  this.nodeHash[D.id];
21090     },
21091
21092     toString : function(){
21093         return  "[Tree"+(this.id?" "+this.id:"")+"]";
21094     }
21095 });
21096
21097 /**
21098  * @class Roo.data.Node
21099  * @extends Roo.util.Observable
21100  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21101  * @cfg {String} id The id for this node. If one is not specified, one is generated.
21102  * @constructor
21103  * @param {Object} attributes The attributes/config for the node
21104  */
21105 Roo.data.Node = function(E){
21106     /**
21107      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21108      * @type {Object}
21109      */
21110     this.attributes = E || {};
21111     this.leaf = this.attributes.leaf;
21112     /**
21113      * The node id. @type String
21114      */
21115     this.id = this.attributes.id;
21116     if(!this.id){
21117         this.id = Roo.id(null, "ynode-");
21118         this.attributes.id = this.id;
21119     }
21120
21121     /**
21122      * All child nodes of this node. @type Array
21123      */
21124     this.childNodes = [];
21125     if(!this.childNodes.indexOf){ // indexOf is a must
21126         this.childNodes.indexOf = function(o){
21127             for(var  i = 0, len = this.length; i < len; i++){
21128                 if(this[i] == o) return  i;
21129             }
21130             return  -1;
21131         };
21132     }
21133
21134     /**
21135      * The parent node for this node. @type Node
21136      */
21137     this.parentNode = null;
21138     /**
21139      * The first direct child node of this node, or null if this node has no child nodes. @type Node
21140      */
21141     this.firstChild = null;
21142     /**
21143      * The last direct child node of this node, or null if this node has no child nodes. @type Node
21144      */
21145     this.lastChild = null;
21146     /**
21147      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21148      */
21149     this.previousSibling = null;
21150     /**
21151      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21152      */
21153     this.nextSibling = null;
21154
21155     this.addEvents({
21156        /**
21157         * @event append
21158         * Fires when a new child node is appended
21159         * @param {Tree} tree The owner tree
21160         * @param {Node} this This node
21161         * @param {Node} node The newly appended node
21162         * @param {Number} index The index of the newly appended node
21163         */
21164        "append" : true,
21165        /**
21166         * @event remove
21167         * Fires when a child node is removed
21168         * @param {Tree} tree The owner tree
21169         * @param {Node} this This node
21170         * @param {Node} node The removed node
21171         */
21172        "remove" : true,
21173        /**
21174         * @event move
21175         * Fires when this node is moved to a new location in the tree
21176         * @param {Tree} tree The owner tree
21177         * @param {Node} this This node
21178         * @param {Node} oldParent The old parent of this node
21179         * @param {Node} newParent The new parent of this node
21180         * @param {Number} index The index it was moved to
21181         */
21182        "move" : true,
21183        /**
21184         * @event insert
21185         * Fires when a new child node is inserted.
21186         * @param {Tree} tree The owner tree
21187         * @param {Node} this This node
21188         * @param {Node} node The child node inserted
21189         * @param {Node} refNode The child node the node was inserted before
21190         */
21191        "insert" : true,
21192        /**
21193         * @event beforeappend
21194         * Fires before a new child is appended, return false to cancel the append.
21195         * @param {Tree} tree The owner tree
21196         * @param {Node} this This node
21197         * @param {Node} node The child node to be appended
21198         */
21199        "beforeappend" : true,
21200        /**
21201         * @event beforeremove
21202         * Fires before a child is removed, return false to cancel the remove.
21203         * @param {Tree} tree The owner tree
21204         * @param {Node} this This node
21205         * @param {Node} node The child node to be removed
21206         */
21207        "beforeremove" : true,
21208        /**
21209         * @event beforemove
21210         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21211         * @param {Tree} tree The owner tree
21212         * @param {Node} this This node
21213         * @param {Node} oldParent The parent of this node
21214         * @param {Node} newParent The new parent this node is moving to
21215         * @param {Number} index The index it is being moved to
21216         */
21217        "beforemove" : true,
21218        /**
21219         * @event beforeinsert
21220         * Fires before a new child is inserted, return false to cancel the insert.
21221         * @param {Tree} tree The owner tree
21222         * @param {Node} this This node
21223         * @param {Node} node The child node to be inserted
21224         * @param {Node} refNode The child node the node is being inserted before
21225         */
21226        "beforeinsert" : true
21227    });
21228     this.listeners = this.attributes.listeners;
21229     Roo.data.Node.superclass.constructor.call(this);
21230 };
21231
21232 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21233     fireEvent : function(F){
21234         // first do standard event for this node
21235         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21236             return  false;
21237         }
21238         // then bubble it up to the tree if the event wasn't cancelled
21239         var  ot = this.getOwnerTree();
21240         if(ot){
21241             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21242                 return  false;
21243             }
21244         }
21245         return  true;
21246     },
21247
21248     /**
21249      * Returns true if this node is a leaf
21250      * @return {Boolean}
21251      */
21252     isLeaf : function(){
21253         return  this.leaf === true;
21254     },
21255
21256     // private
21257     setFirstChild : function(G){
21258         this.firstChild = G;
21259     },
21260
21261     //private
21262     setLastChild : function(H){
21263         this.lastChild = H;
21264     },
21265
21266
21267     /**
21268      * Returns true if this node is the last child of its parent
21269      * @return {Boolean}
21270      */
21271     isLast : function(){
21272        return  (!this.parentNode ? true : this.parentNode.lastChild == this);
21273     },
21274
21275     /**
21276      * Returns true if this node is the first child of its parent
21277      * @return {Boolean}
21278      */
21279     isFirst : function(){
21280        return  (!this.parentNode ? true : this.parentNode.firstChild == this);
21281     },
21282
21283     hasChildNodes : function(){
21284         return  !this.isLeaf() && this.childNodes.length > 0;
21285     },
21286
21287     /**
21288      * Insert node(s) as the last child node of this node.
21289      * @param {Node/Array} node The node or Array of nodes to append
21290      * @return {Node} The appended node if single append, or null if an array was passed
21291      */
21292     appendChild : function(I){
21293         var  J = false;
21294         if(I  instanceof  Array){
21295             J = I;
21296         }else  if(arguments.length > 1){
21297             J = arguments;
21298         }
21299         // if passed an array or multiple args do them one by one
21300         if(J){
21301             for(var  i = 0, len = J.length; i < len; i++) {
21302                 this.appendChild(J[i]);
21303             }
21304         }else {
21305             if(this.fireEvent("beforeappend", this.ownerTree, this, I) === false){
21306                 return  false;
21307             }
21308             var  index = this.childNodes.length;
21309             var  oldParent = I.parentNode;
21310             // it's a move, make sure we move it cleanly
21311             if(oldParent){
21312                 if(I.fireEvent("beforemove", I.getOwnerTree(), I, oldParent, this, index) === false){
21313                     return  false;
21314                 }
21315
21316                 oldParent.removeChild(I);
21317             }
21318
21319             index = this.childNodes.length;
21320             if(index == 0){
21321                 this.setFirstChild(I);
21322             }
21323
21324             this.childNodes.push(I);
21325             I.parentNode = this;
21326             var  ps = this.childNodes[index-1];
21327             if(ps){
21328                 I.previousSibling = ps;
21329                 ps.nextSibling = I;
21330             }else {
21331                 I.previousSibling = null;
21332             }
21333
21334             I.nextSibling = null;
21335             this.setLastChild(I);
21336             I.setOwnerTree(this.getOwnerTree());
21337             this.fireEvent("append", this.ownerTree, this, I, index);
21338             if(oldParent){
21339                 I.fireEvent("move", this.ownerTree, I, oldParent, this, index);
21340             }
21341             return  I;
21342         }
21343     },
21344
21345     /**
21346      * Removes a child node from this node.
21347      * @param {Node} node The node to remove
21348      * @return {Node} The removed node
21349      */
21350     removeChild : function(K){
21351         var  L = this.childNodes.indexOf(K);
21352         if(L == -1){
21353             return  false;
21354         }
21355         if(this.fireEvent("beforeremove", this.ownerTree, this, K) === false){
21356             return  false;
21357         }
21358
21359
21360         // remove it from childNodes collection
21361         this.childNodes.splice(L, 1);
21362
21363         // update siblings
21364         if(K.previousSibling){
21365             K.previousSibling.nextSibling = K.nextSibling;
21366         }
21367         if(K.nextSibling){
21368             K.nextSibling.previousSibling = K.previousSibling;
21369         }
21370
21371         // update child refs
21372         if(this.firstChild == K){
21373             this.setFirstChild(K.nextSibling);
21374         }
21375         if(this.lastChild == K){
21376             this.setLastChild(K.previousSibling);
21377         }
21378
21379
21380         K.setOwnerTree(null);
21381         // clear any references from the node
21382         K.parentNode = null;
21383         K.previousSibling = null;
21384         K.nextSibling = null;
21385         this.fireEvent("remove", this.ownerTree, this, K);
21386         return  K;
21387     },
21388
21389     /**
21390      * Inserts the first node before the second node in this nodes childNodes collection.
21391      * @param {Node} node The node to insert
21392      * @param {Node} refNode The node to insert before (if null the node is appended)
21393      * @return {Node} The inserted node
21394      */
21395     insertBefore : function(M, N){
21396         if(!N){ // like standard Dom, refNode can be null for append
21397             return  this.appendChild(M);
21398         }
21399         // nothing to do
21400         if(M == N){
21401             return  false;
21402         }
21403
21404         if(this.fireEvent("beforeinsert", this.ownerTree, this, M, N) === false){
21405             return  false;
21406         }
21407         var  O = this.childNodes.indexOf(N);
21408         var  P = M.parentNode;
21409         var  Q = O;
21410
21411         // when moving internally, indexes will change after remove
21412         if(P == this && this.childNodes.indexOf(M) < O){
21413             Q--;
21414         }
21415
21416         // it's a move, make sure we move it cleanly
21417         if(P){
21418             if(M.fireEvent("beforemove", M.getOwnerTree(), M, P, this, O, N) === false){
21419                 return  false;
21420             }
21421
21422             P.removeChild(M);
21423         }
21424         if(Q == 0){
21425             this.setFirstChild(M);
21426         }
21427
21428         this.childNodes.splice(Q, 0, M);
21429         M.parentNode = this;
21430         var  ps = this.childNodes[Q-1];
21431         if(ps){
21432             M.previousSibling = ps;
21433             ps.nextSibling = M;
21434         }else {
21435             M.previousSibling = null;
21436         }
21437
21438         M.nextSibling = N;
21439         N.previousSibling = M;
21440         M.setOwnerTree(this.getOwnerTree());
21441         this.fireEvent("insert", this.ownerTree, this, M, N);
21442         if(P){
21443             M.fireEvent("move", this.ownerTree, M, P, this, Q, N);
21444         }
21445         return  M;
21446     },
21447
21448     /**
21449      * Returns the child node at the specified index.
21450      * @param {Number} index
21451      * @return {Node}
21452      */
21453     item : function(R){
21454         return  this.childNodes[R];
21455     },
21456
21457     /**
21458      * Replaces one child node in this node with another.
21459      * @param {Node} newChild The replacement node
21460      * @param {Node} oldChild The node to replace
21461      * @return {Node} The replaced node
21462      */
21463     replaceChild : function(S, T){
21464         this.insertBefore(S, T);
21465         this.removeChild(T);
21466         return  T;
21467     },
21468
21469     /**
21470      * Returns the index of a child node
21471      * @param {Node} node
21472      * @return {Number} The index of the node or -1 if it was not found
21473      */
21474     indexOf : function(U){
21475         return  this.childNodes.indexOf(U);
21476     },
21477
21478     /**
21479      * Returns the tree this node is in.
21480      * @return {Tree}
21481      */
21482     getOwnerTree : function(){
21483         // if it doesn't have one, look for one
21484         if(!this.ownerTree){
21485             var  p = this;
21486             while(p){
21487                 if(p.ownerTree){
21488                     this.ownerTree = p.ownerTree;
21489                     break;
21490                 }
21491
21492                 p = p.parentNode;
21493             }
21494         }
21495         return  this.ownerTree;
21496     },
21497
21498     /**
21499      * Returns depth of this node (the root node has a depth of 0)
21500      * @return {Number}
21501      */
21502     getDepth : function(){
21503         var  V = 0;
21504         var  p = this;
21505         while(p.parentNode){
21506             ++V;
21507             p = p.parentNode;
21508         }
21509         return  V;
21510     },
21511
21512     // private
21513     setOwnerTree : function(W){
21514         // if it's move, we need to update everyone
21515         if(W != this.ownerTree){
21516             if(this.ownerTree){
21517                 this.ownerTree.unregisterNode(this);
21518             }
21519
21520             this.ownerTree = W;
21521             var  cs = this.childNodes;
21522             for(var  i = 0, len = cs.length; i < len; i++) {
21523                 cs[i].setOwnerTree(W);
21524             }
21525             if(W){
21526                 W.registerNode(this);
21527             }
21528         }
21529     },
21530
21531     /**
21532      * Returns the path for this node. The path can be used to expand or select this node programmatically.
21533      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21534      * @return {String} The path
21535      */
21536     getPath : function(X){
21537         X = X || "id";
21538         var  p = this.parentNode;
21539         var  b = [this.attributes[X]];
21540         while(p){
21541             b.unshift(p.attributes[X]);
21542             p = p.parentNode;
21543         }
21544         var  Y = this.getOwnerTree().pathSeparator;
21545         return  Y + b.join(Y);
21546     },
21547
21548     /**
21549      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21550      * function call will be the scope provided or the current node. The arguments to the function
21551      * will be the args provided or the current node. If the function returns false at any point,
21552      * the bubble is stopped.
21553      * @param {Function} fn The function to call
21554      * @param {Object} scope (optional) The scope of the function (defaults to current node)
21555      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21556      */
21557     bubble : function(fn, Z, a){
21558         var  p = this;
21559         while(p){
21560             if(fn.call(Z || p, a || p) === false){
21561                 break;
21562             }
21563
21564             p = p.parentNode;
21565         }
21566     },
21567
21568     /**
21569      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21570      * function call will be the scope provided or the current node. The arguments to the function
21571      * will be the args provided or the current node. If the function returns false at any point,
21572      * the cascade is stopped on that branch.
21573      * @param {Function} fn The function to call
21574      * @param {Object} scope (optional) The scope of the function (defaults to current node)
21575      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21576      */
21577     cascade : function(fn, c, d){
21578         if(fn.call(c || this, d || this) !== false){
21579             var  cs = this.childNodes;
21580             for(var  i = 0, len = cs.length; i < len; i++) {
21581                 cs[i].cascade(fn, c, d);
21582             }
21583         }
21584     },
21585
21586     /**
21587      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21588      * function call will be the scope provided or the current node. The arguments to the function
21589      * will be the args provided or the current node. If the function returns false at any point,
21590      * the iteration stops.
21591      * @param {Function} fn The function to call
21592      * @param {Object} scope (optional) The scope of the function (defaults to current node)
21593      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21594      */
21595     eachChild : function(fn, e, f){
21596         var  cs = this.childNodes;
21597         for(var  i = 0, len = cs.length; i < len; i++) {
21598                 if(fn.call(e || this, f || cs[i]) === false){
21599                     break;
21600                 }
21601         }
21602     },
21603
21604     /**
21605      * Finds the first child that has the attribute with the specified value.
21606      * @param {String} attribute The attribute name
21607      * @param {Mixed} value The value to search for
21608      * @return {Node} The found child or null if none was found
21609      */
21610     findChild : function(g, h){
21611         var  cs = this.childNodes;
21612         for(var  i = 0, len = cs.length; i < len; i++) {
21613                 if(cs[i].attributes[g] == h){
21614                     return  cs[i];
21615                 }
21616         }
21617         return  null;
21618     },
21619
21620     /**
21621      * Finds the first child by a custom function. The child matches if the function passed
21622      * returns true.
21623      * @param {Function} fn
21624      * @param {Object} scope (optional)
21625      * @return {Node} The found child or null if none was found
21626      */
21627     findChildBy : function(fn, j){
21628         var  cs = this.childNodes;
21629         for(var  i = 0, len = cs.length; i < len; i++) {
21630                 if(fn.call(j||cs[i], cs[i]) === true){
21631                     return  cs[i];
21632                 }
21633         }
21634         return  null;
21635     },
21636
21637     /**
21638      * Sorts this nodes children using the supplied sort function
21639      * @param {Function} fn
21640      * @param {Object} scope (optional)
21641      */
21642     sort : function(fn, k){
21643         var  cs = this.childNodes;
21644         var  l = cs.length;
21645         if(l > 0){
21646             var  sortFn = k ? function(){fn.apply(k, arguments);} : fn;
21647             cs.sort(sortFn);
21648             for(var  i = 0; i < l; i++){
21649                 var  n = cs[i];
21650                 n.previousSibling = cs[i-1];
21651                 n.nextSibling = cs[i+1];
21652                 if(i == 0){
21653                     this.setFirstChild(n);
21654                 }
21655                 if(i == l-1){
21656                     this.setLastChild(n);
21657                 }
21658             }
21659         }
21660     },
21661
21662     /**
21663      * Returns true if this node is an ancestor (at any point) of the passed node.
21664      * @param {Node} node
21665      * @return {Boolean}
21666      */
21667     contains : function(m){
21668         return  m.isAncestor(this);
21669     },
21670
21671     /**
21672      * Returns true if the passed node is an ancestor (at any point) of this node.
21673      * @param {Node} node
21674      * @return {Boolean}
21675      */
21676     isAncestor : function(o){
21677         var  p = this.parentNode;
21678         while(p){
21679             if(p == o){
21680                 return  true;
21681             }
21682
21683             p = p.parentNode;
21684         }
21685         return  false;
21686     },
21687
21688     toString : function(){
21689         return  "[Node"+(this.id?" "+this.id:"")+"]";
21690     }
21691 });
21692 /*
21693  * Based on:
21694  * Ext JS Library 1.1.1
21695  * Copyright(c) 2006-2007, Ext JS, LLC.
21696  *
21697  * Originally Released Under LGPL - original licence link has changed is not relivant.
21698  *
21699  * Fork - LGPL
21700  * <script type="text/javascript">
21701  */
21702  
21703
21704 /**
21705  * @class Roo.ComponentMgr
21706  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21707  * @singleton
21708  */
21709 Roo.ComponentMgr = function(){
21710     var  A = new  Roo.util.MixedCollection();
21711
21712     return  {
21713         /**
21714          * Registers a component.
21715          * @param {Roo.Component} c The component
21716          */
21717         register : function(c){
21718             A.add(c);
21719         },
21720
21721         /**
21722          * Unregisters a component.
21723          * @param {Roo.Component} c The component
21724          */
21725         unregister : function(c){
21726             A.remove(c);
21727         },
21728
21729         /**
21730          * Returns a component by id
21731          * @param {String} id The component id
21732          */
21733         get : function(id){
21734             return  A.get(id);
21735         },
21736
21737         /**
21738          * Registers a function that will be called when a specified component is added to ComponentMgr
21739          * @param {String} id The component id
21740          * @param {Funtction} fn The callback function
21741          * @param {Object} scope The scope of the callback
21742          */
21743         onAvailable : function(id, fn, C){
21744             A.on("add", function(D, o){
21745                 if(o.id == id){
21746                     fn.call(C || o, o);
21747                     A.un("add", fn, C);
21748                 }
21749             });
21750         }
21751     };
21752 }();
21753 /*
21754  * Based on:
21755  * Ext JS Library 1.1.1
21756  * Copyright(c) 2006-2007, Ext JS, LLC.
21757  *
21758  * Originally Released Under LGPL - original licence link has changed is not relivant.
21759  *
21760  * Fork - LGPL
21761  * <script type="text/javascript">
21762  */
21763  
21764 /**
21765  * @class Roo.Component
21766  * @extends Roo.util.Observable
21767  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
21768  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
21769  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21770  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21771  * All visual components (widgets) that require rendering into a layout should subclass Component.
21772  * @constructor
21773  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
21774  * 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
21775  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
21776  */
21777 Roo.Component = function(A){
21778     A = A || {};
21779     if(A.tagName || A.dom || typeof  A == "string"){ // element object
21780         A = {el: A, id: A.id || A};
21781     }
21782
21783     this.initialConfig = A;
21784
21785     Roo.apply(this, A);
21786     this.addEvents({
21787         /**
21788          * @event disable
21789          * Fires after the component is disabled.
21790              * @param {Roo.Component} this
21791              */
21792         disable : true,
21793         /**
21794          * @event enable
21795          * Fires after the component is enabled.
21796              * @param {Roo.Component} this
21797              */
21798         enable : true,
21799         /**
21800          * @event beforeshow
21801          * Fires before the component is shown.  Return false to stop the show.
21802              * @param {Roo.Component} this
21803              */
21804         beforeshow : true,
21805         /**
21806          * @event show
21807          * Fires after the component is shown.
21808              * @param {Roo.Component} this
21809              */
21810         show : true,
21811         /**
21812          * @event beforehide
21813          * Fires before the component is hidden. Return false to stop the hide.
21814              * @param {Roo.Component} this
21815              */
21816         beforehide : true,
21817         /**
21818          * @event hide
21819          * Fires after the component is hidden.
21820              * @param {Roo.Component} this
21821              */
21822         hide : true,
21823         /**
21824          * @event beforerender
21825          * Fires before the component is rendered. Return false to stop the render.
21826              * @param {Roo.Component} this
21827              */
21828         beforerender : true,
21829         /**
21830          * @event render
21831          * Fires after the component is rendered.
21832              * @param {Roo.Component} this
21833              */
21834         render : true,
21835         /**
21836          * @event beforedestroy
21837          * Fires before the component is destroyed. Return false to stop the destroy.
21838              * @param {Roo.Component} this
21839              */
21840         beforedestroy : true,
21841         /**
21842          * @event destroy
21843          * Fires after the component is destroyed.
21844              * @param {Roo.Component} this
21845              */
21846         destroy : true
21847     });
21848     if(!this.id){
21849         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21850     }
21851
21852     Roo.ComponentMgr.register(this);
21853     Roo.Component.superclass.constructor.call(this);
21854     this.initComponent();
21855     if(this.renderTo){ // not supported by all components yet. use at your own risk!
21856         this.render(this.renderTo);
21857         delete  this.renderTo;
21858     }
21859 };
21860
21861 // private
21862 Roo.Component.AUTO_ID = 1000;
21863
21864 Roo.extend(Roo.Component, Roo.util.Observable, {
21865     /**
21866      * @property {Boolean} hidden
21867      * true if this component is hidden. Read-only.
21868      */
21869     hidden : false,
21870     /**
21871      * true if this component is disabled. Read-only.
21872      */
21873     disabled : false,
21874     /**
21875      * true if this component has been rendered. Read-only.
21876      */
21877     rendered : false,
21878     
21879     /** @cfg {String} disableClass
21880      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21881      */
21882     disabledClass : "x-item-disabled",
21883         /** @cfg {Boolean} allowDomMove
21884          * Whether the component can move the Dom node when rendering (defaults to true).
21885          */
21886     allowDomMove : true,
21887     /** @cfg {String} hideMode
21888      * How this component should hidden. Supported values are
21889      * "visibility" (css visibility), "offsets" (negative offset position) and
21890      * "display" (css display) - defaults to "display".
21891      */
21892     hideMode: 'display',
21893
21894     // private
21895     ctype : "Roo.Component",
21896
21897     /** @cfg {String} actionMode 
21898      * which property holds the element that used for  hide() / show() / disable() / enable()
21899      * default is 'el' 
21900      */
21901     actionMode : "el",
21902
21903     // private
21904     getActionEl : function(){
21905         return  this[this.actionMode];
21906     },
21907
21908     initComponent : Roo.emptyFn,
21909     /**
21910      * If this is a lazy rendering component, render it to its container element.
21911      * @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.
21912      */
21913     render : function(B, C){
21914         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21915             if(!B && this.el){
21916                 this.el = Roo.get(this.el);
21917                 B = this.el.dom.parentNode;
21918                 this.allowDomMove = false;
21919             }
21920
21921             this.container = Roo.get(B);
21922             this.rendered = true;
21923             if(C !== undefined){
21924                 if(typeof  C == 'number'){
21925                     C = this.container.dom.childNodes[C];
21926                 }else {
21927                     C = Roo.getDom(C);
21928                 }
21929             }
21930
21931             this.onRender(this.container, C || null);
21932             if(this.cls){
21933                 this.el.addClass(this.cls);
21934                 delete  this.cls;
21935             }
21936             if(this.style){
21937                 this.el.applyStyles(this.style);
21938                 delete  this.style;
21939             }
21940
21941             this.fireEvent("render", this);
21942             this.afterRender(this.container);
21943             if(this.hidden){
21944                 this.hide();
21945             }
21946             if(this.disabled){
21947                 this.disable();
21948             }
21949         }
21950         return  this;
21951     },
21952
21953     // private
21954     // default function is not really useful
21955     onRender : function(ct, D){
21956         if(this.el){
21957             this.el = Roo.get(this.el);
21958             if(this.allowDomMove !== false){
21959                 ct.dom.insertBefore(this.el.dom, D);
21960             }
21961         }
21962     },
21963
21964     // private
21965     getAutoCreate : function(){
21966         var  E = typeof  this.autoCreate == "object" ?
21967                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21968         if(this.id && !E.id){
21969             E.id = this.id;
21970         }
21971         return  E;
21972     },
21973
21974     // private
21975     afterRender : Roo.emptyFn,
21976
21977     /**
21978      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21979      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21980      */
21981     destroy : function(){
21982         if(this.fireEvent("beforedestroy", this) !== false){
21983             this.purgeListeners();
21984             this.beforeDestroy();
21985             if(this.rendered){
21986                 this.el.removeAllListeners();
21987                 this.el.remove();
21988                 if(this.actionMode == "container"){
21989                     this.container.remove();
21990                 }
21991             }
21992
21993             this.onDestroy();
21994             Roo.ComponentMgr.unregister(this);
21995             this.fireEvent("destroy", this);
21996         }
21997     },
21998
21999         // private
22000     beforeDestroy : function(){
22001
22002     },
22003
22004         // private
22005         onDestroy : function(){
22006
22007     },
22008
22009     /**
22010      * Returns the underlying {@link Roo.Element}.
22011      * @return {Roo.Element} The element
22012      */
22013     getEl : function(){
22014         return  this.el;
22015     },
22016
22017     /**
22018      * Returns the id of this component.
22019      * @return {String}
22020      */
22021     getId : function(){
22022         return  this.id;
22023     },
22024
22025     /**
22026      * Try to focus this component.
22027      * @param {Boolean} selectText True to also select the text in this component (if applicable)
22028      * @return {Roo.Component} this
22029      */
22030     focus : function(F){
22031         if(this.rendered){
22032             this.el.focus();
22033             if(F === true){
22034                 this.el.dom.select();
22035             }
22036         }
22037         return  this;
22038     },
22039
22040     // private
22041     blur : function(){
22042         if(this.rendered){
22043             this.el.blur();
22044         }
22045         return  this;
22046     },
22047
22048     /**
22049      * Disable this component.
22050      * @return {Roo.Component} this
22051      */
22052     disable : function(){
22053         if(this.rendered){
22054             this.onDisable();
22055         }
22056
22057         this.disabled = true;
22058         this.fireEvent("disable", this);
22059         return  this;
22060     },
22061
22062         // private
22063     onDisable : function(){
22064         this.getActionEl().addClass(this.disabledClass);
22065         this.el.dom.disabled = true;
22066     },
22067
22068     /**
22069      * Enable this component.
22070      * @return {Roo.Component} this
22071      */
22072     enable : function(){
22073         if(this.rendered){
22074             this.onEnable();
22075         }
22076
22077         this.disabled = false;
22078         this.fireEvent("enable", this);
22079         return  this;
22080     },
22081
22082         // private
22083     onEnable : function(){
22084         this.getActionEl().removeClass(this.disabledClass);
22085         this.el.dom.disabled = false;
22086     },
22087
22088     /**
22089      * Convenience function for setting disabled/enabled by boolean.
22090      * @param {Boolean} disabled
22091      */
22092     setDisabled : function(G){
22093         this[G ? "disable" : "enable"]();
22094     },
22095
22096     /**
22097      * Show this component.
22098      * @return {Roo.Component} this
22099      */
22100     show: function(){
22101         if(this.fireEvent("beforeshow", this) !== false){
22102             this.hidden = false;
22103             if(this.rendered){
22104                 this.onShow();
22105             }
22106
22107             this.fireEvent("show", this);
22108         }
22109         return  this;
22110     },
22111
22112     // private
22113     onShow : function(){
22114         var  ae = this.getActionEl();
22115         if(this.hideMode == 'visibility'){
22116             ae.dom.style.visibility = "visible";
22117         }else  if(this.hideMode == 'offsets'){
22118             ae.removeClass('x-hidden');
22119         }else {
22120             ae.dom.style.display = "";
22121         }
22122     },
22123
22124     /**
22125      * Hide this component.
22126      * @return {Roo.Component} this
22127      */
22128     hide: function(){
22129         if(this.fireEvent("beforehide", this) !== false){
22130             this.hidden = true;
22131             if(this.rendered){
22132                 this.onHide();
22133             }
22134
22135             this.fireEvent("hide", this);
22136         }
22137         return  this;
22138     },
22139
22140     // private
22141     onHide : function(){
22142         var  ae = this.getActionEl();
22143         if(this.hideMode == 'visibility'){
22144             ae.dom.style.visibility = "hidden";
22145         }else  if(this.hideMode == 'offsets'){
22146             ae.addClass('x-hidden');
22147         }else {
22148             ae.dom.style.display = "none";
22149         }
22150     },
22151
22152     /**
22153      * Convenience function to hide or show this component by boolean.
22154      * @param {Boolean} visible True to show, false to hide
22155      * @return {Roo.Component} this
22156      */
22157     setVisible: function(H){
22158         if(H) {
22159             this.show();
22160         }else {
22161             this.hide();
22162         }
22163         return  this;
22164     },
22165
22166     /**
22167      * Returns true if this component is visible.
22168      */
22169     isVisible : function(){
22170         return  this.getActionEl().isVisible();
22171     },
22172
22173     cloneConfig : function(I){
22174         I = I || {};
22175         var  id = I.id || Roo.id();
22176         var  J = Roo.applyIf(I, this.initialConfig);
22177         J.id = id; // prevent dup id
22178         return  new  this.constructor(J);
22179     }
22180 });
22181 /*
22182  * Based on:
22183  * Ext JS Library 1.1.1
22184  * Copyright(c) 2006-2007, Ext JS, LLC.
22185  *
22186  * Originally Released Under LGPL - original licence link has changed is not relivant.
22187  *
22188  * Fork - LGPL
22189  * <script type="text/javascript">
22190  */
22191  (function(){ 
22192 /**
22193  * @class Roo.Layer
22194  * @extends Roo.Element
22195  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22196  * automatic maintaining of shadow/shim positions.
22197  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22198  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22199  * you can pass a string with a CSS class name. False turns off the shadow.
22200  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22201  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22202  * @cfg {String} cls CSS class to add to the element
22203  * @cfg {Number} zindex Starting z-index (defaults to 11000)
22204  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22205  * @constructor
22206  * @param {Object} config An object with config options.
22207  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22208  */
22209
22210 Roo.Layer = function(C, D){
22211     C = C || {};
22212     var  dh = Roo.DomHelper;
22213     var  cp = C.parentEl, E = cp ? Roo.getDom(cp) : document.body;
22214     if(D){
22215         this.dom = Roo.getDom(D);
22216     }
22217     if(!this.dom){
22218         var  o = C.dh || {tag: "div", cls: "x-layer"};
22219         this.dom = dh.append(E, o);
22220     }
22221     if(C.cls){
22222         this.addClass(C.cls);
22223     }
22224
22225     this.constrain = C.constrain !== false;
22226     this.visibilityMode = Roo.Element.VISIBILITY;
22227     if(C.id){
22228         this.id = this.dom.id = C.id;
22229     }else {
22230         this.id = Roo.id(this.dom);
22231     }
22232
22233     this.zindex = C.zindex || this.getZIndex();
22234     this.position("absolute", this.zindex);
22235     if(C.shadow){
22236         this.shadowOffset = C.shadowOffset || 4;
22237         this.shadow = new  Roo.Shadow({
22238             offset : this.shadowOffset,
22239             mode : C.shadow
22240         });
22241     }else {
22242         this.shadowOffset = 0;
22243     }
22244
22245     this.useShim = C.shim !== false && Roo.useShims;
22246     this.useDisplay = C.useDisplay;
22247     this.hide();
22248 };
22249
22250 var  A = Roo.Element.prototype;
22251
22252 // shims are shared among layer to keep from having 100 iframes
22253 var  B = [];
22254
22255 Roo.extend(Roo.Layer, Roo.Element, {
22256
22257     getZIndex : function(){
22258         return  this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22259     },
22260
22261     getShim : function(){
22262         if(!this.useShim){
22263             return  null;
22264         }
22265         if(this.shim){
22266             return  this.shim;
22267         }
22268         var  C = B.shift();
22269         if(!C){
22270             C = this.createShim();
22271             C.enableDisplayMode('block');
22272             C.dom.style.display = 'none';
22273             C.dom.style.visibility = 'visible';
22274         }
22275         var  pn = this.dom.parentNode;
22276         if(C.dom.parentNode != pn){
22277             pn.insertBefore(C.dom, this.dom);
22278         }
22279
22280         C.setStyle('z-index', this.getZIndex()-2);
22281         this.shim = C;
22282         return  C;
22283     },
22284
22285     hideShim : function(){
22286         if(this.shim){
22287             this.shim.setDisplayed(false);
22288             B.push(this.shim);
22289             delete  this.shim;
22290         }
22291     },
22292
22293     disableShadow : function(){
22294         if(this.shadow){
22295             this.shadowDisabled = true;
22296             this.shadow.hide();
22297             this.lastShadowOffset = this.shadowOffset;
22298             this.shadowOffset = 0;
22299         }
22300     },
22301
22302     enableShadow : function(D){
22303         if(this.shadow){
22304             this.shadowDisabled = false;
22305             this.shadowOffset = this.lastShadowOffset;
22306             delete  this.lastShadowOffset;
22307             if(D){
22308                 this.sync(true);
22309             }
22310         }
22311     },
22312
22313     // private
22314     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22315     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22316     sync : function(E){
22317         var  sw = this.shadow;
22318         if(!this.updating && this.isVisible() && (sw || this.useShim)){
22319             var  sh = this.getShim();
22320
22321             var  w = this.getWidth(),
22322                 h = this.getHeight();
22323
22324             var  l = this.getLeft(true),
22325                 t = this.getTop(true);
22326
22327             if(sw && !this.shadowDisabled){
22328                 if(E && !sw.isVisible()){
22329                     sw.show(this);
22330                 }else {
22331                     sw.realign(l, t, w, h);
22332                 }
22333                 if(sh){
22334                     if(E){
22335                        sh.show();
22336                     }
22337                     // fit the shim behind the shadow, so it is shimmed too
22338                     var  a = sw.adjusts, s = sh.dom.style;
22339                     s.left = (Math.min(l, l+a.l))+"px";
22340                     s.top = (Math.min(t, t+a.t))+"px";
22341                     s.width = (w+a.w)+"px";
22342                     s.height = (h+a.h)+"px";
22343                 }
22344             }else  if(sh){
22345                 if(E){
22346                    sh.show();
22347                 }
22348
22349                 sh.setSize(w, h);
22350                 sh.setLeftTop(l, t);
22351             }
22352             
22353         }
22354     },
22355
22356     // private
22357     destroy : function(){
22358         this.hideShim();
22359         if(this.shadow){
22360             this.shadow.hide();
22361         }
22362
22363         this.removeAllListeners();
22364         var  pn = this.dom.parentNode;
22365         if(pn){
22366             pn.removeChild(this.dom);
22367         }
22368
22369         Roo.Element.uncache(this.id);
22370     },
22371
22372     remove : function(){
22373         this.destroy();
22374     },
22375
22376     // private
22377     beginUpdate : function(){
22378         this.updating = true;
22379     },
22380
22381     // private
22382     endUpdate : function(){
22383         this.updating = false;
22384         this.sync(true);
22385     },
22386
22387     // private
22388     hideUnders : function(F){
22389         if(this.shadow){
22390             this.shadow.hide();
22391         }
22392
22393         this.hideShim();
22394     },
22395
22396     // private
22397     constrainXY : function(){
22398         if(this.constrain){
22399             var  vw = Roo.lib.Dom.getViewWidth(),
22400                 vh = Roo.lib.Dom.getViewHeight();
22401             var  s = Roo.get(document).getScroll();
22402
22403             var  xy = this.getXY();
22404             var  x = xy[0], y = xy[1];   
22405             var  w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22406             // only move it if it needs it
22407             var  moved = false;
22408             // first validate right/bottom
22409             if((x + w) > vw+s.left){
22410                 x = vw - w - this.shadowOffset;
22411                 moved = true;
22412             }
22413             if((y + h) > vh+s.top){
22414                 y = vh - h - this.shadowOffset;
22415                 moved = true;
22416             }
22417             // then make sure top/left isn't negative
22418             if(x < s.left){
22419                 x = s.left;
22420                 moved = true;
22421             }
22422             if(y < s.top){
22423                 y = s.top;
22424                 moved = true;
22425             }
22426             if(moved){
22427                 if(this.avoidY){
22428                     var  ay = this.avoidY;
22429                     if(y <= ay && (y+h) >= ay){
22430                         y = ay-h-5;   
22431                     }
22432                 }
22433
22434                 xy = [x, y];
22435                 this.storeXY(xy);
22436                 A.setXY.call(this, xy);
22437                 this.sync();
22438             }
22439         }
22440     },
22441
22442     isVisible : function(){
22443         return  this.visible;    
22444     },
22445
22446     // private
22447     showAction : function(){
22448         this.visible = true; // track visibility to prevent getStyle calls
22449         if(this.useDisplay === true){
22450             this.setDisplayed("");
22451         }else  if(this.lastXY){
22452             A.setXY.call(this, this.lastXY);
22453         }else  if(this.lastLT){
22454             A.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22455         }
22456     },
22457
22458     // private
22459     hideAction : function(){
22460         this.visible = false;
22461         if(this.useDisplay === true){
22462             this.setDisplayed(false);
22463         }else {
22464             this.setLeftTop(-10000,-10000);
22465         }
22466     },
22467
22468     // overridden Element method
22469     setVisible : function(v, a, d, c, e){
22470         if(v){
22471             this.showAction();
22472         }
22473         if(a && v){
22474             var  cb = function(){
22475                 this.sync(true);
22476                 if(c){
22477                     c();
22478                 }
22479             }.createDelegate(this);
22480             A.setVisible.call(this, true, true, d, cb, e);
22481         }else {
22482             if(!v){
22483                 this.hideUnders(true);
22484             }
22485             var  cb = c;
22486             if(a){
22487                 cb = function(){
22488                     this.hideAction();
22489                     if(c){
22490                         c();
22491                     }
22492                 }.createDelegate(this);
22493             }
22494
22495             A.setVisible.call(this, v, a, d, cb, e);
22496             if(v){
22497                 this.sync(true);
22498             }else  if(!a){
22499                 this.hideAction();
22500             }
22501         }
22502     },
22503
22504     storeXY : function(xy){
22505         delete  this.lastLT;
22506         this.lastXY = xy;
22507     },
22508
22509     storeLeftTop : function(G, H){
22510         delete  this.lastXY;
22511         this.lastLT = [G, H];
22512     },
22513
22514     // private
22515     beforeFx : function(){
22516         this.beforeAction();
22517         return  Roo.Layer.superclass.beforeFx.apply(this, arguments);
22518     },
22519
22520     // private
22521     afterFx : function(){
22522         Roo.Layer.superclass.afterFx.apply(this, arguments);
22523         this.sync(this.isVisible());
22524     },
22525
22526     // private
22527     beforeAction : function(){
22528         if(!this.updating && this.shadow){
22529             this.shadow.hide();
22530         }
22531     },
22532
22533     // overridden Element method
22534     setLeft : function(I){
22535         this.storeLeftTop(I, this.getTop(true));
22536         A.setLeft.apply(this, arguments);
22537         this.sync();
22538     },
22539
22540     setTop : function(J){
22541         this.storeLeftTop(this.getLeft(true), J);
22542         A.setTop.apply(this, arguments);
22543         this.sync();
22544     },
22545
22546     setLeftTop : function(K, L){
22547         this.storeLeftTop(K, L);
22548         A.setLeftTop.apply(this, arguments);
22549         this.sync();
22550     },
22551
22552     setXY : function(xy, a, d, c, e){
22553         this.fixDisplay();
22554         this.beforeAction();
22555         this.storeXY(xy);
22556         var  cb = this.createCB(c);
22557         A.setXY.call(this, xy, a, d, cb, e);
22558         if(!a){
22559             cb();
22560         }
22561     },
22562
22563     // private
22564     createCB : function(c){
22565         var  el = this;
22566         return  function(){
22567             el.constrainXY();
22568             el.sync(true);
22569             if(c){
22570                 c();
22571             }
22572         };
22573     },
22574
22575     // overridden Element method
22576     setX : function(x, a, d, c, e){
22577         this.setXY([x, this.getY()], a, d, c, e);
22578     },
22579
22580     // overridden Element method
22581     setY : function(y, a, d, c, e){
22582         this.setXY([this.getX(), y], a, d, c, e);
22583     },
22584
22585     // overridden Element method
22586     setSize : function(w, h, a, d, c, e){
22587         this.beforeAction();
22588         var  cb = this.createCB(c);
22589         A.setSize.call(this, w, h, a, d, cb, e);
22590         if(!a){
22591             cb();
22592         }
22593     },
22594
22595     // overridden Element method
22596     setWidth : function(w, a, d, c, e){
22597         this.beforeAction();
22598         var  cb = this.createCB(c);
22599         A.setWidth.call(this, w, a, d, cb, e);
22600         if(!a){
22601             cb();
22602         }
22603     },
22604
22605     // overridden Element method
22606     setHeight : function(h, a, d, c, e){
22607         this.beforeAction();
22608         var  cb = this.createCB(c);
22609         A.setHeight.call(this, h, a, d, cb, e);
22610         if(!a){
22611             cb();
22612         }
22613     },
22614
22615     // overridden Element method
22616     setBounds : function(x, y, w, h, a, d, c, e){
22617         this.beforeAction();
22618         var  cb = this.createCB(c);
22619         if(!a){
22620             this.storeXY([x, y]);
22621             A.setXY.call(this, [x, y]);
22622             A.setSize.call(this, w, h, a, d, cb, e);
22623             cb();
22624         }else {
22625             A.setBounds.call(this, x, y, w, h, a, d, cb, e);
22626         }
22627         return  this;
22628     },
22629     
22630     /**
22631      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22632      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22633      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22634      * @param {Number} zindex The new z-index to set
22635      * @return {this} The Layer
22636      */
22637     setZIndex : function(M){
22638         this.zindex = M;
22639         this.setStyle("z-index", M + 2);
22640         if(this.shadow){
22641             this.shadow.setZIndex(M + 1);
22642         }
22643         if(this.shim){
22644             this.shim.setStyle("z-index", M);
22645         }
22646     }
22647 });
22648 })();
22649 /*
22650  * Based on:
22651  * Ext JS Library 1.1.1
22652  * Copyright(c) 2006-2007, Ext JS, LLC.
22653  *
22654  * Originally Released Under LGPL - original licence link has changed is not relivant.
22655  *
22656  * Fork - LGPL
22657  * <script type="text/javascript">
22658  */
22659
22660
22661 /**
22662  * @class Roo.Shadow
22663  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
22664  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
22665  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22666  * @constructor
22667  * Create a new Shadow
22668  * @param {Object} config The config object
22669  */
22670 Roo.Shadow = function(A){
22671     Roo.apply(this, A);
22672     if(typeof  this.mode != "string"){
22673         this.mode = this.defaultMode;
22674     }
22675     var  o = this.offset, a = {h: 0};
22676     var  B = Math.floor(this.offset/2);
22677     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22678         case  "drop":
22679             a.w = 0;
22680             a.l = a.t = o;
22681             a.t -= 1;
22682             if(Roo.isIE){
22683                 a.l -= this.offset + B;
22684                 a.t -= this.offset + B;
22685                 a.w -= B;
22686                 a.h -= B;
22687                 a.t += 1;
22688             }
22689         break;
22690         case  "sides":
22691             a.w = (o*2);
22692             a.l = -o;
22693             a.t = o-1;
22694             if(Roo.isIE){
22695                 a.l -= (this.offset - B);
22696                 a.t -= this.offset + B;
22697                 a.l += 1;
22698                 a.w -= (this.offset - B)*2;
22699                 a.w -= B + 1;
22700                 a.h -= 1;
22701             }
22702         break;
22703         case  "frame":
22704             a.w = a.h = (o*2);
22705             a.l = a.t = -o;
22706             a.t += 1;
22707             a.h -= 2;
22708             if(Roo.isIE){
22709                 a.l -= (this.offset - B);
22710                 a.t -= (this.offset - B);
22711                 a.l += 1;
22712                 a.w -= (this.offset + B + 1);
22713                 a.h -= (this.offset + B);
22714                 a.h += 1;
22715             }
22716         break;
22717     };
22718
22719     this.adjusts = a;
22720 };
22721
22722 Roo.Shadow.prototype = {
22723     /**
22724      * @cfg {String} mode
22725      * The shadow display mode.  Supports the following options:<br />
22726      * sides: Shadow displays on both sides and bottom only<br />
22727      * frame: Shadow displays equally on all four sides<br />
22728      * drop: Traditional bottom-right drop shadow (default)
22729      */
22730     /**
22731      * @cfg {String} offset
22732      * The number of pixels to offset the shadow from the element (defaults to 4)
22733      */
22734     offset: 4,
22735
22736     // private
22737     defaultMode: "drop",
22738
22739     /**
22740      * Displays the shadow under the target element
22741      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22742      */
22743     show : function(C){
22744         C = Roo.get(C);
22745         if(!this.el){
22746             this.el = Roo.Shadow.Pool.pull();
22747             if(this.el.dom.nextSibling != C.dom){
22748                 this.el.insertBefore(C);
22749             }
22750         }
22751
22752         this.el.setStyle("z-index", this.zIndex || parseInt(C.getStyle("z-index"), 10)-1);
22753         if(Roo.isIE){
22754             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22755         }
22756
22757         this.realign(
22758             C.getLeft(true),
22759             C.getTop(true),
22760             C.getWidth(),
22761             C.getHeight()
22762         );
22763         this.el.dom.style.display = "block";
22764     },
22765
22766     /**
22767      * Returns true if the shadow is visible, else false
22768      */
22769     isVisible : function(){
22770         return  this.el ? true : false;  
22771     },
22772
22773     /**
22774      * Direct alignment when values are already available. Show must be called at least once before
22775      * calling this method to ensure it is initialized.
22776      * @param {Number} left The target element left position
22777      * @param {Number} top The target element top position
22778      * @param {Number} width The target element width
22779      * @param {Number} height The target element height
22780      */
22781     realign : function(l, t, w, h){
22782         if(!this.el){
22783             return;
22784         }
22785         var  a = this.adjusts, d = this.el.dom, s = d.style;
22786         var  D = 0;
22787         s.left = (l+a.l)+"px";
22788         s.top = (t+a.t)+"px";
22789         var  sw = (w+a.w), sh = (h+a.h), E = sw +"px", F = sh + "px";
22790         if(s.width != E || s.height != F){
22791             s.width = E;
22792             s.height = F;
22793             if(!Roo.isIE){
22794                 var  cn = d.childNodes;
22795                 var  sww = Math.max(0, (sw-12))+"px";
22796                 cn[0].childNodes[1].style.width = sww;
22797                 cn[1].childNodes[1].style.width = sww;
22798                 cn[2].childNodes[1].style.width = sww;
22799                 cn[1].style.height = Math.max(0, (sh-12))+"px";
22800             }
22801         }
22802     },
22803
22804     /**
22805      * Hides this shadow
22806      */
22807     hide : function(){
22808         if(this.el){
22809             this.el.dom.style.display = "none";
22810             Roo.Shadow.Pool.push(this.el);
22811             delete  this.el;
22812         }
22813     },
22814
22815     /**
22816      * Adjust the z-index of this shadow
22817      * @param {Number} zindex The new z-index
22818      */
22819     setZIndex : function(z){
22820         this.zIndex = z;
22821         if(this.el){
22822             this.el.setStyle("z-index", z);
22823         }
22824     }
22825 };
22826
22827 // Private utility class that manages the internal Shadow cache
22828 Roo.Shadow.Pool = function(){
22829     var  p = [];
22830     var  G = Roo.isIE ?
22831                  '<div class="x-ie-shadow"></div>' :
22832                  '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
22833     return  {
22834         pull : function(){
22835             var  sh = p.shift();
22836             if(!sh){
22837                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, G));
22838                 sh.autoBoxAdjust = false;
22839             }
22840             return  sh;
22841         },
22842
22843         push : function(sh){
22844             p.push(sh);
22845         }
22846     };
22847 }();
22848 /*
22849  * Based on:
22850  * Ext JS Library 1.1.1
22851  * Copyright(c) 2006-2007, Ext JS, LLC.
22852  *
22853  * Originally Released Under LGPL - original licence link has changed is not relivant.
22854  *
22855  * Fork - LGPL
22856  * <script type="text/javascript">
22857  */
22858
22859 /**
22860  * @class Roo.BoxComponent
22861  * @extends Roo.Component
22862  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
22863  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
22864  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22865  * layout containers.
22866  * @constructor
22867  * @param {Roo.Element/String/Object} config The configuration options.
22868  */
22869 Roo.BoxComponent = function(A){
22870     Roo.Component.call(this, A);
22871     this.addEvents({
22872         /**
22873          * @event resize
22874          * Fires after the component is resized.
22875              * @param {Roo.Component} this
22876              * @param {Number} adjWidth The box-adjusted width that was set
22877              * @param {Number} adjHeight The box-adjusted height that was set
22878              * @param {Number} rawWidth The width that was originally specified
22879              * @param {Number} rawHeight The height that was originally specified
22880              */
22881         resize : true,
22882         /**
22883          * @event move
22884          * Fires after the component is moved.
22885              * @param {Roo.Component} this
22886              * @param {Number} x The new x position
22887              * @param {Number} y The new y position
22888              */
22889         move : true
22890     });
22891 };
22892
22893 Roo.extend(Roo.BoxComponent, Roo.Component, {
22894     // private, set in afterRender to signify that the component has been rendered
22895     boxReady : false,
22896     // private, used to defer height settings to subclasses
22897     deferHeight: false,
22898     /** @cfg {Number} width
22899      * width (optional) size of component
22900      */
22901      /** @cfg {Number} height
22902      * height (optional) size of component
22903      */
22904      
22905     /**
22906      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
22907      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22908      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22909      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22910      * @return {Roo.BoxComponent} this
22911      */
22912     setSize : function(w, h){
22913         // support for standard size objects
22914         if(typeof  w == 'object'){
22915             h = w.height;
22916             w = w.width;
22917         }
22918         // not rendered
22919         if(!this.boxReady){
22920             this.width = w;
22921             this.height = h;
22922             return  this;
22923         }
22924
22925         // prevent recalcs when not needed
22926         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22927             return  this;
22928         }
22929
22930         this.lastSize = {width: w, height: h};
22931
22932         var  B = this.adjustSize(w, h);
22933         var  aw = B.width, ah = B.height;
22934         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22935             var  rz = this.getResizeEl();
22936             if(!this.deferHeight && aw !== undefined && ah !== undefined){
22937                 rz.setSize(aw, ah);
22938             }else  if(!this.deferHeight && ah !== undefined){
22939                 rz.setHeight(ah);
22940             }else  if(aw !== undefined){
22941                 rz.setWidth(aw);
22942             }
22943
22944             this.onResize(aw, ah, w, h);
22945             this.fireEvent('resize', this, aw, ah, w, h);
22946         }
22947         return  this;
22948     },
22949
22950     /**
22951      * Gets the current size of the component's underlying element.
22952      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22953      */
22954     getSize : function(){
22955         return  this.el.getSize();
22956     },
22957
22958     /**
22959      * Gets the current XY position of the component's underlying element.
22960      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22961      * @return {Array} The XY position of the element (e.g., [100, 200])
22962      */
22963     getPosition : function(C){
22964         if(C === true){
22965             return  [this.el.getLeft(true), this.el.getTop(true)];
22966         }
22967         return  this.xy || this.el.getXY();
22968     },
22969
22970     /**
22971      * Gets the current box measurements of the component's underlying element.
22972      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22973      * @returns {Object} box An object in the format {x, y, width, height}
22974      */
22975     getBox : function(D){
22976         var  s = this.el.getSize();
22977         if(D){
22978             s.x = this.el.getLeft(true);
22979             s.y = this.el.getTop(true);
22980         }else {
22981             var  xy = this.xy || this.el.getXY();
22982             s.x = xy[0];
22983             s.y = xy[1];
22984         }
22985         return  s;
22986     },
22987
22988     /**
22989      * Sets the current box measurements of the component's underlying element.
22990      * @param {Object} box An object in the format {x, y, width, height}
22991      * @returns {Roo.BoxComponent} this
22992      */
22993     updateBox : function(E){
22994         this.setSize(E.width, E.height);
22995         this.setPagePosition(E.x, E.y);
22996         return  this;
22997     },
22998
22999     // protected
23000     getResizeEl : function(){
23001         return  this.resizeEl || this.el;
23002     },
23003
23004     // protected
23005     getPositionEl : function(){
23006         return  this.positionEl || this.el;
23007     },
23008
23009     /**
23010      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
23011      * This method fires the move event.
23012      * @param {Number} left The new left
23013      * @param {Number} top The new top
23014      * @returns {Roo.BoxComponent} this
23015      */
23016     setPosition : function(x, y){
23017         this.x = x;
23018         this.y = y;
23019         if(!this.boxReady){
23020             return  this;
23021         }
23022         var  F = this.adjustPosition(x, y);
23023         var  ax = F.x, ay = F.y;
23024
23025         var  el = this.getPositionEl();
23026         if(ax !== undefined || ay !== undefined){
23027             if(ax !== undefined && ay !== undefined){
23028                 el.setLeftTop(ax, ay);
23029             }else  if(ax !== undefined){
23030                 el.setLeft(ax);
23031             }else  if(ay !== undefined){
23032                 el.setTop(ay);
23033             }
23034
23035             this.onPosition(ax, ay);
23036             this.fireEvent('move', this, ax, ay);
23037         }
23038         return  this;
23039     },
23040
23041     /**
23042      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
23043      * This method fires the move event.
23044      * @param {Number} x The new x position
23045      * @param {Number} y The new y position
23046      * @returns {Roo.BoxComponent} this
23047      */
23048     setPagePosition : function(x, y){
23049         this.pageX = x;
23050         this.pageY = y;
23051         if(!this.boxReady){
23052             return;
23053         }
23054         if(x === undefined || y === undefined){ // cannot translate undefined points
23055             return;
23056         }
23057         var  p = this.el.translatePoints(x, y);
23058         this.setPosition(p.left, p.top);
23059         return  this;
23060     },
23061
23062     // private
23063     onRender : function(ct, G){
23064         Roo.BoxComponent.superclass.onRender.call(this, ct, G);
23065         if(this.resizeEl){
23066             this.resizeEl = Roo.get(this.resizeEl);
23067         }
23068         if(this.positionEl){
23069             this.positionEl = Roo.get(this.positionEl);
23070         }
23071     },
23072
23073     // private
23074     afterRender : function(){
23075         Roo.BoxComponent.superclass.afterRender.call(this);
23076         this.boxReady = true;
23077         this.setSize(this.width, this.height);
23078         if(this.x || this.y){
23079             this.setPosition(this.x, this.y);
23080         }
23081         if(this.pageX || this.pageY){
23082             this.setPagePosition(this.pageX, this.pageY);
23083         }
23084     },
23085
23086     /**
23087      * Force the component's size to recalculate based on the underlying element's current height and width.
23088      * @returns {Roo.BoxComponent} this
23089      */
23090     syncSize : function(){
23091         delete  this.lastSize;
23092         this.setSize(this.el.getWidth(), this.el.getHeight());
23093         return  this;
23094     },
23095
23096     /**
23097      * Called after the component is resized, this method is empty by default but can be implemented by any
23098      * subclass that needs to perform custom logic after a resize occurs.
23099      * @param {Number} adjWidth The box-adjusted width that was set
23100      * @param {Number} adjHeight The box-adjusted height that was set
23101      * @param {Number} rawWidth The width that was originally specified
23102      * @param {Number} rawHeight The height that was originally specified
23103      */
23104     onResize : function(H, I, J, K){
23105
23106     },
23107
23108     /**
23109      * Called after the component is moved, this method is empty by default but can be implemented by any
23110      * subclass that needs to perform custom logic after a move occurs.
23111      * @param {Number} x The new x position
23112      * @param {Number} y The new y position
23113      */
23114     onPosition : function(x, y){
23115
23116     },
23117
23118     // private
23119     adjustSize : function(w, h){
23120         if(this.autoWidth){
23121             w = 'auto';
23122         }
23123         if(this.autoHeight){
23124             h = 'auto';
23125         }
23126         return  {width : w, height: h};
23127     },
23128
23129     // private
23130     adjustPosition : function(x, y){
23131         return  {x : x, y: y};
23132     }
23133 });
23134 /*
23135  * Based on:
23136  * Ext JS Library 1.1.1
23137  * Copyright(c) 2006-2007, Ext JS, LLC.
23138  *
23139  * Originally Released Under LGPL - original licence link has changed is not relivant.
23140  *
23141  * Fork - LGPL
23142  * <script type="text/javascript">
23143  */
23144
23145
23146 /**
23147  * @class Roo.SplitBar
23148  * @extends Roo.util.Observable
23149  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23150  * <br><br>
23151  * Usage:
23152  * <pre><code>
23153 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23154                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23155 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23156 split.minSize = 100;
23157 split.maxSize = 600;
23158 split.animate = true;
23159 split.on('moved', splitterMoved);
23160 </code></pre>
23161  * @constructor
23162  * Create a new SplitBar
23163  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
23164  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
23165  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23166  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
23167                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23168                         position of the SplitBar).
23169  */
23170 Roo.SplitBar = function(A, B, C, D, E){
23171     
23172     /** @private */
23173     this.el = Roo.get(A, true);
23174     this.el.dom.unselectable = "on";
23175     /** @private */
23176     this.resizingEl = Roo.get(B, true);
23177
23178     /**
23179      * @private
23180      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23181      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23182      * @type Number
23183      */
23184     this.orientation = C || Roo.SplitBar.HORIZONTAL;
23185     
23186     /**
23187      * The minimum size of the resizing element. (Defaults to 0)
23188      * @type Number
23189      */
23190     this.minSize = 0;
23191     
23192     /**
23193      * The maximum size of the resizing element. (Defaults to 2000)
23194      * @type Number
23195      */
23196     this.maxSize = 2000;
23197     
23198     /**
23199      * Whether to animate the transition to the new size
23200      * @type Boolean
23201      */
23202     this.animate = false;
23203     
23204     /**
23205      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23206      * @type Boolean
23207      */
23208     this.useShim = false;
23209     
23210     /** @private */
23211     this.shim = null;
23212     
23213     if(!E){
23214         /** @private */
23215         this.proxy = Roo.SplitBar.createProxy(this.orientation);
23216     }else {
23217         this.proxy = Roo.get(E).dom;
23218     }
23219
23220     /** @private */
23221     this.dd = new  Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23222     
23223     /** @private */
23224     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23225     
23226     /** @private */
23227     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23228     
23229     /** @private */
23230     this.dragSpecs = {};
23231     
23232     /**
23233      * @private The adapter to use to positon and resize elements
23234      */
23235     this.adapter = new  Roo.SplitBar.BasicLayoutAdapter();
23236     this.adapter.init(this);
23237     
23238     if(this.orientation == Roo.SplitBar.HORIZONTAL){
23239         /** @private */
23240         this.placement = D || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23241         this.el.addClass("x-splitbar-h");
23242     }else {
23243         /** @private */
23244         this.placement = D || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23245         this.el.addClass("x-splitbar-v");
23246     }
23247
23248     
23249     this.addEvents({
23250         /**
23251          * @event resize
23252          * Fires when the splitter is moved (alias for {@link #event-moved})
23253          * @param {Roo.SplitBar} this
23254          * @param {Number} newSize the new width or height
23255          */
23256         "resize" : true,
23257         /**
23258          * @event moved
23259          * Fires when the splitter is moved
23260          * @param {Roo.SplitBar} this
23261          * @param {Number} newSize the new width or height
23262          */
23263         "moved" : true,
23264         /**
23265          * @event beforeresize
23266          * Fires before the splitter is dragged
23267          * @param {Roo.SplitBar} this
23268          */
23269         "beforeresize" : true,
23270
23271         "beforeapply" : true
23272     });
23273
23274     Roo.util.Observable.call(this);
23275 };
23276
23277 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23278     onStartProxyDrag : function(x, y){
23279         this.fireEvent("beforeresize", this);
23280         if(!this.overlay){
23281             var  o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
23282             o.unselectable();
23283             o.enableDisplayMode("block");
23284             // all splitbars share the same overlay
23285             Roo.SplitBar.prototype.overlay = o;
23286         }
23287
23288         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23289         this.overlay.show();
23290         Roo.get(this.proxy).setDisplayed("block");
23291         var  F = this.adapter.getElementSize(this);
23292         this.activeMinSize = this.getMinimumSize();;
23293         this.activeMaxSize = this.getMaximumSize();;
23294         var  c1 = F - this.activeMinSize;
23295         var  c2 = Math.max(this.activeMaxSize - F, 0);
23296         if(this.orientation == Roo.SplitBar.HORIZONTAL){
23297             this.dd.resetConstraints();
23298             this.dd.setXConstraint(
23299                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
23300                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23301             );
23302             this.dd.setYConstraint(0, 0);
23303         }else {
23304             this.dd.resetConstraints();
23305             this.dd.setXConstraint(0, 0);
23306             this.dd.setYConstraint(
23307                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
23308                 this.placement == Roo.SplitBar.TOP ? c2 : c1
23309             );
23310          }
23311
23312         this.dragSpecs.startSize = F;
23313         this.dragSpecs.startPoint = [x, y];
23314         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23315     },
23316     
23317     /** 
23318      * @private Called after the drag operation by the DDProxy
23319      */
23320     onEndProxyDrag : function(e){
23321         Roo.get(this.proxy).setDisplayed(false);
23322         var  G = Roo.lib.Event.getXY(e);
23323         if(this.overlay){
23324             this.overlay.hide();
23325         }
23326         var  H;
23327         if(this.orientation == Roo.SplitBar.HORIZONTAL){
23328             H = this.dragSpecs.startSize + 
23329                 (this.placement == Roo.SplitBar.LEFT ?
23330                     G[0] - this.dragSpecs.startPoint[0] :
23331                     this.dragSpecs.startPoint[0] - G[0]
23332                 );
23333         }else {
23334             H = this.dragSpecs.startSize + 
23335                 (this.placement == Roo.SplitBar.TOP ?
23336                     G[1] - this.dragSpecs.startPoint[1] :
23337                     this.dragSpecs.startPoint[1] - G[1]
23338                 );
23339         }
23340
23341         H = Math.min(Math.max(H, this.activeMinSize), this.activeMaxSize);
23342         if(H != this.dragSpecs.startSize){
23343             if(this.fireEvent('beforeapply', this, H) !== false){
23344                 this.adapter.setElementSize(this, H);
23345                 this.fireEvent("moved", this, H);
23346                 this.fireEvent("resize", this, H);
23347             }
23348         }
23349     },
23350     
23351     /**
23352      * Get the adapter this SplitBar uses
23353      * @return The adapter object
23354      */
23355     getAdapter : function(){
23356         return  this.adapter;
23357     },
23358     
23359     /**
23360      * Set the adapter this SplitBar uses
23361      * @param {Object} adapter A SplitBar adapter object
23362      */
23363     setAdapter : function(I){
23364         this.adapter = I;
23365         this.adapter.init(this);
23366     },
23367     
23368     /**
23369      * Gets the minimum size for the resizing element
23370      * @return {Number} The minimum size
23371      */
23372     getMinimumSize : function(){
23373         return  this.minSize;
23374     },
23375     
23376     /**
23377      * Sets the minimum size for the resizing element
23378      * @param {Number} minSize The minimum size
23379      */
23380     setMinimumSize : function(J){
23381         this.minSize = J;
23382     },
23383     
23384     /**
23385      * Gets the maximum size for the resizing element
23386      * @return {Number} The maximum size
23387      */
23388     getMaximumSize : function(){
23389         return  this.maxSize;
23390     },
23391     
23392     /**
23393      * Sets the maximum size for the resizing element
23394      * @param {Number} maxSize The maximum size
23395      */
23396     setMaximumSize : function(K){
23397         this.maxSize = K;
23398     },
23399     
23400     /**
23401      * Sets the initialize size for the resizing element
23402      * @param {Number} size The initial size
23403      */
23404     setCurrentSize : function(L){
23405         var  M = this.animate;
23406         this.animate = false;
23407         this.adapter.setElementSize(this, L);
23408         this.animate = M;
23409     },
23410     
23411     /**
23412      * Destroy this splitbar. 
23413      * @param {Boolean} removeEl True to remove the element
23414      */
23415     destroy : function(N){
23416         if(this.shim){
23417             this.shim.remove();
23418         }
23419
23420         this.dd.unreg();
23421         this.proxy.parentNode.removeChild(this.proxy);
23422         if(N){
23423             this.el.remove();
23424         }
23425     }
23426 });
23427
23428 /**
23429  * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
23430  */
23431 Roo.SplitBar.createProxy = function(O){
23432     var  P = new  Roo.Element(document.createElement("div"));
23433     P.unselectable();
23434     var  Q = 'x-splitbar-proxy';
23435     P.addClass(Q + ' ' + (O == Roo.SplitBar.HORIZONTAL ? Q +'-h' : Q + '-v'));
23436     document.body.appendChild(P.dom);
23437     return  P.dom;
23438 };
23439
23440 /** 
23441  * @class Roo.SplitBar.BasicLayoutAdapter
23442  * Default Adapter. It assumes the splitter and resizing element are not positioned
23443  * elements and only gets/sets the width of the element. Generally used for table based layouts.
23444  */
23445 Roo.SplitBar.BasicLayoutAdapter = function(){
23446 };
23447
23448 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23449     // do nothing for now
23450     init : function(s){
23451     
23452     },
23453     /**
23454      * Called before drag operations to get the current size of the resizing element. 
23455      * @param {Roo.SplitBar} s The SplitBar using this adapter
23456      */
23457      getElementSize : function(s){
23458         if(s.orientation == Roo.SplitBar.HORIZONTAL){
23459             return  s.resizingEl.getWidth();
23460         }else {
23461             return  s.resizingEl.getHeight();
23462         }
23463     },
23464     
23465     /**
23466      * Called after drag operations to set the size of the resizing element.
23467      * @param {Roo.SplitBar} s The SplitBar using this adapter
23468      * @param {Number} newSize The new size to set
23469      * @param {Function} onComplete A function to be invoked when resizing is complete
23470      */
23471     setElementSize : function(s, R, S){
23472         if(s.orientation == Roo.SplitBar.HORIZONTAL){
23473             if(!s.animate){
23474                 s.resizingEl.setWidth(R);
23475                 if(S){
23476                     S(s, R);
23477                 }
23478             }else {
23479                 s.resizingEl.setWidth(R, true, .1, S, 'easeOut');
23480             }
23481         }else {
23482             
23483             if(!s.animate){
23484                 s.resizingEl.setHeight(R);
23485                 if(S){
23486                     S(s, R);
23487                 }
23488             }else {
23489                 s.resizingEl.setHeight(R, true, .1, S, 'easeOut');
23490             }
23491         }
23492     }
23493 };
23494
23495 /** 
23496  *@class Roo.SplitBar.AbsoluteLayoutAdapter
23497  * @extends Roo.SplitBar.BasicLayoutAdapter
23498  * Adapter that  moves the splitter element to align with the resized sizing element. 
23499  * Used with an absolute positioned SplitBar.
23500  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23501  * document.body, make sure you assign an id to the body element.
23502  */
23503 Roo.SplitBar.AbsoluteLayoutAdapter = function(T){
23504     this.basic = new  Roo.SplitBar.BasicLayoutAdapter();
23505     this.container = Roo.get(T);
23506 };
23507
23508 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23509     init : function(s){
23510         this.basic.init(s);
23511     },
23512     
23513     getElementSize : function(s){
23514         return  this.basic.getElementSize(s);
23515     },
23516     
23517     setElementSize : function(s, U, V){
23518         this.basic.setElementSize(s, U, this.moveSplitter.createDelegate(this, [s]));
23519     },
23520     
23521     moveSplitter : function(s){
23522         var  W = Roo.SplitBar;
23523         switch(s.placement){
23524             case  W.LEFT:
23525                 s.el.setX(s.resizingEl.getRight());
23526                 break;
23527             case  W.RIGHT:
23528                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23529                 break;
23530             case  W.TOP:
23531                 s.el.setY(s.resizingEl.getBottom());
23532                 break;
23533             case  W.BOTTOM:
23534                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23535                 break;
23536         }
23537     }
23538 };
23539
23540 /**
23541  * Orientation constant - Create a vertical SplitBar
23542  * @static
23543  * @type Number
23544  */
23545 Roo.SplitBar.VERTICAL = 1;
23546
23547 /**
23548  * Orientation constant - Create a horizontal SplitBar
23549  * @static
23550  * @type Number
23551  */
23552 Roo.SplitBar.HORIZONTAL = 2;
23553
23554 /**
23555  * Placement constant - The resizing element is to the left of the splitter element
23556  * @static
23557  * @type Number
23558  */
23559 Roo.SplitBar.LEFT = 1;
23560
23561 /**
23562  * Placement constant - The resizing element is to the right of the splitter element
23563  * @static
23564  * @type Number
23565  */
23566 Roo.SplitBar.RIGHT = 2;
23567
23568 /**
23569  * Placement constant - The resizing element is positioned above the splitter element
23570  * @static
23571  * @type Number
23572  */
23573 Roo.SplitBar.TOP = 3;
23574
23575 /**
23576  * Placement constant - The resizing element is positioned under splitter element
23577  * @static
23578  * @type Number
23579  */
23580 Roo.SplitBar.BOTTOM = 4;
23581
23582 /*
23583  * Based on:
23584  * Ext JS Library 1.1.1
23585  * Copyright(c) 2006-2007, Ext JS, LLC.
23586  *
23587  * Originally Released Under LGPL - original licence link has changed is not relivant.
23588  *
23589  * Fork - LGPL
23590  * <script type="text/javascript">
23591  */
23592
23593 /**
23594  * @class Roo.View
23595  * @extends Roo.util.Observable
23596  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
23597  * This class also supports single and multi selection modes. <br>
23598  * Create a data model bound view:
23599  <pre><code>
23600  var store = new Roo.data.Store(...);
23601
23602  var view = new Roo.View("my-element",
23603  '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
23604  {
23605  singleSelect: true,
23606  selectedClass: "ydataview-selected",
23607  store: store
23608  });
23609
23610  // listen for node click?
23611  view.on("click", function(vw, index, node, e){
23612  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23613  });
23614
23615  // load XML data
23616  dataModel.load("foobar.xml");
23617  </code></pre>
23618  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23619  * <br><br>
23620  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23621  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23622  * @constructor
23623  * Create a new View
23624  * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23625  * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23626  * @param {Object} config The config object
23627  */
23628 Roo.View = function(A, B, C){
23629     this.el = Roo.get(A);
23630     if(typeof  B == "string"){
23631         B = new  Roo.Template(B);
23632     }
23633
23634     B.compile();
23635     /**
23636      * The template used by this View
23637      * @type {Roo.DomHelper.Template}
23638      */
23639     this.tpl = B;
23640
23641     Roo.apply(this, C);
23642
23643     /** @private */
23644     this.addEvents({
23645     /**
23646      * @event beforeclick
23647      * Fires before a click is processed. Returns false to cancel the default action.
23648      * @param {Roo.View} this
23649      * @param {Number} index The index of the target node
23650      * @param {HTMLElement} node The target node
23651      * @param {Roo.EventObject} e The raw event object
23652      */
23653         "beforeclick" : true,
23654     /**
23655      * @event click
23656      * Fires when a template node is clicked.
23657      * @param {Roo.View} this
23658      * @param {Number} index The index of the target node
23659      * @param {HTMLElement} node The target node
23660      * @param {Roo.EventObject} e The raw event object
23661      */
23662         "click" : true,
23663     /**
23664      * @event dblclick
23665      * Fires when a template node is double clicked.
23666      * @param {Roo.View} this
23667      * @param {Number} index The index of the target node
23668      * @param {HTMLElement} node The target node
23669      * @param {Roo.EventObject} e The raw event object
23670      */
23671         "dblclick" : true,
23672     /**
23673      * @event contextmenu
23674      * Fires when a template node is right clicked.
23675      * @param {Roo.View} this
23676      * @param {Number} index The index of the target node
23677      * @param {HTMLElement} node The target node
23678      * @param {Roo.EventObject} e The raw event object
23679      */
23680         "contextmenu" : true,
23681     /**
23682      * @event selectionchange
23683      * Fires when the selected nodes change.
23684      * @param {Roo.View} this
23685      * @param {Array} selections Array of the selected nodes
23686      */
23687         "selectionchange" : true,
23688
23689     /**
23690      * @event beforeselect
23691      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23692      * @param {Roo.View} this
23693      * @param {HTMLElement} node The node to be selected
23694      * @param {Array} selections Array of currently selected nodes
23695      */
23696         "beforeselect" : true
23697     });
23698
23699     this.el.on({
23700         "click": this.onClick,
23701         "dblclick": this.onDblClick,
23702         "contextmenu": this.onContextMenu,
23703         scope:this
23704     });
23705
23706     this.selections = [];
23707     this.nodes = [];
23708     this.cmp = new  Roo.CompositeElementLite([]);
23709     if(this.store){
23710         this.store = Roo.factory(this.store, Roo.data);
23711         this.setStore(this.store, true);
23712     }
23713
23714     Roo.View.superclass.constructor.call(this);
23715 };
23716
23717 Roo.extend(Roo.View, Roo.util.Observable, {
23718     /**
23719      * The css class to add to selected nodes
23720      * @type {Roo.DomHelper.Template}
23721      */
23722     selectedClass : "x-view-selected",
23723     
23724     emptyText : "",
23725     /**
23726      * Returns the element this view is bound to.
23727      * @return {Roo.Element}
23728      */
23729     getEl : function(){
23730         return  this.el;
23731     },
23732
23733     /**
23734      * Refreshes the view.
23735      */
23736     refresh : function(){
23737         var  t = this.tpl;
23738         this.clearSelections();
23739         this.el.update("");
23740         var  D = [];
23741         var  E = this.store.getRange();
23742         if(E.length < 1){
23743             this.el.update(this.emptyText);
23744             return;
23745         }
23746         for(var  i = 0, len = E.length; i < len; i++){
23747             var  data = this.prepareData(E[i].data, i, E[i]);
23748             D[D.length] = t.apply(data);
23749         }
23750
23751         this.el.update(D.join(""));
23752         this.nodes = this.el.dom.childNodes;
23753         this.updateIndexes(0);
23754     },
23755
23756     /**
23757      * Function to override to reformat the data that is sent to
23758      * the template for each node.
23759      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23760      * a JSON object for an UpdateManager bound view).
23761      */
23762     prepareData : function(F){
23763         return  F;
23764     },
23765
23766     onUpdate : function(ds, G){
23767         this.clearSelections();
23768         var  H = this.store.indexOf(G);
23769         var  n = this.nodes[H];
23770         this.tpl.insertBefore(n, this.prepareData(G.data));
23771         n.parentNode.removeChild(n);
23772         this.updateIndexes(H, H);
23773     },
23774
23775     onAdd : function(ds, I, J){
23776         this.clearSelections();
23777         if(this.nodes.length == 0){
23778             this.refresh();
23779             return;
23780         }
23781         var  n = this.nodes[J];
23782         for(var  i = 0, len = I.length; i < len; i++){
23783             var  d = this.prepareData(I[i].data);
23784             if(n){
23785                 this.tpl.insertBefore(n, d);
23786             }else {
23787                 this.tpl.append(this.el, d);
23788             }
23789         }
23790
23791         this.updateIndexes(J);
23792     },
23793
23794     onRemove : function(ds, K, L){
23795         this.clearSelections();
23796         this.el.dom.removeChild(this.nodes[L]);
23797         this.updateIndexes(L);
23798     },
23799
23800     /**
23801      * Refresh an individual node.
23802      * @param {Number} index
23803      */
23804     refreshNode : function(M){
23805         this.onUpdate(this.store, this.store.getAt(M));
23806     },
23807
23808     updateIndexes : function(N, O){
23809         var  ns = this.nodes;
23810         N = N || 0;
23811         O = O || ns.length - 1;
23812         for(var  i = N; i <= O; i++){
23813             ns[i].nodeIndex = i;
23814         }
23815     },
23816
23817     /**
23818      * Changes the data store this view uses and refresh the view.
23819      * @param {Store} store
23820      */
23821     setStore : function(P, Q){
23822         if(!Q && this.store){
23823             this.store.un("datachanged", this.refresh);
23824             this.store.un("add", this.onAdd);
23825             this.store.un("remove", this.onRemove);
23826             this.store.un("update", this.onUpdate);
23827             this.store.un("clear", this.refresh);
23828         }
23829         if(P){
23830           
23831             P.on("datachanged", this.refresh, this);
23832             P.on("add", this.onAdd, this);
23833             P.on("remove", this.onRemove, this);
23834             P.on("update", this.onUpdate, this);
23835             P.on("clear", this.refresh, this);
23836         }
23837         
23838         if(P){
23839             this.refresh();
23840         }
23841     },
23842
23843     /**
23844      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23845      * @param {HTMLElement} node
23846      * @return {HTMLElement} The template node
23847      */
23848     findItemFromChild : function(R){
23849         var  el = this.el.dom;
23850         if(!R || R.parentNode == el){
23851                     return  R;
23852             }
23853             var  p = R.parentNode;
23854             while(p && p != el){
23855             if(p.parentNode == el){
23856                 return  p;
23857             }
23858
23859             p = p.parentNode;
23860         }
23861             return  null;
23862     },
23863
23864     /** @ignore */
23865     onClick : function(e){
23866         var  S = this.findItemFromChild(e.getTarget());
23867         if(S){
23868             var  M = this.indexOf(S);
23869             if(this.onItemClick(S, M, e) !== false){
23870                 this.fireEvent("click", this, M, S, e);
23871             }
23872         }else {
23873             this.clearSelections();
23874         }
23875     },
23876
23877     /** @ignore */
23878     onContextMenu : function(e){
23879         var  T = this.findItemFromChild(e.getTarget());
23880         if(T){
23881             this.fireEvent("contextmenu", this, this.indexOf(T), T, e);
23882         }
23883     },
23884
23885     /** @ignore */
23886     onDblClick : function(e){
23887         var  U = this.findItemFromChild(e.getTarget());
23888         if(U){
23889             this.fireEvent("dblclick", this, this.indexOf(U), U, e);
23890         }
23891     },
23892
23893     onItemClick : function(V, W, e){
23894         if(this.fireEvent("beforeclick", this, W, V, e) === false){
23895             return  false;
23896         }
23897         if(this.multiSelect || this.singleSelect){
23898             if(this.multiSelect && e.shiftKey && this.lastSelection){
23899                 this.select(this.getNodes(this.indexOf(this.lastSelection), W), false);
23900             }else {
23901                 this.select(V, this.multiSelect && e.ctrlKey);
23902                 this.lastSelection = V;
23903             }
23904
23905             e.preventDefault();
23906         }
23907         return  true;
23908     },
23909
23910     /**
23911      * Get the number of selected nodes.
23912      * @return {Number}
23913      */
23914     getSelectionCount : function(){
23915         return  this.selections.length;
23916     },
23917
23918     /**
23919      * Get the currently selected nodes.
23920      * @return {Array} An array of HTMLElements
23921      */
23922     getSelectedNodes : function(){
23923         return  this.selections;
23924     },
23925
23926     /**
23927      * Get the indexes of the selected nodes.
23928      * @return {Array}
23929      */
23930     getSelectedIndexes : function(){
23931         var  X = [], s = this.selections;
23932         for(var  i = 0, len = s.length; i < len; i++){
23933             X.push(s[i].nodeIndex);
23934         }
23935         return  X;
23936     },
23937
23938     /**
23939      * Clear all selections
23940      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23941      */
23942     clearSelections : function(Y){
23943         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23944             this.cmp.elements = this.selections;
23945             this.cmp.removeClass(this.selectedClass);
23946             this.selections = [];
23947             if(!Y){
23948                 this.fireEvent("selectionchange", this, this.selections);
23949             }
23950         }
23951     },
23952
23953     /**
23954      * Returns true if the passed node is selected
23955      * @param {HTMLElement/Number} node The node or node index
23956      * @return {Boolean}
23957      */
23958     isSelected : function(Z){
23959         var  s = this.selections;
23960         if(s.length < 1){
23961             return  false;
23962         }
23963
23964         Z = this.getNode(Z);
23965         return  s.indexOf(Z) !== -1;
23966     },
23967
23968     /**
23969      * Selects nodes.
23970      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
23971      * @param {Boolean} keepExisting (optional) true to keep existing selections
23972      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23973      */
23974     select : function(a, b, c){
23975         if(a  instanceof  Array){
23976             if(!b){
23977                 this.clearSelections(true);
23978             }
23979             for(var  i = 0, len = a.length; i < len; i++){
23980                 this.select(a[i], true, true);
23981             }
23982         } else {
23983             var  Z = this.getNode(a);
23984             if(Z && !this.isSelected(Z)){
23985                 if(!b){
23986                     this.clearSelections(true);
23987                 }
23988                 if(this.fireEvent("beforeselect", this, Z, this.selections) !== false){
23989                     Roo.fly(Z).addClass(this.selectedClass);
23990                     this.selections.push(Z);
23991                     if(!c){
23992                         this.fireEvent("selectionchange", this, this.selections);
23993                     }
23994                 }
23995             }
23996         }
23997     },
23998
23999     /**
24000      * Gets a template node.
24001      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24002      * @return {HTMLElement} The node or null if it wasn't found
24003      */
24004     getNode : function(f){
24005         if(typeof  f == "string"){
24006             return  document.getElementById(f);
24007         }else  if(typeof  f == "number"){
24008             return  this.nodes[f];
24009         }
24010         return  f;
24011     },
24012
24013     /**
24014      * Gets a range template nodes.
24015      * @param {Number} startIndex
24016      * @param {Number} endIndex
24017      * @return {Array} An array of nodes
24018      */
24019     getNodes : function(g, h){
24020         var  ns = this.nodes;
24021         g = g || 0;
24022         h = typeof  h == "undefined" ? ns.length - 1 : h;
24023         var  j = [];
24024         if(g <= h){
24025             for(var  i = g; i <= h; i++){
24026                 j.push(ns[i]);
24027             }
24028         } else {
24029             for(var  i = g; i >= h; i--){
24030                 j.push(ns[i]);
24031             }
24032         }
24033         return  j;
24034     },
24035
24036     /**
24037      * Finds the index of the passed node
24038      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24039      * @return {Number} The index of the node or -1
24040      */
24041     indexOf : function(k){
24042         k = this.getNode(k);
24043         if(typeof  k.nodeIndex == "number"){
24044             return  k.nodeIndex;
24045         }
24046         var  ns = this.nodes;
24047         for(var  i = 0, len = ns.length; i < len; i++){
24048             if(ns[i] == k){
24049                 return  i;
24050             }
24051         }
24052         return  -1;
24053     }
24054 });
24055
24056 /*
24057  * Based on:
24058  * Ext JS Library 1.1.1
24059  * Copyright(c) 2006-2007, Ext JS, LLC.
24060  *
24061  * Originally Released Under LGPL - original licence link has changed is not relivant.
24062  *
24063  * Fork - LGPL
24064  * <script type="text/javascript">
24065  */
24066
24067 /**
24068  * @class Roo.JsonView
24069  * @extends Roo.View
24070  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24071 <pre><code>
24072 var view = new Roo.JsonView("my-element",
24073     '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
24074     { multiSelect: true, jsonRoot: "data" }
24075 );
24076
24077 // listen for node click?
24078 view.on("click", function(vw, index, node, e){
24079     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24080 });
24081
24082 // direct load of JSON data
24083 view.load("foobar.php");
24084
24085 // Example from my blog list
24086 var tpl = new Roo.Template(
24087     '&lt;div class="entry"&gt;' +
24088     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
24089     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
24090     "&lt;/div&gt;&lt;hr /&gt;"
24091 );
24092
24093 var moreView = new Roo.JsonView("entry-list", tpl, {
24094     jsonRoot: "posts"
24095 });
24096 moreView.on("beforerender", this.sortEntries, this);
24097 moreView.load({
24098     url: "/blog/get-posts.php",
24099     params: "allposts=true",
24100     text: "Loading Blog Entries..."
24101 });
24102 </code></pre>
24103  * @constructor
24104  * Create a new JsonView
24105  * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
24106  * @param {Template} tpl The rendering template
24107  * @param {Object} config The config object
24108  */
24109 Roo.JsonView = function(A, B, C){
24110     Roo.JsonView.superclass.constructor.call(this, A, B, C);
24111
24112     var  um = this.el.getUpdateManager();
24113     um.setRenderer(this);
24114     um.on("update", this.onLoad, this);
24115     um.on("failure", this.onLoadException, this);
24116
24117     /**
24118      * @event beforerender
24119      * Fires before rendering of the downloaded JSON data.
24120      * @param {Roo.JsonView} this
24121      * @param {Object} data The JSON data loaded
24122      */
24123     /**
24124      * @event load
24125      * Fires when data is loaded.
24126      * @param {Roo.JsonView} this
24127      * @param {Object} data The JSON data loaded
24128      * @param {Object} response The raw Connect response object
24129      */
24130     /**
24131      * @event loadexception
24132      * Fires when loading fails.
24133      * @param {Roo.JsonView} this
24134      * @param {Object} response The raw Connect response object
24135      */
24136     this.addEvents({
24137         'beforerender' : true,
24138         'load' : true,
24139         'loadexception' : true
24140     });
24141 };
24142 Roo.extend(Roo.JsonView, Roo.View, {
24143     /**
24144      * The root property in the loaded JSON object that contains the data
24145      * @type {String}
24146      */
24147     jsonRoot : "",
24148
24149     /**
24150      * Refreshes the view.
24151      */
24152     refresh : function(){
24153         this.clearSelections();
24154         this.el.update("");
24155         var  D = [];
24156         var  o = this.jsonData;
24157         if(o && o.length > 0){
24158             for(var  i = 0, len = o.length; i < len; i++){
24159                 var  data = this.prepareData(o[i], i, o);
24160                 D[D.length] = this.tpl.apply(data);
24161             }
24162         }else {
24163             D.push(this.emptyText);
24164         }
24165
24166         this.el.update(D.join(""));
24167         this.nodes = this.el.dom.childNodes;
24168         this.updateIndexes(0);
24169     },
24170
24171     /**
24172      * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
24173      * @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:
24174      <pre><code>
24175      view.load({
24176          url: "your-url.php",
24177          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24178          callback: yourFunction,
24179          scope: yourObject, //(optional scope)
24180          discardUrl: false,
24181          nocache: false,
24182          text: "Loading...",
24183          timeout: 30,
24184          scripts: false
24185      });
24186      </code></pre>
24187      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24188      * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
24189      * @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}
24190      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24191      * @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.
24192      */
24193     load : function(){
24194         var  um = this.el.getUpdateManager();
24195         um.update.apply(um, arguments);
24196     },
24197
24198     render : function(el, E){
24199         this.clearSelections();
24200         this.el.update("");
24201         var  o;
24202         try{
24203             o = Roo.util.JSON.decode(E.responseText);
24204             if(this.jsonRoot){
24205                 
24206                 o = /** eval:var:o */ eval("o." + this.jsonRoot);
24207             }
24208         } catch(e){
24209         }
24210
24211         /**
24212          * The current JSON data or null
24213          */
24214         this.jsonData = o;
24215         this.beforeRender();
24216         this.refresh();
24217     },
24218
24219 /**
24220  * Get the number of records in the current JSON dataset
24221  * @return {Number}
24222  */
24223     getCount : function(){
24224         return  this.jsonData ? this.jsonData.length : 0;
24225     },
24226
24227 /**
24228  * Returns the JSON object for the specified node(s)
24229  * @param {HTMLElement/Array} node The node or an array of nodes
24230  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24231  * you get the JSON object for the node
24232  */
24233     getNodeData : function(F){
24234         if(F  instanceof  Array){
24235             var  data = [];
24236             for(var  i = 0, len = F.length; i < len; i++){
24237                 data.push(this.getNodeData(F[i]));
24238             }
24239             return  data;
24240         }
24241         return  this.jsonData[this.indexOf(F)] || null;
24242     },
24243
24244     beforeRender : function(){
24245         this.snapshot = this.jsonData;
24246         if(this.sortInfo){
24247             this.sort.apply(this, this.sortInfo);
24248         }
24249
24250         this.fireEvent("beforerender", this, this.jsonData);
24251     },
24252
24253     onLoad : function(el, o){
24254         this.fireEvent("load", this, this.jsonData, o);
24255     },
24256
24257     onLoadException : function(el, o){
24258         this.fireEvent("loadexception", this, o);
24259     },
24260
24261 /**
24262  * Filter the data by a specific property.
24263  * @param {String} property A property on your JSON objects
24264  * @param {String/RegExp} value Either string that the property values
24265  * should start with, or a RegExp to test against the property
24266  */
24267     filter : function(G, H){
24268         if(this.jsonData){
24269             var  data = [];
24270             var  ss = this.snapshot;
24271             if(typeof  H == "string"){
24272                 var  vlen = H.length;
24273                 if(vlen == 0){
24274                     this.clearFilter();
24275                     return;
24276                 }
24277
24278                 H = H.toLowerCase();
24279                 for(var  i = 0, len = ss.length; i < len; i++){
24280                     var  o = ss[i];
24281                     if(o[G].substr(0, vlen).toLowerCase() == H){
24282                         data.push(o);
24283                     }
24284                 }
24285             } else  if(H.exec){ // regex?
24286                 for(var  i = 0, len = ss.length; i < len; i++){
24287                     var  o = ss[i];
24288                     if(H.test(o[G])){
24289                         data.push(o);
24290                     }
24291                 }
24292             } else {
24293                 return;
24294             }
24295
24296             this.jsonData = data;
24297             this.refresh();
24298         }
24299     },
24300
24301 /**
24302  * Filter by a function. The passed function will be called with each
24303  * object in the current dataset. If the function returns true the value is kept,
24304  * otherwise it is filtered.
24305  * @param {Function} fn
24306  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24307  */
24308     filterBy : function(fn, I){
24309         if(this.jsonData){
24310             var  data = [];
24311             var  ss = this.snapshot;
24312             for(var  i = 0, len = ss.length; i < len; i++){
24313                 var  o = ss[i];
24314                 if(fn.call(I || this, o)){
24315                     data.push(o);
24316                 }
24317             }
24318
24319             this.jsonData = data;
24320             this.refresh();
24321         }
24322     },
24323
24324 /**
24325  * Clears the current filter.
24326  */
24327     clearFilter : function(){
24328         if(this.snapshot && this.jsonData != this.snapshot){
24329             this.jsonData = this.snapshot;
24330             this.refresh();
24331         }
24332     },
24333
24334
24335 /**
24336  * Sorts the data for this view and refreshes it.
24337  * @param {String} property A property on your JSON objects to sort on
24338  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24339  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24340  */
24341     sort : function(J, K, L){
24342         this.sortInfo = Array.prototype.slice.call(arguments, 0);
24343         if(this.jsonData){
24344             var  p = J;
24345             var  dsc = K && K.toLowerCase() == "desc";
24346             var  f = function(o1, o2){
24347                 var  v1 = L ? L(o1[p]) : o1[p];
24348                 var  v2 = L ? L(o2[p]) : o2[p];
24349                 ;
24350                 if(v1 < v2){
24351                     return  dsc ? +1 : -1;
24352                 } else  if(v1 > v2){
24353                     return  dsc ? -1 : +1;
24354                 } else {
24355                     return  0;
24356                 }
24357             };
24358             this.jsonData.sort(f);
24359             this.refresh();
24360             if(this.jsonData != this.snapshot){
24361                 this.snapshot.sort(f);
24362             }
24363         }
24364     }
24365 });
24366 /*
24367  * Based on:
24368  * Ext JS Library 1.1.1
24369  * Copyright(c) 2006-2007, Ext JS, LLC.
24370  *
24371  * Originally Released Under LGPL - original licence link has changed is not relivant.
24372  *
24373  * Fork - LGPL
24374  * <script type="text/javascript">
24375  */
24376  
24377
24378 /**
24379  * @class Roo.ColorPalette
24380  * @extends Roo.Component
24381  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
24382  * Here's an example of typical usage:
24383  * <pre><code>
24384 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
24385 cp.render('my-div');
24386
24387 cp.on('select', function(palette, selColor){
24388     // do something with selColor
24389 });
24390 </code></pre>
24391  * @constructor
24392  * Create a new ColorPalette
24393  * @param {Object} config The config object
24394  */
24395 Roo.ColorPalette = function(A){
24396     Roo.ColorPalette.superclass.constructor.call(this, A);
24397     this.addEvents({
24398         /**
24399              * @event select
24400              * Fires when a color is selected
24401              * @param {ColorPalette} this
24402              * @param {String} color The 6-digit color hex code (without the # symbol)
24403              */
24404         select: true
24405     });
24406
24407     if(this.handler){
24408         this.on("select", this.handler, this.scope, true);
24409     }
24410 };
24411 Roo.extend(Roo.ColorPalette, Roo.Component, {
24412     /**
24413      * @cfg {String} itemCls
24414      * The CSS class to apply to the containing element (defaults to "x-color-palette")
24415      */
24416     itemCls : "x-color-palette",
24417     /**
24418      * @cfg {String} value
24419      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
24420      * the hex codes are case-sensitive.
24421      */
24422     value : null,
24423     clickEvent:'click',
24424     // private
24425     ctype: "Roo.ColorPalette",
24426
24427     /**
24428      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24429      */
24430     allowReselect : false,
24431
24432     /**
24433      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
24434      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
24435      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24436      * of colors with the width setting until the box is symmetrical.</p>
24437      * <p>You can override individual colors if needed:</p>
24438      * <pre><code>
24439 var cp = new Roo.ColorPalette();
24440 cp.colors[0] = "FF0000";  // change the first box to red
24441 </code></pre>
24442
24443 Or you can provide a custom array of your own for complete control:
24444 <pre><code>
24445 var cp = new Roo.ColorPalette();
24446 cp.colors = ["000000", "993300", "333300"];
24447 </code></pre>
24448      * @type Array
24449      */
24450     colors : [
24451         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24452         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24453         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24454         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24455         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24456     ],
24457
24458     // private
24459     onRender : function(B, C){
24460         var  t = new  Roo.MasterTemplate(
24461             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
24462         );
24463         var  c = this.colors;
24464         for(var  i = 0, len = c.length; i < len; i++){
24465             t.add([c[i]]);
24466         }
24467         var  el = document.createElement("div");
24468         el.className = this.itemCls;
24469         t.overwrite(el);
24470         B.dom.insertBefore(el, C);
24471         this.el = Roo.get(el);
24472         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
24473         if(this.clickEvent != 'click'){
24474             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
24475         }
24476     },
24477
24478     // private
24479     afterRender : function(){
24480         Roo.ColorPalette.superclass.afterRender.call(this);
24481         if(this.value){
24482             var  s = this.value;
24483             this.value = null;
24484             this.select(s);
24485         }
24486     },
24487
24488     // private
24489     handleClick : function(e, t){
24490         e.preventDefault();
24491         if(!this.disabled){
24492             var  c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24493             this.select(c.toUpperCase());
24494         }
24495     },
24496
24497     /**
24498      * Selects the specified color in the palette (fires the select event)
24499      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24500      */
24501     select : function(D){
24502         D = D.replace("#", "");
24503         if(D != this.value || this.allowReselect){
24504             var  el = this.el;
24505             if(this.value){
24506                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24507             }
24508
24509             el.child("a.color-"+D).addClass("x-color-palette-sel");
24510             this.value = D;
24511             this.fireEvent("select", this, D);
24512         }
24513     }
24514 });
24515 /*
24516  * Based on:
24517  * Ext JS Library 1.1.1
24518  * Copyright(c) 2006-2007, Ext JS, LLC.
24519  *
24520  * Originally Released Under LGPL - original licence link has changed is not relivant.
24521  *
24522  * Fork - LGPL
24523  * <script type="text/javascript">
24524  */
24525  
24526 /**
24527  * @class Roo.DatePicker
24528  * @extends Roo.Component
24529  * Simple date picker class.
24530  * @constructor
24531  * Create a new DatePicker
24532  * @param {Object} config The config object
24533  */
24534 Roo.DatePicker = function(A){
24535     Roo.DatePicker.superclass.constructor.call(this, A);
24536
24537     this.value = A && A.value ?
24538                  A.value.clearTime() : new  Date().clearTime();
24539
24540     this.addEvents({
24541         /**
24542              * @event select
24543              * Fires when a date is selected
24544              * @param {DatePicker} this
24545              * @param {Date} date The selected date
24546              */
24547         select: true
24548     });
24549
24550     if(this.handler){
24551         this.on("select", this.handler,  this.scope || this);
24552     }
24553     // build the disabledDatesRE
24554     if(!this.disabledDatesRE && this.disabledDates){
24555         var  dd = this.disabledDates;
24556         var  re = "(?:";
24557         for(var  i = 0; i < dd.length; i++){
24558             re += dd[i];
24559             if(i != dd.length-1) re += "|";
24560         }
24561
24562         this.disabledDatesRE = new  RegExp(re + ")");
24563     }
24564 };
24565
24566 Roo.extend(Roo.DatePicker, Roo.Component, {
24567     /**
24568      * @cfg {String} todayText
24569      * The text to display on the button that selects the current date (defaults to "Today")
24570      */
24571     todayText : "Today",
24572     /**
24573      * @cfg {String} okText
24574      * The text to display on the ok button
24575      */
24576     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
24577     /**
24578      * @cfg {String} cancelText
24579      * The text to display on the cancel button
24580      */
24581     cancelText : "Cancel",
24582     /**
24583      * @cfg {String} todayTip
24584      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24585      */
24586     todayTip : "{0} (Spacebar)",
24587     /**
24588      * @cfg {Date} minDate
24589      * Minimum allowable date (JavaScript date object, defaults to null)
24590      */
24591     minDate : null,
24592     /**
24593      * @cfg {Date} maxDate
24594      * Maximum allowable date (JavaScript date object, defaults to null)
24595      */
24596     maxDate : null,
24597     /**
24598      * @cfg {String} minText
24599      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24600      */
24601     minText : "This date is before the minimum date",
24602     /**
24603      * @cfg {String} maxText
24604      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24605      */
24606     maxText : "This date is after the maximum date",
24607     /**
24608      * @cfg {String} format
24609      * The default date format string which can be overriden for localization support.  The format must be
24610      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24611      */
24612     format : "m/d/y",
24613     /**
24614      * @cfg {Array} disabledDays
24615      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24616      */
24617     disabledDays : null,
24618     /**
24619      * @cfg {String} disabledDaysText
24620      * The tooltip to display when the date falls on a disabled day (defaults to "")
24621      */
24622     disabledDaysText : "",
24623     /**
24624      * @cfg {RegExp} disabledDatesRE
24625      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24626      */
24627     disabledDatesRE : null,
24628     /**
24629      * @cfg {String} disabledDatesText
24630      * The tooltip text to display when the date falls on a disabled date (defaults to "")
24631      */
24632     disabledDatesText : "",
24633     /**
24634      * @cfg {Boolean} constrainToViewport
24635      * True to constrain the date picker to the viewport (defaults to true)
24636      */
24637     constrainToViewport : true,
24638     /**
24639      * @cfg {Array} monthNames
24640      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24641      */
24642     monthNames : Date.monthNames,
24643     /**
24644      * @cfg {Array} dayNames
24645      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24646      */
24647     dayNames : Date.dayNames,
24648     /**
24649      * @cfg {String} nextText
24650      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24651      */
24652     nextText: 'Next Month (Control+Right)',
24653     /**
24654      * @cfg {String} prevText
24655      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24656      */
24657     prevText: 'Previous Month (Control+Left)',
24658     /**
24659      * @cfg {String} monthYearText
24660      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24661      */
24662     monthYearText: 'Choose a month (Control+Up/Down to move years)',
24663     /**
24664      * @cfg {Number} startDay
24665      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24666      */
24667     startDay : 0,
24668     /**
24669      * @cfg {Bool} showClear
24670      * Show a clear button (usefull for date form elements that can be blank.)
24671      */
24672     
24673     showClear: false,
24674     
24675     /**
24676      * Sets the value of the date field
24677      * @param {Date} value The date to set
24678      */
24679     setValue : function(B){
24680         var  C = this.value;
24681         this.value = B.clearTime(true);
24682         if(this.el){
24683             this.update(this.value);
24684         }
24685     },
24686
24687     /**
24688      * Gets the current selected value of the date field
24689      * @return {Date} The selected date
24690      */
24691     getValue : function(){
24692         return  this.value;
24693     },
24694
24695     // private
24696     focus : function(){
24697         if(this.el){
24698             this.update(this.activeDate);
24699         }
24700     },
24701
24702     // private
24703     onRender : function(D, E){
24704         var  m = [
24705              '<table cellspacing="0">',
24706                 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',
24707                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24708         var  dn = this.dayNames;
24709         for(var  i = 0; i < 7; i++){
24710             var  d = this.startDay+i;
24711             if(d > 6){
24712                 d = d-7;
24713             }
24714
24715             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24716         }
24717
24718         m[m.length] = "</tr></thead><tbody><tr>";
24719         for(var  i = 0; i < 42; i++) {
24720             if(i % 7 == 0 && i != 0){
24721                 m[m.length] = "</tr><tr>";
24722             }
24723
24724             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24725         }
24726
24727         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24728             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24729
24730         var  el = document.createElement("div");
24731         el.className = "x-date-picker";
24732         el.innerHTML = m.join("");
24733
24734         D.dom.insertBefore(el, E);
24735
24736         this.el = Roo.get(el);
24737         this.eventEl = Roo.get(el.firstChild);
24738
24739         new  Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24740             handler: this.showPrevMonth,
24741             scope: this,
24742             preventDefault:true,
24743             stopDefault:true
24744         });
24745
24746         new  Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24747             handler: this.showNextMonth,
24748             scope: this,
24749             preventDefault:true,
24750             stopDefault:true
24751         });
24752
24753         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
24754
24755         this.monthPicker = this.el.down('div.x-date-mp');
24756         this.monthPicker.enableDisplayMode('block');
24757         
24758         var  kn = new  Roo.KeyNav(this.eventEl, {
24759             "left" : function(e){
24760                 e.ctrlKey ?
24761                     this.showPrevMonth() :
24762                     this.update(this.activeDate.add("d", -1));
24763             },
24764
24765             "right" : function(e){
24766                 e.ctrlKey ?
24767                     this.showNextMonth() :
24768                     this.update(this.activeDate.add("d", 1));
24769             },
24770
24771             "up" : function(e){
24772                 e.ctrlKey ?
24773                     this.showNextYear() :
24774                     this.update(this.activeDate.add("d", -7));
24775             },
24776
24777             "down" : function(e){
24778                 e.ctrlKey ?
24779                     this.showPrevYear() :
24780                     this.update(this.activeDate.add("d", 7));
24781             },
24782
24783             "pageUp" : function(e){
24784                 this.showNextMonth();
24785             },
24786
24787             "pageDown" : function(e){
24788                 this.showPrevMonth();
24789             },
24790
24791             "enter" : function(e){
24792                 e.stopPropagation();
24793                 return  true;
24794             },
24795
24796             scope : this
24797         });
24798
24799         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
24800
24801         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
24802
24803         this.el.unselectable();
24804         
24805         this.cells = this.el.select("table.x-date-inner tbody td");
24806         this.textNodes = this.el.query("table.x-date-inner tbody span");
24807
24808         this.mbtn = new  Roo.Button(this.el.child("td.x-date-middle", true), {
24809             text: "&#160;",
24810             tooltip: this.monthYearText
24811         });
24812
24813         this.mbtn.on('click', this.showMonthPicker, this);
24814         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24815
24816
24817         var  F = (new  Date()).dateFormat(this.format);
24818         
24819         var  G = new  Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24820         G.add({
24821             text: String.format(this.todayText, F),
24822             tooltip: String.format(this.todayTip, F),
24823             handler: this.selectToday,
24824             scope: this
24825         });
24826         
24827         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24828             
24829         //});
24830         if (this.showClear) {
24831             
24832             G.add( new  Roo.Toolbar.Fill());
24833             G.add({
24834                 text: '&#160;',
24835                 cls: 'x-btn-icon x-btn-clear',
24836                 handler: function() {
24837                     //this.value = '';
24838                     this.fireEvent("select", this, '');
24839                 },
24840                 scope: this
24841             });
24842         }
24843         
24844         
24845         if(Roo.isIE){
24846             this.el.repaint();
24847         }
24848
24849         this.update(this.value);
24850     },
24851
24852     createMonthPicker : function(){
24853         if(!this.monthPicker.dom.firstChild){
24854             var  buf = ['<table border="0" cellspacing="0">'];
24855             for(var  i = 0; i < 6; i++){
24856                 buf.push(
24857                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24858                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24859                     i == 0 ?
24860                     '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
24861                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24862                 );
24863             }
24864
24865             buf.push(
24866                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24867                     this.okText,
24868                     '</button><button type="button" class="x-date-mp-cancel">',
24869                     this.cancelText,
24870                     '</button></td></tr>',
24871                 '</table>'
24872             );
24873             this.monthPicker.update(buf.join(''));
24874             this.monthPicker.on('click', this.onMonthClick, this);
24875             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24876
24877             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24878             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24879
24880             this.mpMonths.each(function(m, a, i){
24881                 i += 1;
24882                 if((i%2) == 0){
24883                     m.dom.xmonth = 5 + Math.round(i * .5);
24884                 }else {
24885                     m.dom.xmonth = Math.round((i-1) * .5);
24886                 }
24887             });
24888         }
24889     },
24890
24891     showMonthPicker : function(){
24892         this.createMonthPicker();
24893         var  H = this.el.getSize();
24894         this.monthPicker.setSize(H);
24895         this.monthPicker.child('table').setSize(H);
24896
24897         this.mpSelMonth = (this.activeDate || this.value).getMonth();
24898         this.updateMPMonth(this.mpSelMonth);
24899         this.mpSelYear = (this.activeDate || this.value).getFullYear();
24900         this.updateMPYear(this.mpSelYear);
24901
24902         this.monthPicker.slideIn('t', {duration:.2});
24903     },
24904
24905     updateMPYear : function(y){
24906         this.mpyear = y;
24907         var  ys = this.mpYears.elements;
24908         for(var  i = 1; i <= 10; i++){
24909             var  td = ys[i-1], y2;
24910             if((i%2) == 0){
24911                 y2 = y + Math.round(i * .5);
24912                 td.firstChild.innerHTML = y2;
24913                 td.xyear = y2;
24914             }else {
24915                 y2 = y - (5-Math.round(i * .5));
24916                 td.firstChild.innerHTML = y2;
24917                 td.xyear = y2;
24918             }
24919
24920             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24921         }
24922     },
24923
24924     updateMPMonth : function(sm){
24925         this.mpMonths.each(function(m, a, i){
24926             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24927         });
24928     },
24929
24930     selectMPMonth: function(m){
24931         
24932     },
24933
24934     onMonthClick : function(e, t){
24935         e.stopEvent();
24936         var  el = new  Roo.Element(t), pn;
24937         if(el.is('button.x-date-mp-cancel')){
24938             this.hideMonthPicker();
24939         }
24940         else  if(el.is('button.x-date-mp-ok')){
24941             this.update(new  Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24942             this.hideMonthPicker();
24943         }
24944         else  if(pn = el.up('td.x-date-mp-month', 2)){
24945             this.mpMonths.removeClass('x-date-mp-sel');
24946             pn.addClass('x-date-mp-sel');
24947             this.mpSelMonth = pn.dom.xmonth;
24948         }
24949         else  if(pn = el.up('td.x-date-mp-year', 2)){
24950             this.mpYears.removeClass('x-date-mp-sel');
24951             pn.addClass('x-date-mp-sel');
24952             this.mpSelYear = pn.dom.xyear;
24953         }
24954         else  if(el.is('a.x-date-mp-prev')){
24955             this.updateMPYear(this.mpyear-10);
24956         }
24957         else  if(el.is('a.x-date-mp-next')){
24958             this.updateMPYear(this.mpyear+10);
24959         }
24960     },
24961
24962     onMonthDblClick : function(e, t){
24963         e.stopEvent();
24964         var  el = new  Roo.Element(t), pn;
24965         if(pn = el.up('td.x-date-mp-month', 2)){
24966             this.update(new  Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24967             this.hideMonthPicker();
24968         }
24969         else  if(pn = el.up('td.x-date-mp-year', 2)){
24970             this.update(new  Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24971             this.hideMonthPicker();
24972         }
24973     },
24974
24975     hideMonthPicker : function(I){
24976         if(this.monthPicker){
24977             if(I === true){
24978                 this.monthPicker.hide();
24979             }else {
24980                 this.monthPicker.slideOut('t', {duration:.2});
24981             }
24982         }
24983     },
24984
24985     // private
24986     showPrevMonth : function(e){
24987         this.update(this.activeDate.add("mo", -1));
24988     },
24989
24990     // private
24991     showNextMonth : function(e){
24992         this.update(this.activeDate.add("mo", 1));
24993     },
24994
24995     // private
24996     showPrevYear : function(){
24997         this.update(this.activeDate.add("y", -1));
24998     },
24999
25000     // private
25001     showNextYear : function(){
25002         this.update(this.activeDate.add("y", 1));
25003     },
25004
25005     // private
25006     handleMouseWheel : function(e){
25007         var  J = e.getWheelDelta();
25008         if(J > 0){
25009             this.showPrevMonth();
25010             e.stopEvent();
25011         } else  if(J < 0){
25012             this.showNextMonth();
25013             e.stopEvent();
25014         }
25015     },
25016
25017     // private
25018     handleDateClick : function(e, t){
25019         e.stopEvent();
25020         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25021             this.setValue(new  Date(t.dateValue));
25022             this.fireEvent("select", this, this.value);
25023         }
25024     },
25025
25026     // private
25027     selectToday : function(){
25028         this.setValue(new  Date().clearTime());
25029         this.fireEvent("select", this, this.value);
25030     },
25031
25032     // private
25033     update : function(K){
25034         var  vd = this.activeDate;
25035         this.activeDate = K;
25036         if(vd && this.el){
25037             var  t = K.getTime();
25038             if(vd.getMonth() == K.getMonth() && vd.getFullYear() == K.getFullYear()){
25039                 this.cells.removeClass("x-date-selected");
25040                 this.cells.each(function(c){
25041                    if(c.dom.firstChild.dateValue == t){
25042                        c.addClass("x-date-selected");
25043                        setTimeout(function(){
25044                             try{c.dom.firstChild.focus();}catch(e){}
25045                        }, 50);
25046                        return  false;
25047                    }
25048                 });
25049                 return;
25050             }
25051         }
25052         var  L = K.getDaysInMonth();
25053         var  M = K.getFirstDateOfMonth();
25054         var  N = M.getDay()-this.startDay;
25055
25056         if(N <= this.startDay){
25057             N += 7;
25058         }
25059
25060         var  pm = K.add("mo", -1);
25061         var  O = pm.getDaysInMonth()-N;
25062
25063         var  P = this.cells.elements;
25064         var  Q = this.textNodes;
25065         L += N;
25066
25067         // convert everything to numbers so it's fast
25068         var  R = 86400000;
25069         var  d = (new  Date(pm.getFullYear(), pm.getMonth(), O)).clearTime();
25070         var  S = new  Date().clearTime().getTime();
25071         var  T = K.clearTime().getTime();
25072         var  U = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25073         var  V = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25074         var  W = this.disabledDatesRE;
25075         var  X = this.disabledDatesText;
25076         var  Y = this.disabledDays ? this.disabledDays.join("") : false;
25077         var  Z = this.disabledDaysText;
25078         var  a = this.format;
25079
25080         var  b = function(f, g){
25081             g.title = "";
25082             var  t = d.getTime();
25083             g.firstChild.dateValue = t;
25084             if(t == S){
25085                 g.className += " x-date-today";
25086                 g.title = f.todayText;
25087             }
25088             if(t == T){
25089                 g.className += " x-date-selected";
25090                 setTimeout(function(){
25091                     try{g.firstChild.focus();}catch(e){}
25092                 }, 50);
25093             }
25094             // disabling
25095             if(t < U) {
25096                 g.className = " x-date-disabled";
25097                 g.title = f.minText;
25098                 return;
25099             }
25100             if(t > V) {
25101                 g.className = " x-date-disabled";
25102                 g.title = f.maxText;
25103                 return;
25104             }
25105             if(Y){
25106                 if(Y.indexOf(d.getDay()) != -1){
25107                     g.title = Z;
25108                     g.className = " x-date-disabled";
25109                 }
25110             }
25111             if(W && a){
25112                 var  fvalue = d.dateFormat(a);
25113                 if(W.test(fvalue)){
25114                     g.title = X.replace("%0", fvalue);
25115                     g.className = " x-date-disabled";
25116                 }
25117             }
25118         };
25119
25120         var  i = 0;
25121         for(; i < N; i++) {
25122             Q[i].innerHTML = (++O);
25123             d.setDate(d.getDate()+1);
25124             P[i].className = "x-date-prevday";
25125             b(this, P[i]);
25126         }
25127         for(; i < L; i++){
25128             intDay = i - N + 1;
25129             Q[i].innerHTML = (intDay);
25130             d.setDate(d.getDate()+1);
25131             P[i].className = "x-date-active";
25132             b(this, P[i]);
25133         }
25134         var  c = 0;
25135         for(; i < 42; i++) {
25136              Q[i].innerHTML = (++c);
25137              d.setDate(d.getDate()+1);
25138              P[i].className = "x-date-nextday";
25139              b(this, P[i]);
25140         }
25141
25142
25143         this.mbtn.setText(this.monthNames[K.getMonth()] + " " + K.getFullYear());
25144
25145         if(!this.internalRender){
25146             var  main = this.el.dom.firstChild;
25147             var  w = main.offsetWidth;
25148             this.el.setWidth(w + this.el.getBorderWidth("lr"));
25149             Roo.fly(main).setWidth(w);
25150             this.internalRender = true;
25151             // opera does not respect the auto grow header center column
25152             // then, after it gets a width opera refuses to recalculate
25153             // without a second pass
25154             if(Roo.isOpera && !this.secondPass){
25155                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25156                 this.secondPass = true;
25157                 this.update.defer(10, this, [K]);
25158             }
25159         }
25160     }
25161 });
25162 /*
25163  * Based on:
25164  * Ext JS Library 1.1.1
25165  * Copyright(c) 2006-2007, Ext JS, LLC.
25166  *
25167  * Originally Released Under LGPL - original licence link has changed is not relivant.
25168  *
25169  * Fork - LGPL
25170  * <script type="text/javascript">
25171  */
25172 /**
25173  * @class Roo.TabPanel
25174  * @extends Roo.util.Observable
25175  * A lightweight tab container.
25176  * <br><br>
25177  * Usage:
25178  * <pre><code>
25179 // basic tabs 1, built from existing content
25180 var tabs = new Roo.TabPanel("tabs1");
25181 tabs.addTab("script", "View Script");
25182 tabs.addTab("markup", "View Markup");
25183 tabs.activate("script");
25184
25185 // more advanced tabs, built from javascript
25186 var jtabs = new Roo.TabPanel("jtabs");
25187 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25188
25189 // set up the UpdateManager
25190 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25191 var updater = tab2.getUpdateManager();
25192 updater.setDefaultUrl("ajax1.htm");
25193 tab2.on('activate', updater.refresh, updater, true);
25194
25195 // Use setUrl for Ajax loading
25196 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25197 tab3.setUrl("ajax2.htm", null, true);
25198
25199 // Disabled tab
25200 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25201 tab4.disable();
25202
25203 jtabs.activate("jtabs-1");
25204  * </code></pre>
25205  * @constructor
25206  * Create a new TabPanel.
25207  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25208  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25209  */
25210 Roo.TabPanel = function(A, B){
25211     /**
25212     * The container element for this TabPanel.
25213     * @type Roo.Element
25214     */
25215     this.el = Roo.get(A, true);
25216     if(B){
25217         if(typeof  B == "boolean"){
25218             this.tabPosition = B ? "bottom" : "top";
25219         }else {
25220             Roo.apply(this, B);
25221         }
25222     }
25223     if(this.tabPosition == "bottom"){
25224         this.bodyEl = Roo.get(this.createBody(this.el.dom));
25225         this.el.addClass("x-tabs-bottom");
25226     }
25227
25228     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25229     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25230     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25231     if(Roo.isIE){
25232         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25233     }
25234     if(this.tabPosition != "bottom"){
25235     /** The body element that contains {@link Roo.TabPanelItem} bodies.
25236      * @type Roo.Element
25237      */
25238       this.bodyEl = Roo.get(this.createBody(this.el.dom));
25239       this.el.addClass("x-tabs-top");
25240     }
25241
25242     this.items = [];
25243
25244     this.bodyEl.setStyle("position", "relative");
25245
25246     this.active = null;
25247     this.activateDelegate = this.activate.createDelegate(this);
25248
25249     this.addEvents({
25250         /**
25251          * @event tabchange
25252          * Fires when the active tab changes
25253          * @param {Roo.TabPanel} this
25254          * @param {Roo.TabPanelItem} activePanel The new active tab
25255          */
25256         "tabchange": true,
25257         /**
25258          * @event beforetabchange
25259          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25260          * @param {Roo.TabPanel} this
25261          * @param {Object} e Set cancel to true on this object to cancel the tab change
25262          * @param {Roo.TabPanelItem} tab The tab being changed to
25263          */
25264         "beforetabchange" : true
25265     });
25266
25267     Roo.EventManager.onWindowResize(this.onResize, this);
25268     this.cpad = this.el.getPadding("lr");
25269     this.hiddenCount = 0;
25270
25271     Roo.TabPanel.superclass.constructor.call(this);
25272 };
25273
25274 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25275         /*
25276          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25277          */
25278     tabPosition : "top",
25279         /*
25280          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25281          */
25282     currentTabWidth : 0,
25283         /*
25284          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25285          */
25286     minTabWidth : 40,
25287         /*
25288          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25289          */
25290     maxTabWidth : 250,
25291         /*
25292          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25293          */
25294     preferredTabWidth : 175,
25295         /*
25296          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25297          */
25298     resizeTabs : false,
25299         /*
25300          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25301          */
25302     monitorResize : true,
25303
25304     /**
25305      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25306      * @param {String} id The id of the div to use <b>or create</b>
25307      * @param {String} text The text for the tab
25308      * @param {String} content (optional) Content to put in the TabPanelItem body
25309      * @param {Boolean} closable (optional) True to create a close icon on the tab
25310      * @return {Roo.TabPanelItem} The created TabPanelItem
25311      */
25312     addTab : function(id, C, D, E){
25313         var  F = new  Roo.TabPanelItem(this, id, C, E);
25314         this.addTabItem(F);
25315         if(D){
25316             F.setContent(D);
25317         }
25318         return  F;
25319     },
25320
25321     /**
25322      * Returns the {@link Roo.TabPanelItem} with the specified id/index
25323      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25324      * @return {Roo.TabPanelItem}
25325      */
25326     getTab : function(id){
25327         return  this.items[id];
25328     },
25329
25330     /**
25331      * Hides the {@link Roo.TabPanelItem} with the specified id/index
25332      * @param {String/Number} id The id or index of the TabPanelItem to hide.
25333      */
25334     hideTab : function(id){
25335         var  t = this.items[id];
25336         if(!t.isHidden()){
25337            t.setHidden(true);
25338            this.hiddenCount++;
25339            this.autoSizeTabs();
25340         }
25341     },
25342
25343     /**
25344      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25345      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25346      */
25347     unhideTab : function(id){
25348         var  t = this.items[id];
25349         if(t.isHidden()){
25350            t.setHidden(false);
25351            this.hiddenCount--;
25352            this.autoSizeTabs();
25353         }
25354     },
25355
25356     /**
25357      * Adds an existing {@link Roo.TabPanelItem}.
25358      * @param {Roo.TabPanelItem} item The TabPanelItem to add
25359      */
25360     addTabItem : function(G){
25361         this.items[G.id] = G;
25362         this.items.push(G);
25363         if(this.resizeTabs){
25364            G.setWidth(this.currentTabWidth || this.preferredTabWidth);
25365            this.autoSizeTabs();
25366         }else {
25367             G.autoSize();
25368         }
25369     },
25370
25371     /**
25372      * Removes a {@link Roo.TabPanelItem}.
25373      * @param {String/Number} id The id or index of the TabPanelItem to remove.
25374      */
25375     removeTab : function(id){
25376         var  H = this.items;
25377         var  I = H[id];
25378         if(!I) return;
25379         var  J = H.indexOf(I);
25380         if(this.active == I && H.length > 1){
25381             var  newTab = this.getNextAvailable(J);
25382             if(newTab)newTab.activate();
25383         }
25384
25385         this.stripEl.dom.removeChild(I.pnode.dom);
25386         if(I.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25387             this.bodyEl.dom.removeChild(I.bodyEl.dom);
25388         }
25389
25390         H.splice(J, 1);
25391         delete  this.items[I.id];
25392         I.fireEvent("close", I);
25393         I.purgeListeners();
25394         this.autoSizeTabs();
25395     },
25396
25397     getNextAvailable : function(K){
25398         var  L = this.items;
25399         var  M = K;
25400         // look for a next tab that will slide over to
25401         // replace the one being removed
25402         while(M < L.length){
25403             var  G = L[++M];
25404             if(G && !G.isHidden()){
25405                 return  G;
25406             }
25407         }
25408
25409         // if one isn't found select the previous tab (on the left)
25410         M = K;
25411         while(M >= 0){
25412             var  G = L[--M];
25413             if(G && !G.isHidden()){
25414                 return  G;
25415             }
25416         }
25417         return  null;
25418     },
25419
25420     /**
25421      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25422      * @param {String/Number} id The id or index of the TabPanelItem to disable.
25423      */
25424     disableTab : function(id){
25425         var  N = this.items[id];
25426         if(N && this.active != N){
25427             N.disable();
25428         }
25429     },
25430
25431     /**
25432      * Enables a {@link Roo.TabPanelItem} that is disabled.
25433      * @param {String/Number} id The id or index of the TabPanelItem to enable.
25434      */
25435     enableTab : function(id){
25436         var  O = this.items[id];
25437         O.enable();
25438     },
25439
25440     /**
25441      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25442      * @param {String/Number} id The id or index of the TabPanelItem to activate.
25443      * @return {Roo.TabPanelItem} The TabPanelItem.
25444      */
25445     activate : function(id){
25446         var  P = this.items[id];
25447         if(!P){
25448             return  null;
25449         }
25450         if(P == this.active || P.disabled){
25451             return  P;
25452         }
25453         var  e = {};
25454         this.fireEvent("beforetabchange", this, e, P);
25455         if(e.cancel !== true && !P.disabled){
25456             if(this.active){
25457                 this.active.hide();
25458             }
25459
25460             this.active = this.items[id];
25461             this.active.show();
25462             this.fireEvent("tabchange", this, this.active);
25463         }
25464         return  P;
25465     },
25466
25467     /**
25468      * Gets the active {@link Roo.TabPanelItem}.
25469      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25470      */
25471     getActiveTab : function(){
25472         return  this.active;
25473     },
25474
25475     /**
25476      * Updates the tab body element to fit the height of the container element
25477      * for overflow scrolling
25478      * @param {Number} targetHeight (optional) Override the starting height from the elements height
25479      */
25480     syncHeight : function(Q){
25481         var  R = (Q || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25482         var  bm = this.bodyEl.getMargins();
25483         var  S = R-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25484         this.bodyEl.setHeight(S);
25485         return  S;
25486     },
25487
25488     onResize : function(){
25489         if(this.monitorResize){
25490             this.autoSizeTabs();
25491         }
25492     },
25493
25494     /**
25495      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25496      */
25497     beginUpdate : function(){
25498         this.updating = true;
25499     },
25500
25501     /**
25502      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25503      */
25504     endUpdate : function(){
25505         this.updating = false;
25506         this.autoSizeTabs();
25507     },
25508
25509     /**
25510      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25511      */
25512     autoSizeTabs : function(){
25513         var  T = this.items.length;
25514         var  U = T - this.hiddenCount;
25515         if(!this.resizeTabs || T < 1 || U < 1 || this.updating) return;
25516         var  w = Math.max(this.el.getWidth() - this.cpad, 10);
25517         var  V = Math.floor(w / U);
25518         var  b = this.stripBody;
25519         if(b.getWidth() > w){
25520             var  tabs = this.items;
25521             this.setTabWidth(Math.max(V, this.minTabWidth)-2);
25522             if(V < this.minTabWidth){
25523                 /*if(!this.sleft){    // incomplete scrolling code
25524                     this.createScrollButtons();
25525                 }
25526                 this.showScroll();
25527                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25528             }
25529         }else {
25530             if(this.currentTabWidth < this.preferredTabWidth){
25531                 this.setTabWidth(Math.min(V, this.preferredTabWidth)-2);
25532             }
25533         }
25534     },
25535
25536     /**
25537      * Returns the number of tabs in this TabPanel.
25538      * @return {Number}
25539      */
25540      getCount : function(){
25541          return  this.items.length;
25542      },
25543
25544     /**
25545      * Resizes all the tabs to the passed width
25546      * @param {Number} The new width
25547      */
25548     setTabWidth : function(W){
25549         this.currentTabWidth = W;
25550         for(var  i = 0, len = this.items.length; i < len; i++) {
25551                 if(!this.items[i].isHidden())this.items[i].setWidth(W);
25552         }
25553     },
25554
25555     /**
25556      * Destroys this TabPanel
25557      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25558      */
25559     destroy : function(X){
25560         Roo.EventManager.removeResizeListener(this.onResize, this);
25561         for(var  i = 0, len = this.items.length; i < len; i++){
25562             this.items[i].purgeListeners();
25563         }
25564         if(X === true){
25565             this.el.update("");
25566             this.el.remove();
25567         }
25568     }
25569 });
25570
25571 /**
25572  * @class Roo.TabPanelItem
25573  * @extends Roo.util.Observable
25574  * Represents an individual item (tab plus body) in a TabPanel.
25575  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25576  * @param {String} id The id of this TabPanelItem
25577  * @param {String} text The text for the tab of this TabPanelItem
25578  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25579  */
25580 Roo.TabPanelItem = function(Y, id, Z, a){
25581     /**
25582      * The {@link Roo.TabPanel} this TabPanelItem belongs to
25583      * @type Roo.TabPanel
25584      */
25585     this.tabPanel = Y;
25586     /**
25587      * The id for this TabPanelItem
25588      * @type String
25589      */
25590     this.id = id;
25591     /** @private */
25592     this.disabled = false;
25593     /** @private */
25594     this.text = Z;
25595     /** @private */
25596     this.loaded = false;
25597     this.closable = a;
25598
25599     /**
25600      * The body element for this TabPanelItem.
25601      * @type Roo.Element
25602      */
25603     this.bodyEl = Roo.get(Y.createItemBody(Y.bodyEl.dom, id));
25604     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25605     this.bodyEl.setStyle("display", "block");
25606     this.bodyEl.setStyle("zoom", "1");
25607     this.hideAction();
25608
25609     var  d = Y.createStripElements(Y.stripEl.dom, Z, a);
25610     /** @private */
25611     this.el = Roo.get(d.el, true);
25612     this.inner = Roo.get(d.inner, true);
25613     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25614     this.pnode = Roo.get(d.el.parentNode, true);
25615     this.el.on("mousedown", this.onTabMouseDown, this);
25616     this.el.on("click", this.onTabClick, this);
25617     /** @private */
25618     if(a){
25619         var  c = Roo.get(d.close, true);
25620         c.dom.title = this.closeText;
25621         c.addClassOnOver("close-over");
25622         c.on("click", this.closeClick, this);
25623      }
25624
25625
25626     this.addEvents({
25627          /**
25628          * @event activate
25629          * Fires when this tab becomes the active tab.
25630          * @param {Roo.TabPanel} tabPanel The parent TabPanel
25631          * @param {Roo.TabPanelItem} this
25632          */
25633         "activate": true,
25634         /**
25635          * @event beforeclose
25636          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25637          * @param {Roo.TabPanelItem} this
25638          * @param {Object} e Set cancel to true on this object to cancel the close.
25639          */
25640         "beforeclose": true,
25641         /**
25642          * @event close
25643          * Fires when this tab is closed.
25644          * @param {Roo.TabPanelItem} this
25645          */
25646          "close": true,
25647         /**
25648          * @event deactivate
25649          * Fires when this tab is no longer the active tab.
25650          * @param {Roo.TabPanel} tabPanel The parent TabPanel
25651          * @param {Roo.TabPanelItem} this
25652          */
25653          "deactivate" : true
25654     });
25655     this.hidden = false;
25656
25657     Roo.TabPanelItem.superclass.constructor.call(this);
25658 };
25659
25660 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25661     purgeListeners : function(){
25662        Roo.util.Observable.prototype.purgeListeners.call(this);
25663        this.el.removeAllListeners();
25664     },
25665     /**
25666      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25667      */
25668     show : function(){
25669         this.pnode.addClass("on");
25670         this.showAction();
25671         if(Roo.isOpera){
25672             this.tabPanel.stripWrap.repaint();
25673         }
25674
25675         this.fireEvent("activate", this.tabPanel, this);
25676     },
25677
25678     /**
25679      * Returns true if this tab is the active tab.
25680      * @return {Boolean}
25681      */
25682     isActive : function(){
25683         return  this.tabPanel.getActiveTab() == this;
25684     },
25685
25686     /**
25687      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25688      */
25689     hide : function(){
25690         this.pnode.removeClass("on");
25691         this.hideAction();
25692         this.fireEvent("deactivate", this.tabPanel, this);
25693     },
25694
25695     hideAction : function(){
25696         this.bodyEl.hide();
25697         this.bodyEl.setStyle("position", "absolute");
25698         this.bodyEl.setLeft("-20000px");
25699         this.bodyEl.setTop("-20000px");
25700     },
25701
25702     showAction : function(){
25703         this.bodyEl.setStyle("position", "relative");
25704         this.bodyEl.setTop("");
25705         this.bodyEl.setLeft("");
25706         this.bodyEl.show();
25707     },
25708
25709     /**
25710      * Set the tooltip for the tab.
25711      * @param {String} tooltip The tab's tooltip
25712      */
25713     setTooltip : function(f){
25714         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25715             this.textEl.dom.qtip = f;
25716             this.textEl.dom.removeAttribute('title');
25717         }else {
25718             this.textEl.dom.title = f;
25719         }
25720     },
25721
25722     onTabClick : function(e){
25723         e.preventDefault();
25724         this.tabPanel.activate(this.id);
25725     },
25726
25727     onTabMouseDown : function(e){
25728         e.preventDefault();
25729         this.tabPanel.activate(this.id);
25730     },
25731
25732     getWidth : function(){
25733         return  this.inner.getWidth();
25734     },
25735
25736     setWidth : function(g){
25737         var  h = g - this.pnode.getPadding("lr");
25738         this.inner.setWidth(h);
25739         this.textEl.setWidth(h-this.inner.getPadding("lr"));
25740         this.pnode.setWidth(g);
25741     },
25742
25743     /**
25744      * Show or hide the tab
25745      * @param {Boolean} hidden True to hide or false to show.
25746      */
25747     setHidden : function(j){
25748         this.hidden = j;
25749         this.pnode.setStyle("display", j ? "none" : "");
25750     },
25751
25752     /**
25753      * Returns true if this tab is "hidden"
25754      * @return {Boolean}
25755      */
25756     isHidden : function(){
25757         return  this.hidden;
25758     },
25759
25760     /**
25761      * Returns the text for this tab
25762      * @return {String}
25763      */
25764     getText : function(){
25765         return  this.text;
25766     },
25767
25768     autoSize : function(){
25769         //this.el.beginMeasure();
25770         this.textEl.setWidth(1);
25771         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25772         //this.el.endMeasure();
25773     },
25774
25775     /**
25776      * Sets the text for the tab (Note: this also sets the tooltip text)
25777      * @param {String} text The tab's text and tooltip
25778      */
25779     setText : function(k){
25780         this.text = k;
25781         this.textEl.update(k);
25782         this.setTooltip(k);
25783         if(!this.tabPanel.resizeTabs){
25784             this.autoSize();
25785         }
25786     },
25787     /**
25788      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25789      */
25790     activate : function(){
25791         this.tabPanel.activate(this.id);
25792     },
25793
25794     /**
25795      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25796      */
25797     disable : function(){
25798         if(this.tabPanel.active != this){
25799             this.disabled = true;
25800             this.pnode.addClass("disabled");
25801         }
25802     },
25803
25804     /**
25805      * Enables this TabPanelItem if it was previously disabled.
25806      */
25807     enable : function(){
25808         this.disabled = false;
25809         this.pnode.removeClass("disabled");
25810     },
25811
25812     /**
25813      * Sets the content for this TabPanelItem.
25814      * @param {String} content The content
25815      * @param {Boolean} loadScripts true to look for and load scripts
25816      */
25817     setContent : function(l, m){
25818         this.bodyEl.update(l, m);
25819     },
25820
25821     /**
25822      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25823      * @return {Roo.UpdateManager} The UpdateManager
25824      */
25825     getUpdateManager : function(){
25826         return  this.bodyEl.getUpdateManager();
25827     },
25828
25829     /**
25830      * Set a URL to be used to load the content for this TabPanelItem.
25831      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25832      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
25833      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
25834      * @return {Roo.UpdateManager} The UpdateManager
25835      */
25836     setUrl : function(n, o, p){
25837         if(this.refreshDelegate){
25838             this.un('activate', this.refreshDelegate);
25839         }
25840
25841         this.refreshDelegate = this._handleRefresh.createDelegate(this, [n, o, p]);
25842         this.on("activate", this.refreshDelegate);
25843         return  this.bodyEl.getUpdateManager();
25844     },
25845
25846     /** @private */
25847     _handleRefresh : function(q, r, s){
25848         if(!s || !this.loaded){
25849             var  updater = this.bodyEl.getUpdateManager();
25850             updater.update(q, r, this._setLoaded.createDelegate(this));
25851         }
25852     },
25853
25854     /**
25855      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
25856      *   Will fail silently if the setUrl method has not been called.
25857      *   This does not activate the panel, just updates its content.
25858      */
25859     refresh : function(){
25860         if(this.refreshDelegate){
25861            this.loaded = false;
25862            this.refreshDelegate();
25863         }
25864     },
25865
25866     /** @private */
25867     _setLoaded : function(){
25868         this.loaded = true;
25869     },
25870
25871     /** @private */
25872     closeClick : function(e){
25873         var  o = {};
25874         e.stopEvent();
25875         this.fireEvent("beforeclose", this, o);
25876         if(o.cancel !== true){
25877             this.tabPanel.removeTab(this.id);
25878         }
25879     },
25880     /**
25881      * The text displayed in the tooltip for the close icon.
25882      * @type String
25883      */
25884     closeText : "Close this tab"
25885 });
25886
25887 /** @private */
25888 Roo.TabPanel.prototype.createStrip = function(u){
25889     var  v = document.createElement("div");
25890     v.className = "x-tabs-wrap";
25891     u.appendChild(v);
25892     return  v;
25893 };
25894 /** @private */
25895 Roo.TabPanel.prototype.createStripList = function(x){
25896     // div wrapper for retard IE
25897     x.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25898     return  x.firstChild.firstChild.firstChild.firstChild;
25899 };
25900 /** @private */
25901 Roo.TabPanel.prototype.createBody = function(y){
25902     var  z = document.createElement("div");
25903     Roo.id(z, "tab-body");
25904     Roo.fly(z).addClass("x-tabs-body");
25905     y.appendChild(z);
25906     return  z;
25907 };
25908 /** @private */
25909 Roo.TabPanel.prototype.createItemBody = function(AA, id){
25910     var  AB = Roo.getDom(id);
25911     if(!AB){
25912         AB = document.createElement("div");
25913         AB.id = id;
25914     }
25915
25916     Roo.fly(AB).addClass("x-tabs-item-body");
25917     AA.insertBefore(AB, AA.firstChild);
25918     return  AB;
25919 };
25920 /** @private */
25921 Roo.TabPanel.prototype.createStripElements = function(AC, AD, AE){
25922     var  td = document.createElement("td");
25923     AC.appendChild(td);
25924     if(AE){
25925         td.className = "x-tabs-closable";
25926         if(!this.closeTpl){
25927             this.closeTpl = new  Roo.Template(
25928                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25929                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25930                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
25931             );
25932         }
25933         var  el = this.closeTpl.overwrite(td, {"text": AD});
25934         var  close = el.getElementsByTagName("div")[0];
25935         var  inner = el.getElementsByTagName("em")[0];
25936         return  {"el": el, "close": close, "inner": inner};
25937     } else  {
25938         if(!this.tabTpl){
25939             this.tabTpl = new  Roo.Template(
25940                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25941                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25942             );
25943         }
25944         var  el = this.tabTpl.overwrite(td, {"text": AD});
25945         var  inner = el.getElementsByTagName("em")[0];
25946         return  {"el": el, "inner": inner};
25947     }
25948 };
25949 /*
25950  * Based on:
25951  * Ext JS Library 1.1.1
25952  * Copyright(c) 2006-2007, Ext JS, LLC.
25953  *
25954  * Originally Released Under LGPL - original licence link has changed is not relivant.
25955  *
25956  * Fork - LGPL
25957  * <script type="text/javascript">
25958  */
25959
25960 /**
25961  * @class Roo.Button
25962  * @extends Roo.util.Observable
25963  * Simple Button class
25964  * @cfg {String} text The button text
25965  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25966  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25967  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25968  * @cfg {Object} scope The scope of the handler
25969  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25970  * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25971  * @cfg {Boolean} hidden True to start hidden (defaults to false)
25972  * @cfg {Boolean} disabled True to start disabled (defaults to false)
25973  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25974  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25975    applies if enableToggle = true)
25976  * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25977  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25978   an {@link Roo.util.ClickRepeater} config object (defaults to false).
25979  * @constructor
25980  * Create a new button
25981  * @param {Object} config The config object
25982  */
25983 Roo.Button = function(A, B)
25984 {
25985     if (!B) {
25986         B = A;
25987         A = B.renderTo || false;
25988     }
25989
25990     
25991     Roo.apply(this, B);
25992     this.addEvents({
25993         /**
25994              * @event click
25995              * Fires when this button is clicked
25996              * @param {Button} this
25997              * @param {EventObject} e The click event
25998              */
25999             "click" : true,
26000         /**
26001              * @event toggle
26002              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26003              * @param {Button} this
26004              * @param {Boolean} pressed
26005              */
26006             "toggle" : true,
26007         /**
26008              * @event mouseover
26009              * Fires when the mouse hovers over the button
26010              * @param {Button} this
26011              * @param {Event} e The event object
26012              */
26013         'mouseover' : true,
26014         /**
26015              * @event mouseout
26016              * Fires when the mouse exits the button
26017              * @param {Button} this
26018              * @param {Event} e The event object
26019              */
26020         'mouseout': true,
26021          /**
26022              * @event render
26023              * Fires when the button is rendered
26024              * @param {Button} this
26025              */
26026         'render': true
26027     });
26028     if(this.menu){
26029         this.menu = Roo.menu.MenuMgr.get(this.menu);
26030     }
26031     if(A){
26032         this.render(A);
26033     }
26034
26035     
26036     Roo.util.Observable.call(this);
26037 };
26038
26039 Roo.extend(Roo.Button, Roo.util.Observable, {
26040     /**
26041      * 
26042      */
26043     
26044     /**
26045      * Read-only. True if this button is hidden
26046      * @type Boolean
26047      */
26048     hidden : false,
26049     /**
26050      * Read-only. True if this button is disabled
26051      * @type Boolean
26052      */
26053     disabled : false,
26054     /**
26055      * Read-only. True if this button is pressed (only if enableToggle = true)
26056      * @type Boolean
26057      */
26058     pressed : false,
26059
26060     /**
26061      * @cfg {Number} tabIndex 
26062      * The DOM tabIndex for this button (defaults to undefined)
26063      */
26064     tabIndex : undefined,
26065
26066     /**
26067      * @cfg {Boolean} enableToggle
26068      * True to enable pressed/not pressed toggling (defaults to false)
26069      */
26070     enableToggle: false,
26071     /**
26072      * @cfg {Mixed} menu
26073      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26074      */
26075     menu : undefined,
26076     /**
26077      * @cfg {String} menuAlign
26078      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26079      */
26080     menuAlign : "tl-bl?",
26081
26082     /**
26083      * @cfg {String} iconCls
26084      * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26085      */
26086     iconCls : undefined,
26087     /**
26088      * @cfg {String} type
26089      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
26090      */
26091     type : 'button',
26092
26093     // private
26094     menuClassTarget: 'tr',
26095
26096     /**
26097      * @cfg {String} clickEvent
26098      * The type of event to map to the button's event handler (defaults to 'click')
26099      */
26100     clickEvent : 'click',
26101
26102     /**
26103      * @cfg {Boolean} handleMouseEvents
26104      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26105      */
26106     handleMouseEvents : true,
26107
26108     /**
26109      * @cfg {String} tooltipType
26110      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26111      */
26112     tooltipType : 'qtip',
26113
26114     /**
26115      * @cfg {String} cls
26116      * A CSS class to apply to the button's main element.
26117      */
26118     
26119     /**
26120      * @cfg {Roo.Template} template (Optional)
26121      * An {@link Roo.Template} with which to create the Button's main element. This Template must
26122      * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26123      * require code modifications if required elements (e.g. a button) aren't present.
26124      */
26125
26126     // private
26127     render : function(C){
26128         var  D;
26129         if(this.hideParent){
26130             this.parentEl = Roo.get(C);
26131         }
26132         if(!this.dhconfig){
26133             if(!this.template){
26134                 if(!Roo.Button.buttonTemplate){
26135                     // hideous table template
26136                     Roo.Button.buttonTemplate = new  Roo.Template(
26137                         '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26138                         '<td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i>&#160;</i></td>',
26139                         "</tr></tbody></table>");
26140                 }
26141
26142                 this.template = Roo.Button.buttonTemplate;
26143             }
26144
26145             D = this.template.append(C, [this.text || '&#160;', this.type], true);
26146             var  btnEl = D.child("button:first");
26147             btnEl.on('focus', this.onFocus, this);
26148             btnEl.on('blur', this.onBlur, this);
26149             if(this.cls){
26150                 D.addClass(this.cls);
26151             }
26152             if(this.icon){
26153                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26154             }
26155             if(this.iconCls){
26156                 btnEl.addClass(this.iconCls);
26157                 if(!this.cls){
26158                     D.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26159                 }
26160             }
26161             if(this.tabIndex !== undefined){
26162                 btnEl.dom.tabIndex = this.tabIndex;
26163             }
26164             if(this.tooltip){
26165                 if(typeof  this.tooltip == 'object'){
26166                     Roo.QuickTips.tips(Roo.apply({
26167                           target: btnEl.id
26168                     }, this.tooltip));
26169                 } else  {
26170                     btnEl.dom[this.tooltipType] = this.tooltip;
26171                 }
26172             }
26173         }else {
26174             D = Roo.DomHelper.append(Roo.get(C).dom, this.dhconfig, true);
26175         }
26176
26177         this.el = D;
26178         if(this.id){
26179             this.el.dom.id = this.el.id = this.id;
26180         }
26181         if(this.menu){
26182             this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26183             this.menu.on("show", this.onMenuShow, this);
26184             this.menu.on("hide", this.onMenuHide, this);
26185         }
26186
26187         D.addClass("x-btn");
26188         if(Roo.isIE && !Roo.isIE7){
26189             this.autoWidth.defer(1, this);
26190         }else {
26191             this.autoWidth();
26192         }
26193         if(this.handleMouseEvents){
26194             D.on("mouseover", this.onMouseOver, this);
26195             D.on("mouseout", this.onMouseOut, this);
26196             D.on("mousedown", this.onMouseDown, this);
26197         }
26198
26199         D.on(this.clickEvent, this.onClick, this);
26200         //btn.on("mouseup", this.onMouseUp, this);
26201         if(this.hidden){
26202             this.hide();
26203         }
26204         if(this.disabled){
26205             this.disable();
26206         }
26207
26208         Roo.ButtonToggleMgr.register(this);
26209         if(this.pressed){
26210             this.el.addClass("x-btn-pressed");
26211         }
26212         if(this.repeat){
26213             var  repeater = new  Roo.util.ClickRepeater(D,
26214                 typeof  this.repeat == "object" ? this.repeat : {}
26215             );
26216             repeater.on("click", this.onClick,  this);
26217         }
26218
26219         this.fireEvent('render', this);
26220         
26221     },
26222     /**
26223      * Returns the button's underlying element
26224      * @return {Roo.Element} The element
26225      */
26226     getEl : function(){
26227         return  this.el;  
26228     },
26229     
26230     /**
26231      * Destroys this Button and removes any listeners.
26232      */
26233     destroy : function(){
26234         Roo.ButtonToggleMgr.unregister(this);
26235         this.el.removeAllListeners();
26236         this.purgeListeners();
26237         this.el.remove();
26238     },
26239
26240     // private
26241     autoWidth : function(){
26242         if(this.el){
26243             this.el.setWidth("auto");
26244             if(Roo.isIE7 && Roo.isStrict){
26245                 var  ib = this.el.child('button');
26246                 if(ib && ib.getWidth() > 20){
26247                     ib.clip();
26248                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26249                 }
26250             }
26251             if(this.minWidth){
26252                 if(this.hidden){
26253                     this.el.beginMeasure();
26254                 }
26255                 if(this.el.getWidth() < this.minWidth){
26256                     this.el.setWidth(this.minWidth);
26257                 }
26258                 if(this.hidden){
26259                     this.el.endMeasure();
26260                 }
26261             }
26262         }
26263     },
26264
26265     /**
26266      * Assigns this button's click handler
26267      * @param {Function} handler The function to call when the button is clicked
26268      * @param {Object} scope (optional) Scope for the function passed in
26269      */
26270     setHandler : function(E, F){
26271         this.handler = E;
26272         this.scope = F;  
26273     },
26274     
26275     /**
26276      * Sets this button's text
26277      * @param {String} text The button text
26278      */
26279     setText : function(G){
26280         this.text = G;
26281         if(this.el){
26282             this.el.child("td.x-btn-center button.x-btn-text").update(G);
26283         }
26284
26285         this.autoWidth();
26286     },
26287     
26288     /**
26289      * Gets the text for this button
26290      * @return {String} The button text
26291      */
26292     getText : function(){
26293         return  this.text;  
26294     },
26295     
26296     /**
26297      * Show this button
26298      */
26299     show: function(){
26300         this.hidden = false;
26301         if(this.el){
26302             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26303         }
26304     },
26305     
26306     /**
26307      * Hide this button
26308      */
26309     hide: function(){
26310         this.hidden = true;
26311         if(this.el){
26312             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26313         }
26314     },
26315     
26316     /**
26317      * Convenience function for boolean show/hide
26318      * @param {Boolean} visible True to show, false to hide
26319      */
26320     setVisible: function(H){
26321         if(H) {
26322             this.show();
26323         }else {
26324             this.hide();
26325         }
26326     },
26327     
26328     /**
26329      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26330      * @param {Boolean} state (optional) Force a particular state
26331      */
26332     toggle : function(I){
26333         I = I === undefined ? !this.pressed : I;
26334         if(I != this.pressed){
26335             if(I){
26336                 this.el.addClass("x-btn-pressed");
26337                 this.pressed = true;
26338                 this.fireEvent("toggle", this, true);
26339             }else {
26340                 this.el.removeClass("x-btn-pressed");
26341                 this.pressed = false;
26342                 this.fireEvent("toggle", this, false);
26343             }
26344             if(this.toggleHandler){
26345                 this.toggleHandler.call(this.scope || this, this, I);
26346             }
26347         }
26348     },
26349     
26350     /**
26351      * Focus the button
26352      */
26353     focus : function(){
26354         this.el.child('button:first').focus();
26355     },
26356     
26357     /**
26358      * Disable this button
26359      */
26360     disable : function(){
26361         if(this.el){
26362             this.el.addClass("x-btn-disabled");
26363         }
26364
26365         this.disabled = true;
26366     },
26367     
26368     /**
26369      * Enable this button
26370      */
26371     enable : function(){
26372         if(this.el){
26373             this.el.removeClass("x-btn-disabled");
26374         }
26375
26376         this.disabled = false;
26377     },
26378
26379     /**
26380      * Convenience function for boolean enable/disable
26381      * @param {Boolean} enabled True to enable, false to disable
26382      */
26383     setDisabled : function(v){
26384         this[v !== true ? "enable" : "disable"]();
26385     },
26386
26387     // private
26388     onClick : function(e){
26389         if(e){
26390             e.preventDefault();
26391         }
26392         if(e.button != 0){
26393             return;
26394         }
26395         if(!this.disabled){
26396             if(this.enableToggle){
26397                 this.toggle();
26398             }
26399             if(this.menu && !this.menu.isVisible()){
26400                 this.menu.show(this.el, this.menuAlign);
26401             }
26402
26403             this.fireEvent("click", this, e);
26404             if(this.handler){
26405                 this.el.removeClass("x-btn-over");
26406                 this.handler.call(this.scope || this, this, e);
26407             }
26408         }
26409     },
26410     // private
26411     onMouseOver : function(e){
26412         if(!this.disabled){
26413             this.el.addClass("x-btn-over");
26414             this.fireEvent('mouseover', this, e);
26415         }
26416     },
26417     // private
26418     onMouseOut : function(e){
26419         if(!e.within(this.el,  true)){
26420             this.el.removeClass("x-btn-over");
26421             this.fireEvent('mouseout', this, e);
26422         }
26423     },
26424     // private
26425     onFocus : function(e){
26426         if(!this.disabled){
26427             this.el.addClass("x-btn-focus");
26428         }
26429     },
26430     // private
26431     onBlur : function(e){
26432         this.el.removeClass("x-btn-focus");
26433     },
26434     // private
26435     onMouseDown : function(e){
26436         if(!this.disabled && e.button == 0){
26437             this.el.addClass("x-btn-click");
26438             Roo.get(document).on('mouseup', this.onMouseUp, this);
26439         }
26440     },
26441     // private
26442     onMouseUp : function(e){
26443         if(e.button == 0){
26444             this.el.removeClass("x-btn-click");
26445             Roo.get(document).un('mouseup', this.onMouseUp, this);
26446         }
26447     },
26448     // private
26449     onMenuShow : function(e){
26450         this.el.addClass("x-btn-menu-active");
26451     },
26452     // private
26453     onMenuHide : function(e){
26454         this.el.removeClass("x-btn-menu-active");
26455     }   
26456 });
26457
26458 // Private utility class used by Button
26459 Roo.ButtonToggleMgr = function(){
26460    var  J = {};
26461    
26462    function  K(L, M){
26463        if(M){
26464            var  g = J[L.toggleGroup];
26465            for(var  i = 0, l = g.length; i < l; i++){
26466                if(g[i] != L){
26467                    g[i].toggle(false);
26468                }
26469            }
26470        }
26471    }
26472    
26473    return  {
26474        register : function(N){
26475            if(!N.toggleGroup){
26476                return;
26477            }
26478            var  g = J[N.toggleGroup];
26479            if(!g){
26480                g = J[N.toggleGroup] = [];
26481            }
26482
26483            g.push(N);
26484            N.on("toggle", K);
26485        },
26486        
26487        unregister : function(O){
26488            if(!O.toggleGroup){
26489                return;
26490            }
26491            var  g = J[O.toggleGroup];
26492            if(g){
26493                g.remove(O);
26494                O.un("toggle", K);
26495            }
26496        }
26497    };
26498 }();
26499 /*
26500  * Based on:
26501  * Ext JS Library 1.1.1
26502  * Copyright(c) 2006-2007, Ext JS, LLC.
26503  *
26504  * Originally Released Under LGPL - original licence link has changed is not relivant.
26505  *
26506  * Fork - LGPL
26507  * <script type="text/javascript">
26508  */
26509  
26510 /**
26511  * @class Roo.SplitButton
26512  * @extends Roo.Button
26513  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26514  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
26515  * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26516  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26517  * @cfg {String} arrowTooltip The title attribute of the arrow
26518  * @constructor
26519  * Create a new menu button
26520  * @param {String/HTMLElement/Element} renderTo The element to append the button to
26521  * @param {Object} config The config object
26522  */
26523 Roo.SplitButton = function(A, B){
26524     Roo.SplitButton.superclass.constructor.call(this, A, B);
26525     /**
26526      * @event arrowclick
26527      * Fires when this button's arrow is clicked
26528      * @param {SplitButton} this
26529      * @param {EventObject} e The click event
26530      */
26531     this.addEvents({"arrowclick":true});
26532 };
26533
26534 Roo.extend(Roo.SplitButton, Roo.Button, {
26535     render : function(C){
26536         // this is one sweet looking template!
26537         var  D = new  Roo.Template(
26538             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26539             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26540             '<tr><td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
26541             "</tbody></table></td><td>",
26542             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26543             '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button">&#160;</button></td><td class="x-btn-right"><i>&#160;</i></td></tr>',
26544             "</tbody></table></td></tr></table>"
26545         );
26546         var  E = D.append(C, [this.text, this.type], true);
26547         var  F = E.child("button");
26548         if(this.cls){
26549             E.addClass(this.cls);
26550         }
26551         if(this.icon){
26552             F.setStyle('background-image', 'url(' +this.icon +')');
26553         }
26554         if(this.iconCls){
26555             F.addClass(this.iconCls);
26556             if(!this.cls){
26557                 E.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26558             }
26559         }
26560
26561         this.el = E;
26562         if(this.handleMouseEvents){
26563             E.on("mouseover", this.onMouseOver, this);
26564             E.on("mouseout", this.onMouseOut, this);
26565             E.on("mousedown", this.onMouseDown, this);
26566             E.on("mouseup", this.onMouseUp, this);
26567         }
26568
26569         E.on(this.clickEvent, this.onClick, this);
26570         if(this.tooltip){
26571             if(typeof  this.tooltip == 'object'){
26572                 Roo.QuickTips.tips(Roo.apply({
26573                       target: F.id
26574                 }, this.tooltip));
26575             } else  {
26576                 F.dom[this.tooltipType] = this.tooltip;
26577             }
26578         }
26579         if(this.arrowTooltip){
26580             E.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26581         }
26582         if(this.hidden){
26583             this.hide();
26584         }
26585         if(this.disabled){
26586             this.disable();
26587         }
26588         if(this.pressed){
26589             this.el.addClass("x-btn-pressed");
26590         }
26591         if(Roo.isIE && !Roo.isIE7){
26592             this.autoWidth.defer(1, this);
26593         }else {
26594             this.autoWidth();
26595         }
26596         if(this.menu){
26597             this.menu.on("show", this.onMenuShow, this);
26598             this.menu.on("hide", this.onMenuHide, this);
26599         }
26600
26601         this.fireEvent('render', this);
26602     },
26603
26604     // private
26605     autoWidth : function(){
26606         if(this.el){
26607             var  tbl = this.el.child("table:first");
26608             var  tbl2 = this.el.child("table:last");
26609             this.el.setWidth("auto");
26610             tbl.setWidth("auto");
26611             if(Roo.isIE7 && Roo.isStrict){
26612                 var  ib = this.el.child('button:first');
26613                 if(ib && ib.getWidth() > 20){
26614                     ib.clip();
26615                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26616                 }
26617             }
26618             if(this.minWidth){
26619                 if(this.hidden){
26620                     this.el.beginMeasure();
26621                 }
26622                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26623                     tbl.setWidth(this.minWidth-tbl2.getWidth());
26624                 }
26625                 if(this.hidden){
26626                     this.el.endMeasure();
26627                 }
26628             }
26629
26630             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26631         } 
26632     },
26633     /**
26634      * Sets this button's click handler
26635      * @param {Function} handler The function to call when the button is clicked
26636      * @param {Object} scope (optional) Scope for the function passed above
26637      */
26638     setHandler : function(G, H){
26639         this.handler = G;
26640         this.scope = H;  
26641     },
26642     
26643     /**
26644      * Sets this button's arrow click handler
26645      * @param {Function} handler The function to call when the arrow is clicked
26646      * @param {Object} scope (optional) Scope for the function passed above
26647      */
26648     setArrowHandler : function(I, J){
26649         this.arrowHandler = I;
26650         this.scope = J;  
26651     },
26652     
26653     /**
26654      * Focus the button
26655      */
26656     focus : function(){
26657         if(this.el){
26658             this.el.child("button:first").focus();
26659         }
26660     },
26661
26662     // private
26663     onClick : function(e){
26664         e.preventDefault();
26665         if(!this.disabled){
26666             if(e.getTarget(".x-btn-menu-arrow-wrap")){
26667                 if(this.menu && !this.menu.isVisible()){
26668                     this.menu.show(this.el, this.menuAlign);
26669                 }
26670
26671                 this.fireEvent("arrowclick", this, e);
26672                 if(this.arrowHandler){
26673                     this.arrowHandler.call(this.scope || this, this, e);
26674                 }
26675             }else {
26676                 this.fireEvent("click", this, e);
26677                 if(this.handler){
26678                     this.handler.call(this.scope || this, this, e);
26679                 }
26680             }
26681         }
26682     },
26683     // private
26684     onMouseDown : function(e){
26685         if(!this.disabled){
26686             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26687         }
26688     },
26689     // private
26690     onMouseUp : function(e){
26691         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26692     }   
26693 });
26694
26695
26696 // backwards compat
26697 Roo.MenuButton = Roo.SplitButton;
26698 /*
26699  * Based on:
26700  * Ext JS Library 1.1.1
26701  * Copyright(c) 2006-2007, Ext JS, LLC.
26702  *
26703  * Originally Released Under LGPL - original licence link has changed is not relivant.
26704  *
26705  * Fork - LGPL
26706  * <script type="text/javascript">
26707  */
26708
26709 /**
26710  * @class Roo.Toolbar
26711  * Basic Toolbar class.
26712  * @constructor
26713  * Creates a new Toolbar
26714  * @param {Object} config The config object
26715  */ 
26716 Roo.Toolbar = function(A, B, C)
26717 {
26718     /// old consturctor format still supported..
26719     if(A  instanceof  Array){ // omit the container for later rendering
26720         B = A;
26721         C = B;
26722         A = null;
26723     }
26724     if (typeof(A) == 'object' && A.xtype) {
26725         C = A;
26726         A = C.container;
26727         B = C.buttons; // not really - use items!!
26728     }
26729     var  D = [];
26730     if (C && C.items) {
26731         D = C.items;
26732         delete  C.items;
26733     }
26734
26735     Roo.apply(this, C);
26736     this.buttons = B;
26737     
26738     if(A){
26739         this.render(A);
26740     }
26741
26742     Roo.each(D, function(b) {
26743         this.add(b);
26744     }, this);
26745     
26746 };
26747
26748 Roo.Toolbar.prototype = {
26749     /**
26750      * @cfg {Roo.data.Store} items
26751      * array of button configs or elements to add
26752      */
26753     
26754     /**
26755      * @cfg {String/HTMLElement/Element} container
26756      * The id or element that will contain the toolbar
26757      */
26758     // private
26759     render : function(ct){
26760         this.el = Roo.get(ct);
26761         if(this.cls){
26762             this.el.addClass(this.cls);
26763         }
26764
26765         // using a table allows for vertical alignment
26766         // 100% width is needed by Safari...
26767         this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26768         this.tr = this.el.child("tr", true);
26769         var  E = 0;
26770         this.items = new  Roo.util.MixedCollection(false, function(o){
26771             return  o.id || ("item" + (++E));
26772         });
26773         if(this.buttons){
26774             this.add.apply(this, this.buttons);
26775             delete  this.buttons;
26776         }
26777     },
26778
26779     /**
26780      * Adds element(s) to the toolbar -- this function takes a variable number of 
26781      * arguments of mixed type and adds them to the toolbar.
26782      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26783      * <ul>
26784      * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26785      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26786      * <li>Field: Any form field (equivalent to {@link #addField})</li>
26787      * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26788      * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26789      * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26790      * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26791      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26792      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26793      * </ul>
26794      * @param {Mixed} arg2
26795      * @param {Mixed} etc.
26796      */
26797     add : function(){
26798         var  a = arguments, l = a.length;
26799         for(var  i = 0; i < l; i++){
26800             this._add(a[i]);
26801         }
26802     },
26803     // private..
26804     _add : function(el) {
26805         
26806         if (el.xtype) {
26807             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26808         }
26809         
26810         if (el.applyTo){ // some kind of form field
26811             return  this.addField(el);
26812         } 
26813         if (el.render){ // some kind of Toolbar.Item
26814             return  this.addItem(el);
26815         }
26816         if (typeof  el == "string"){ // string
26817             if(el == "separator" || el == "-"){
26818                 return  this.addSeparator();
26819             }
26820             if (el == " "){
26821                 return  this.addSpacer();
26822             }
26823             if(el == "->"){
26824                 return  this.addFill();
26825             }
26826             return  this.addText(el);
26827             
26828         }
26829         if(el.tagName){ // element
26830             return  this.addElement(el);
26831         }
26832         if(typeof  el == "object"){ // must be button config?
26833             return  this.addButton(el);
26834         }
26835         // and now what?!?!
26836         return  false;
26837         
26838     },
26839     
26840     /**
26841      * Add an Xtype element
26842      * @param {Object} xtype Xtype Object
26843      * @return {Object} created Object
26844      */
26845     addxtype : function(e){
26846         return  this.add(e);  
26847     },
26848     
26849     /**
26850      * Returns the Element for this toolbar.
26851      * @return {Roo.Element}
26852      */
26853     getEl : function(){
26854         return  this.el;  
26855     },
26856     
26857     /**
26858      * Adds a separator
26859      * @return {Roo.Toolbar.Item} The separator item
26860      */
26861     addSeparator : function(){
26862         return  this.addItem(new  Roo.Toolbar.Separator());
26863     },
26864
26865     /**
26866      * Adds a spacer element
26867      * @return {Roo.Toolbar.Spacer} The spacer item
26868      */
26869     addSpacer : function(){
26870         return  this.addItem(new  Roo.Toolbar.Spacer());
26871     },
26872
26873     /**
26874      * Adds a fill element that forces subsequent additions to the right side of the toolbar
26875      * @return {Roo.Toolbar.Fill} The fill item
26876      */
26877     addFill : function(){
26878         return  this.addItem(new  Roo.Toolbar.Fill());
26879     },
26880
26881     /**
26882      * Adds any standard HTML element to the toolbar
26883      * @param {String/HTMLElement/Element} el The element or id of the element to add
26884      * @return {Roo.Toolbar.Item} The element's item
26885      */
26886     addElement : function(el){
26887         return  this.addItem(new  Roo.Toolbar.Item(el));
26888     },
26889     /**
26890      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26891      * @type Roo.util.MixedCollection  
26892      */
26893     items : false,
26894      
26895     /**
26896      * Adds any Toolbar.Item or subclass
26897      * @param {Roo.Toolbar.Item} item
26898      * @return {Roo.Toolbar.Item} The item
26899      */
26900     addItem : function(F){
26901         var  td = this.nextBlock();
26902         F.render(td);
26903         this.items.add(F);
26904         return  F;
26905     },
26906     
26907     /**
26908      * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26909      * @param {Object/Array} config A button config or array of configs
26910      * @return {Roo.Toolbar.Button/Array}
26911      */
26912     addButton : function(G){
26913         if(G  instanceof  Array){
26914             var  B = [];
26915             for(var  i = 0, len = G.length; i < len; i++) {
26916                 B.push(this.addButton(G[i]));
26917             }
26918             return  B;
26919         }
26920         var  b = G;
26921         if(!(G  instanceof  Roo.Toolbar.Button)){
26922             b = G.split ?
26923                 new  Roo.Toolbar.SplitButton(G) :
26924                 new  Roo.Toolbar.Button(G);
26925         }
26926         var  td = this.nextBlock();
26927         b.render(td);
26928         this.items.add(b);
26929         return  b;
26930     },
26931     
26932     /**
26933      * Adds text to the toolbar
26934      * @param {String} text The text to add
26935      * @return {Roo.Toolbar.Item} The element's item
26936      */
26937     addText : function(H){
26938         return  this.addItem(new  Roo.Toolbar.TextItem(H));
26939     },
26940     
26941     /**
26942      * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26943      * @param {Number} index The index where the item is to be inserted
26944      * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26945      * @return {Roo.Toolbar.Button/Item}
26946      */
26947     insertButton : function(I, J){
26948         if(J  instanceof  Array){
26949             var  B = [];
26950             for(var  i = 0, len = J.length; i < len; i++) {
26951                B.push(this.insertButton(I + i, J[i]));
26952             }
26953             return  B;
26954         }
26955         if (!(J  instanceof  Roo.Toolbar.Button)){
26956            J = new  Roo.Toolbar.Button(J);
26957         }
26958         var  td = document.createElement("td");
26959         this.tr.insertBefore(td, this.tr.childNodes[I]);
26960         J.render(td);
26961         this.items.insert(I, J);
26962         return  J;
26963     },
26964     
26965     /**
26966      * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26967      * @param {Object} config
26968      * @return {Roo.Toolbar.Item} The element's item
26969      */
26970     addDom : function(K, L){
26971         var  td = this.nextBlock();
26972         Roo.DomHelper.overwrite(td, K);
26973         var  ti = new  Roo.Toolbar.Item(td.firstChild);
26974         ti.render(td);
26975         this.items.add(ti);
26976         return  ti;
26977     },
26978
26979     /**
26980      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26981      * @type Roo.util.MixedCollection  
26982      */
26983     fields : false,
26984     
26985     /**
26986      * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26987      * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26988      * @param {Roo.form.Field} field
26989      * @return {Roo.ToolbarItem}
26990      */
26991      
26992       
26993     addField : function(M) {
26994         if (!this.fields) {
26995             var  E = 0;
26996             this.fields = new  Roo.util.MixedCollection(false, function(o){
26997                 return  o.id || ("item" + (++E));
26998             });
26999
27000         }
27001         
27002         var  td = this.nextBlock();
27003         M.render(td);
27004         var  ti = new  Roo.Toolbar.Item(td.firstChild);
27005         ti.render(td);
27006         this.items.add(ti);
27007         this.fields.add(M);
27008         return  ti;
27009     },
27010     /**
27011      * Hide the toolbar
27012      * @method hide
27013      */
27014      
27015       
27016     hide : function()
27017     {
27018         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27019         this.el.child('div').hide();
27020     },
27021     /**
27022      * Show the toolbar
27023      * @method show
27024      */
27025     show : function()
27026     {
27027         this.el.child('div').show();
27028     },
27029       
27030     // private
27031     nextBlock : function(){
27032         var  td = document.createElement("td");
27033         this.tr.appendChild(td);
27034         return  td;
27035     },
27036
27037     // private
27038     destroy : function(){
27039         if(this.items){ // rendered?
27040             Roo.destroy.apply(Roo, this.items.items);
27041         }
27042         if(this.fields){ // rendered?
27043             Roo.destroy.apply(Roo, this.fields.items);
27044         }
27045
27046         Roo.Element.uncache(this.el, this.tr);
27047     }
27048 };
27049
27050 /**
27051  * @class Roo.Toolbar.Item
27052  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27053  * @constructor
27054  * Creates a new Item
27055  * @param {HTMLElement} el 
27056  */
27057 Roo.Toolbar.Item = function(el){
27058     this.el = Roo.getDom(el);
27059     this.id = Roo.id(this.el);
27060     this.hidden = false;
27061 };
27062
27063 Roo.Toolbar.Item.prototype = {
27064     
27065     /**
27066      * Get this item's HTML Element
27067      * @return {HTMLElement}
27068      */
27069     getEl : function(){
27070        return  this.el;  
27071     },
27072
27073     // private
27074     render : function(td){
27075         this.td = td;
27076         td.appendChild(this.el);
27077     },
27078     
27079     /**
27080      * Removes and destroys this item.
27081      */
27082     destroy : function(){
27083         this.td.parentNode.removeChild(this.td);
27084     },
27085     
27086     /**
27087      * Shows this item.
27088      */
27089     show: function(){
27090         this.hidden = false;
27091         this.td.style.display = "";
27092     },
27093     
27094     /**
27095      * Hides this item.
27096      */
27097     hide: function(){
27098         this.hidden = true;
27099         this.td.style.display = "none";
27100     },
27101     
27102     /**
27103      * Convenience function for boolean show/hide.
27104      * @param {Boolean} visible true to show/false to hide
27105      */
27106     setVisible: function(N){
27107         if(N) {
27108             this.show();
27109         }else {
27110             this.hide();
27111         }
27112     },
27113     
27114     /**
27115      * Try to focus this item.
27116      */
27117     focus : function(){
27118         Roo.fly(this.el).focus();
27119     },
27120     
27121     /**
27122      * Disables this item.
27123      */
27124     disable : function(){
27125         Roo.fly(this.td).addClass("x-item-disabled");
27126         this.disabled = true;
27127         this.el.disabled = true;
27128     },
27129     
27130     /**
27131      * Enables this item.
27132      */
27133     enable : function(){
27134         Roo.fly(this.td).removeClass("x-item-disabled");
27135         this.disabled = false;
27136         this.el.disabled = false;
27137     }
27138 };
27139
27140
27141 /**
27142  * @class Roo.Toolbar.Separator
27143  * @extends Roo.Toolbar.Item
27144  * A simple toolbar separator class
27145  * @constructor
27146  * Creates a new Separator
27147  */
27148 Roo.Toolbar.Separator = function(){
27149     var  s = document.createElement("span");
27150     s.className = "ytb-sep";
27151     Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27152 };
27153 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27154     enable:Roo.emptyFn,
27155     disable:Roo.emptyFn,
27156     focus:Roo.emptyFn
27157 });
27158
27159 /**
27160  * @class Roo.Toolbar.Spacer
27161  * @extends Roo.Toolbar.Item
27162  * A simple element that adds extra horizontal space to a toolbar.
27163  * @constructor
27164  * Creates a new Spacer
27165  */
27166 Roo.Toolbar.Spacer = function(){
27167     var  s = document.createElement("div");
27168     s.className = "ytb-spacer";
27169     Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27170 };
27171 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27172     enable:Roo.emptyFn,
27173     disable:Roo.emptyFn,
27174     focus:Roo.emptyFn
27175 });
27176
27177 /**
27178  * @class Roo.Toolbar.Fill
27179  * @extends Roo.Toolbar.Spacer
27180  * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27181  * @constructor
27182  * Creates a new Spacer
27183  */
27184 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27185     // private
27186     render : function(td){
27187         td.style.width = '100%';
27188         Roo.Toolbar.Fill.superclass.render.call(this, td);
27189     }
27190 });
27191
27192 /**
27193  * @class Roo.Toolbar.TextItem
27194  * @extends Roo.Toolbar.Item
27195  * A simple class that renders text directly into a toolbar.
27196  * @constructor
27197  * Creates a new TextItem
27198  * @param {String} text
27199  */
27200 Roo.Toolbar.TextItem = function(O){
27201     if (typeof(O) == 'object') {
27202         O = O.text;
27203     }
27204     var  s = document.createElement("span");
27205     s.className = "ytb-text";
27206     s.innerHTML = O;
27207     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27208 };
27209 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27210     enable:Roo.emptyFn,
27211     disable:Roo.emptyFn,
27212     focus:Roo.emptyFn
27213 });
27214
27215 /**
27216  * @class Roo.Toolbar.Button
27217  * @extends Roo.Button
27218  * A button that renders into a toolbar.
27219  * @constructor
27220  * Creates a new Button
27221  * @param {Object} config A standard {@link Roo.Button} config object
27222  */
27223 Roo.Toolbar.Button = function(P){
27224     Roo.Toolbar.Button.superclass.constructor.call(this, null, P);
27225 };
27226 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27227     render : function(td){
27228         this.td = td;
27229         Roo.Toolbar.Button.superclass.render.call(this, td);
27230     },
27231     
27232     /**
27233      * Removes and destroys this button
27234      */
27235     destroy : function(){
27236         Roo.Toolbar.Button.superclass.destroy.call(this);
27237         this.td.parentNode.removeChild(this.td);
27238     },
27239     
27240     /**
27241      * Shows this button
27242      */
27243     show: function(){
27244         this.hidden = false;
27245         this.td.style.display = "";
27246     },
27247     
27248     /**
27249      * Hides this button
27250      */
27251     hide: function(){
27252         this.hidden = true;
27253         this.td.style.display = "none";
27254     },
27255
27256     /**
27257      * Disables this item
27258      */
27259     disable : function(){
27260         Roo.fly(this.td).addClass("x-item-disabled");
27261         this.disabled = true;
27262     },
27263
27264     /**
27265      * Enables this item
27266      */
27267     enable : function(){
27268         Roo.fly(this.td).removeClass("x-item-disabled");
27269         this.disabled = false;
27270     }
27271 });
27272 // backwards compat
27273 Roo.ToolbarButton = Roo.Toolbar.Button;
27274
27275 /**
27276  * @class Roo.Toolbar.SplitButton
27277  * @extends Roo.SplitButton
27278  * A menu button that renders into a toolbar.
27279  * @constructor
27280  * Creates a new SplitButton
27281  * @param {Object} config A standard {@link Roo.SplitButton} config object
27282  */
27283 Roo.Toolbar.SplitButton = function(Q){
27284     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, Q);
27285 };
27286 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27287     render : function(td){
27288         this.td = td;
27289         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27290     },
27291     
27292     /**
27293      * Removes and destroys this button
27294      */
27295     destroy : function(){
27296         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27297         this.td.parentNode.removeChild(this.td);
27298     },
27299     
27300     /**
27301      * Shows this button
27302      */
27303     show: function(){
27304         this.hidden = false;
27305         this.td.style.display = "";
27306     },
27307     
27308     /**
27309      * Hides this button
27310      */
27311     hide: function(){
27312         this.hidden = true;
27313         this.td.style.display = "none";
27314     }
27315 });
27316
27317 // backwards compat
27318 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;
27319 /*
27320  * Based on:
27321  * Ext JS Library 1.1.1
27322  * Copyright(c) 2006-2007, Ext JS, LLC.
27323  *
27324  * Originally Released Under LGPL - original licence link has changed is not relivant.
27325  *
27326  * Fork - LGPL
27327  * <script type="text/javascript">
27328  */
27329  
27330 /**
27331  * @class Roo.PagingToolbar
27332  * @extends Roo.Toolbar
27333  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27334  * @constructor
27335  * Create a new PagingToolbar
27336  * @param {Object} config The config object
27337  */
27338 Roo.PagingToolbar = function(el, ds, A)
27339 {
27340     // old args format still supported... - xtype is prefered..
27341     if (typeof(el) == 'object' && el.xtype) {
27342         // created from xtype...
27343         A = el;
27344         ds = el.dataSource;
27345         el = A.container;
27346     }
27347
27348     
27349     
27350     Roo.PagingToolbar.superclass.constructor.call(this, el, null, A);
27351     this.ds = ds;
27352     this.cursor = 0;
27353     this.renderButtons(this.el);
27354     this.bind(ds);
27355 };
27356
27357 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27358     /**
27359      * @cfg {Roo.data.Store} dataSource
27360      * The underlying data store providing the paged data
27361      */
27362     /**
27363      * @cfg {String/HTMLElement/Element} container
27364      * container The id or element that will contain the toolbar
27365      */
27366     /**
27367      * @cfg {Boolean} displayInfo
27368      * True to display the displayMsg (defaults to false)
27369      */
27370     /**
27371      * @cfg {Number} pageSize
27372      * The number of records to display per page (defaults to 20)
27373      */
27374     pageSize: 20,
27375     /**
27376      * @cfg {String} displayMsg
27377      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27378      */
27379     displayMsg : 'Displaying {0} - {1} of {2}',
27380     /**
27381      * @cfg {String} emptyMsg
27382      * The message to display when no records are found (defaults to "No data to display")
27383      */
27384     emptyMsg : 'No data to display',
27385     /**
27386      * Customizable piece of the default paging text (defaults to "Page")
27387      * @type String
27388      */
27389     beforePageText : "Page",
27390     /**
27391      * Customizable piece of the default paging text (defaults to "of %0")
27392      * @type String
27393      */
27394     afterPageText : "of {0}",
27395     /**
27396      * Customizable piece of the default paging text (defaults to "First Page")
27397      * @type String
27398      */
27399     firstText : "First Page",
27400     /**
27401      * Customizable piece of the default paging text (defaults to "Previous Page")
27402      * @type String
27403      */
27404     prevText : "Previous Page",
27405     /**
27406      * Customizable piece of the default paging text (defaults to "Next Page")
27407      * @type String
27408      */
27409     nextText : "Next Page",
27410     /**
27411      * Customizable piece of the default paging text (defaults to "Last Page")
27412      * @type String
27413      */
27414     lastText : "Last Page",
27415     /**
27416      * Customizable piece of the default paging text (defaults to "Refresh")
27417      * @type String
27418      */
27419     refreshText : "Refresh",
27420
27421     // private
27422     renderButtons : function(el){
27423         Roo.PagingToolbar.superclass.render.call(this, el);
27424         this.first = this.addButton({
27425             tooltip: this.firstText,
27426             cls: "x-btn-icon x-grid-page-first",
27427             disabled: true,
27428             handler: this.onClick.createDelegate(this, ["first"])
27429         });
27430         this.prev = this.addButton({
27431             tooltip: this.prevText,
27432             cls: "x-btn-icon x-grid-page-prev",
27433             disabled: true,
27434             handler: this.onClick.createDelegate(this, ["prev"])
27435         });
27436         this.addSeparator();
27437         this.add(this.beforePageText);
27438         this.field = Roo.get(this.addDom({
27439            tag: "input",
27440            type: "text",
27441            size: "3",
27442            value: "1",
27443            cls: "x-grid-page-number"
27444         }).el);
27445         this.field.on("keydown", this.onPagingKeydown, this);
27446         this.field.on("focus", function(){this.dom.select();});
27447         this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27448         this.field.setHeight(18);
27449         this.addSeparator();
27450         this.next = this.addButton({
27451             tooltip: this.nextText,
27452             cls: "x-btn-icon x-grid-page-next",
27453             disabled: true,
27454             handler: this.onClick.createDelegate(this, ["next"])
27455         });
27456         this.last = this.addButton({
27457             tooltip: this.lastText,
27458             cls: "x-btn-icon x-grid-page-last",
27459             disabled: true,
27460             handler: this.onClick.createDelegate(this, ["last"])
27461         });
27462         this.addSeparator();
27463         this.loading = this.addButton({
27464             tooltip: this.refreshText,
27465             cls: "x-btn-icon x-grid-loading",
27466             handler: this.onClick.createDelegate(this, ["refresh"])
27467         });
27468
27469         if(this.displayInfo){
27470             this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27471         }
27472     },
27473
27474     // private
27475     updateInfo : function(){
27476         if(this.displayEl){
27477             var  count = this.ds.getCount();
27478             var  msg = count == 0 ?
27479                 this.emptyMsg :
27480                 String.format(
27481                     this.displayMsg,
27482                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
27483                 );
27484             this.displayEl.update(msg);
27485         }
27486     },
27487
27488     // private
27489     onLoad : function(ds, r, o){
27490        this.cursor = o.params ? o.params.start : 0;
27491        var  d = this.getPageData(), ap = d.activePage, ps = d.pages;
27492
27493        this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27494        this.field.dom.value = ap;
27495        this.first.setDisabled(ap == 1);
27496        this.prev.setDisabled(ap == 1);
27497        this.next.setDisabled(ap == ps);
27498        this.last.setDisabled(ap == ps);
27499        this.loading.enable();
27500        this.updateInfo();
27501     },
27502
27503     // private
27504     getPageData : function(){
27505         var  B = this.ds.getTotalCount();
27506         return  {
27507             total : B,
27508             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27509             pages :  B < this.pageSize ? 1 : Math.ceil(B/this.pageSize)
27510         };
27511     },
27512
27513     // private
27514     onLoadError : function(){
27515         this.loading.enable();
27516     },
27517
27518     // private
27519     onPagingKeydown : function(e){
27520         var  k = e.getKey();
27521         var  d = this.getPageData();
27522         if(k == e.RETURN ){
27523             var  v = this.field.dom.value, pageNum;
27524             if(!v || isNaN(pageNum = parseInt(v, 10))){
27525                 this.field.dom.value = d.activePage;
27526                 return;
27527             }
27528
27529             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27530             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27531             e.stopEvent();
27532         }
27533         else  if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
27534         {
27535           var  pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27536           this.field.dom.value = pageNum;
27537           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27538           e.stopEvent();
27539         }
27540         else  if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27541         {
27542           var  v = this.field.dom.value, pageNum; 
27543           var  increment = (e.shiftKey) ? 10 : 1;
27544           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27545             increment *= -1;
27546           if(!v || isNaN(pageNum = parseInt(v, 10))) {
27547             this.field.dom.value = d.activePage;
27548             return;
27549           }
27550           else  if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27551           {
27552             this.field.dom.value = parseInt(v, 10) + increment;
27553             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27554             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27555           }
27556
27557           e.stopEvent();
27558         }
27559     },
27560
27561     // private
27562     beforeLoad : function(){
27563         if(this.loading){
27564             this.loading.disable();
27565         }
27566     },
27567
27568     // private
27569     onClick : function(C){
27570         var  ds = this.ds;
27571         switch(C){
27572             case  "first":
27573                 ds.load({params:{start: 0, limit: this.pageSize}});
27574             break;
27575             case  "prev":
27576                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27577             break;
27578             case  "next":
27579                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27580             break;
27581             case  "last":
27582                 var  B = ds.getTotalCount();
27583                 var  extra = B % this.pageSize;
27584                 var  lastStart = extra ? (B - extra) : B-this.pageSize;
27585                 ds.load({params:{start: lastStart, limit: this.pageSize}});
27586             break;
27587             case  "refresh":
27588                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27589             break;
27590         }
27591     },
27592
27593     /**
27594      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27595      * @param {Roo.data.Store} store The data store to unbind
27596      */
27597     unbind : function(ds){
27598         ds.un("beforeload", this.beforeLoad, this);
27599         ds.un("load", this.onLoad, this);
27600         ds.un("loadexception", this.onLoadError, this);
27601         ds.un("remove", this.updateInfo, this);
27602         ds.un("add", this.updateInfo, this);
27603         this.ds = undefined;
27604     },
27605
27606     /**
27607      * Binds the paging toolbar to the specified {@link Roo.data.Store}
27608      * @param {Roo.data.Store} store The data store to bind
27609      */
27610     bind : function(ds){
27611         ds.on("beforeload", this.beforeLoad, this);
27612         ds.on("load", this.onLoad, this);
27613         ds.on("loadexception", this.onLoadError, this);
27614         ds.on("remove", this.updateInfo, this);
27615         ds.on("add", this.updateInfo, this);
27616         this.ds = ds;
27617     }
27618 });
27619 /*
27620  * Based on:
27621  * Ext JS Library 1.1.1
27622  * Copyright(c) 2006-2007, Ext JS, LLC.
27623  *
27624  * Originally Released Under LGPL - original licence link has changed is not relivant.
27625  *
27626  * Fork - LGPL
27627  * <script type="text/javascript">
27628  */
27629
27630 /**
27631  * @class Roo.Resizable
27632  * @extends Roo.util.Observable
27633  * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27634  * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27635  * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
27636  * the element will be wrapped for you automatically.</p>
27637  * <p>Here is the list of valid resize handles:</p>
27638  * <pre>
27639 Value   Description
27640 ------  -------------------
27641  'n'     north
27642  's'     south
27643  'e'     east
27644  'w'     west
27645  'nw'    northwest
27646  'sw'    southwest
27647  'se'    southeast
27648  'ne'    northeast
27649  'all'   all
27650 </pre>
27651  * <p>Here's an example showing the creation of a typical Resizable:</p>
27652  * <pre><code>
27653 var resizer = new Roo.Resizable("element-id", {
27654     handles: 'all',
27655     minWidth: 200,
27656     minHeight: 100,
27657     maxWidth: 500,
27658     maxHeight: 400,
27659     pinned: true
27660 });
27661 resizer.on("resize", myHandler);
27662 </code></pre>
27663  * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27664  * resizer.east.setDisplayed(false);</p>
27665  * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27666  * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27667  * resize operation's new size (defaults to [0, 0])
27668  * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27669  * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27670  * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27671  * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27672  * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27673  * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27674  * @cfg {Number} width The width of the element in pixels (defaults to null)
27675  * @cfg {Number} height The height of the element in pixels (defaults to null)
27676  * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27677  * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27678  * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27679  * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27680  * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  The old style of adding multi-direction resize handles, deprecated
27681  * in favor of the handles config option (defaults to false)
27682  * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27683  * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27684  * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27685  * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27686  * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27687  * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27688  * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27689  * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27690  * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27691  * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27692  * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27693  * @constructor
27694  * Create a new resizable component
27695  * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27696  * @param {Object} config configuration options
27697   */
27698 Roo.Resizable = function(el, A){
27699     this.el = Roo.get(el);
27700
27701     if(A && A.wrap){
27702         A.resizeChild = this.el;
27703         this.el = this.el.wrap(typeof  A.wrap == "object" ? A.wrap : {cls:"xresizable-wrap"});
27704         this.el.id = this.el.dom.id = A.resizeChild.id + "-rzwrap";
27705         this.el.setStyle("overflow", "hidden");
27706         this.el.setPositioning(A.resizeChild.getPositioning());
27707         A.resizeChild.clearPositioning();
27708         if(!A.width || !A.height){
27709             var  csize = A.resizeChild.getSize();
27710             this.el.setSize(csize.width, csize.height);
27711         }
27712         if(A.pinned && !A.adjustments){
27713             A.adjustments = "auto";
27714         }
27715     }
27716
27717
27718     this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27719     this.proxy.unselectable();
27720     this.proxy.enableDisplayMode('block');
27721
27722     Roo.apply(this, A);
27723
27724     if(this.pinned){
27725         this.disableTrackOver = true;
27726         this.el.addClass("x-resizable-pinned");
27727     }
27728     // if the element isn't positioned, make it relative
27729     var  B = this.el.getStyle("position");
27730     if(B != "absolute" && B != "fixed"){
27731         this.el.setStyle("position", "relative");
27732     }
27733     if(!this.handles){ // no handles passed, must be legacy style
27734         this.handles = 's,e,se';
27735         if(this.multiDirectional){
27736             this.handles += ',n,w';
27737         }
27738     }
27739     if(this.handles == "all"){
27740         this.handles = "n s e w ne nw se sw";
27741     }
27742     var  hs = this.handles.split(/\s*?[,;]\s*?| /);
27743     var  ps = Roo.Resizable.positions;
27744     for(var  i = 0, len = hs.length; i < len; i++){
27745         if(hs[i] && ps[hs[i]]){
27746             var  pos = ps[hs[i]];
27747             this[pos] = new  Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27748         }
27749     }
27750
27751     // legacy
27752     this.corner = this.southeast;
27753
27754     if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27755         this.updateBox = true;
27756     }
27757
27758
27759     this.activeHandle = null;
27760
27761     if(this.resizeChild){
27762         if(typeof  this.resizeChild == "boolean"){
27763             this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27764         }else {
27765             this.resizeChild = Roo.get(this.resizeChild, true);
27766         }
27767     }
27768
27769     if(this.adjustments == "auto"){
27770         var  rc = this.resizeChild;
27771         var  hw = this.west, he = this.east, hn = this.north, hs = this.south;
27772         if(rc && (hw || hn)){
27773             rc.position("relative");
27774             rc.setLeft(hw ? hw.el.getWidth() : 0);
27775             rc.setTop(hn ? hn.el.getHeight() : 0);
27776         }
27777
27778         this.adjustments = [
27779             (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27780             (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27781         ];
27782     }
27783
27784     if(this.draggable){
27785         this.dd = this.dynamic ?
27786             this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27787         this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27788     }
27789
27790
27791     // public events
27792     this.addEvents({
27793         /**
27794          * @event beforeresize
27795          * Fired before resize is allowed. Set enabled to false to cancel resize.
27796          * @param {Roo.Resizable} this
27797          * @param {Roo.EventObject} e The mousedown event
27798          */
27799         "beforeresize" : true,
27800         /**
27801          * @event resize
27802          * Fired after a resize.
27803          * @param {Roo.Resizable} this
27804          * @param {Number} width The new width
27805          * @param {Number} height The new height
27806          * @param {Roo.EventObject} e The mouseup event
27807          */
27808         "resize" : true
27809     });
27810
27811     if(this.width !== null && this.height !== null){
27812         this.resizeTo(this.width, this.height);
27813     }else {
27814         this.updateChildSize();
27815     }
27816     if(Roo.isIE){
27817         this.el.dom.style.zoom = 1;
27818     }
27819
27820     Roo.Resizable.superclass.constructor.call(this);
27821 };
27822
27823 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27824         resizeChild : false,
27825         adjustments : [0, 0],
27826         minWidth : 5,
27827         minHeight : 5,
27828         maxWidth : 10000,
27829         maxHeight : 10000,
27830         enabled : true,
27831         animate : false,
27832         duration : .35,
27833         dynamic : false,
27834         handles : false,
27835         multiDirectional : false,
27836         disableTrackOver : false,
27837         easing : 'easeOutStrong',
27838         widthIncrement : 0,
27839         heightIncrement : 0,
27840         pinned : false,
27841         width : null,
27842         height : null,
27843         preserveRatio : false,
27844         transparent: false,
27845         minX: 0,
27846         minY: 0,
27847         draggable: false,
27848
27849         /**
27850          * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27851          */
27852         constrainTo: undefined,
27853         /**
27854          * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27855          */
27856         resizeRegion: undefined,
27857
27858
27859     /**
27860      * Perform a manual resize
27861      * @param {Number} width
27862      * @param {Number} height
27863      */
27864     resizeTo : function(C, D){
27865         this.el.setSize(C, D);
27866         this.updateChildSize();
27867         this.fireEvent("resize", this, C, D, null);
27868     },
27869
27870     // private
27871     startSizing : function(e, E){
27872         this.fireEvent("beforeresize", this, e);
27873         if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27874
27875             if(!this.overlay){
27876                 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: "&#160;"});
27877                 this.overlay.unselectable();
27878                 this.overlay.enableDisplayMode("block");
27879                 this.overlay.on("mousemove", this.onMouseMove, this);
27880                 this.overlay.on("mouseup", this.onMouseUp, this);
27881             }
27882
27883             this.overlay.setStyle("cursor", E.el.getStyle("cursor"));
27884
27885             this.resizing = true;
27886             this.startBox = this.el.getBox();
27887             this.startPoint = e.getXY();
27888             this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27889                             (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27890
27891             this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27892             this.overlay.show();
27893
27894             if(this.constrainTo) {
27895                 var  ct = Roo.get(this.constrainTo);
27896                 this.resizeRegion = ct.getRegion().adjust(
27897                     ct.getFrameWidth('t'),
27898                     ct.getFrameWidth('l'),
27899                     -ct.getFrameWidth('b'),
27900                     -ct.getFrameWidth('r')
27901                 );
27902             }
27903
27904
27905             this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27906             this.proxy.show();
27907             this.proxy.setBox(this.startBox);
27908             if(!this.dynamic){
27909                 this.proxy.setStyle('visibility', 'visible');
27910             }
27911         }
27912     },
27913
27914     // private
27915     onMouseDown : function(F, e){
27916         if(this.enabled){
27917             e.stopEvent();
27918             this.activeHandle = F;
27919             this.startSizing(e, F);
27920         }
27921     },
27922
27923     // private
27924     onMouseUp : function(e){
27925         var  G = this.resizeElement();
27926         this.resizing = false;
27927         this.handleOut();
27928         this.overlay.hide();
27929         this.proxy.hide();
27930         this.fireEvent("resize", this, G.width, G.height, e);
27931     },
27932
27933     // private
27934     updateChildSize : function(){
27935         if(this.resizeChild){
27936             var  el = this.el;
27937             var  child = this.resizeChild;
27938             var  adj = this.adjustments;
27939             if(el.dom.offsetWidth){
27940                 var  b = el.getSize(true);
27941                 child.setSize(b.width+adj[0], b.height+adj[1]);
27942             }
27943             // Second call here for IE
27944             // The first call enables instant resizing and
27945             // the second call corrects scroll bars if they
27946             // exist
27947             if(Roo.isIE){
27948                 setTimeout(function(){
27949                     if(el.dom.offsetWidth){
27950                         var  b = el.getSize(true);
27951                         child.setSize(b.width+adj[0], b.height+adj[1]);
27952                     }
27953                 }, 10);
27954             }
27955         }
27956     },
27957
27958     // private
27959     snap : function(H, I, J){
27960         if(!I || !H) return  H;
27961         var  K = H;
27962         var  m = H % I;
27963         if(m > 0){
27964             if(m > (I/2)){
27965                 K = H + (I-m);
27966             }else {
27967                 K = H - m;
27968             }
27969         }
27970         return  Math.max(J, K);
27971     },
27972
27973     // private
27974     resizeElement : function(){
27975         var  L = this.proxy.getBox();
27976         if(this.updateBox){
27977             this.el.setBox(L, false, this.animate, this.duration, null, this.easing);
27978         }else {
27979             this.el.setSize(L.width, L.height, this.animate, this.duration, null, this.easing);
27980         }
27981
27982         this.updateChildSize();
27983         if(!this.dynamic){
27984             this.proxy.hide();
27985         }
27986         return  L;
27987     },
27988
27989     // private
27990     constrain : function(v, M, m, mx){
27991         if(v - M < m){
27992             M = v - m;
27993         }else  if(v - M > mx){
27994             M = mx - v;
27995         }
27996         return  M;
27997     },
27998
27999     // private
28000     onMouseMove : function(e){
28001         if(this.enabled){
28002             try{// try catch so if something goes wrong the user doesn't get hung
28003
28004             if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28005                 return;
28006             }
28007
28008             //var curXY = this.startPoint;
28009             var  curSize = this.curSize || this.startBox;
28010             var  x = this.startBox.x, y = this.startBox.y;
28011             var  ox = x, oy = y;
28012             var  w = curSize.width, h = curSize.height;
28013             var  ow = w, oh = h;
28014             var  mw = this.minWidth, mh = this.minHeight;
28015             var  mxw = this.maxWidth, mxh = this.maxHeight;
28016             var  wi = this.widthIncrement;
28017             var  hi = this.heightIncrement;
28018
28019             var  eventXY = e.getXY();
28020             var  diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28021             var  diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28022
28023             var  pos = this.activeHandle.position;
28024
28025             switch(pos){
28026                 case  "east":
28027                     w += diffX;
28028                     w = Math.min(Math.max(mw, w), mxw);
28029                     break;
28030                 case  "south":
28031                     h += diffY;
28032                     h = Math.min(Math.max(mh, h), mxh);
28033                     break;
28034                 case  "southeast":
28035                     w += diffX;
28036                     h += diffY;
28037                     w = Math.min(Math.max(mw, w), mxw);
28038                     h = Math.min(Math.max(mh, h), mxh);
28039                     break;
28040                 case  "north":
28041                     diffY = this.constrain(h, diffY, mh, mxh);
28042                     y += diffY;
28043                     h -= diffY;
28044                     break;
28045                 case  "west":
28046                     diffX = this.constrain(w, diffX, mw, mxw);
28047                     x += diffX;
28048                     w -= diffX;
28049                     break;
28050                 case  "northeast":
28051                     w += diffX;
28052                     w = Math.min(Math.max(mw, w), mxw);
28053                     diffY = this.constrain(h, diffY, mh, mxh);
28054                     y += diffY;
28055                     h -= diffY;
28056                     break;
28057                 case  "northwest":
28058                     diffX = this.constrain(w, diffX, mw, mxw);
28059                     diffY = this.constrain(h, diffY, mh, mxh);
28060                     y += diffY;
28061                     h -= diffY;
28062                     x += diffX;
28063                     w -= diffX;
28064                     break;
28065                case  "southwest":
28066                     diffX = this.constrain(w, diffX, mw, mxw);
28067                     h += diffY;
28068                     h = Math.min(Math.max(mh, h), mxh);
28069                     x += diffX;
28070                     w -= diffX;
28071                     break;
28072             }
28073
28074             var  sw = this.snap(w, wi, mw);
28075             var  sh = this.snap(h, hi, mh);
28076             if(sw != w || sh != h){
28077                 switch(pos){
28078                     case  "northeast":
28079                         y -= sh - h;
28080                     break;
28081                     case  "north":
28082                         y -= sh - h;
28083                         break;
28084                     case  "southwest":
28085                         x -= sw - w;
28086                     break;
28087                     case  "west":
28088                         x -= sw - w;
28089                         break;
28090                     case  "northwest":
28091                         x -= sw - w;
28092                         y -= sh - h;
28093                     break;
28094                 }
28095
28096                 w = sw;
28097                 h = sh;
28098             }
28099
28100             if(this.preserveRatio){
28101                 switch(pos){
28102                     case  "southeast":
28103                     case  "east":
28104                         h = oh * (w/ow);
28105                         h = Math.min(Math.max(mh, h), mxh);
28106                         w = ow * (h/oh);
28107                        break;
28108                     case  "south":
28109                         w = ow * (h/oh);
28110                         w = Math.min(Math.max(mw, w), mxw);
28111                         h = oh * (w/ow);
28112                         break;
28113                     case  "northeast":
28114                         w = ow * (h/oh);
28115                         w = Math.min(Math.max(mw, w), mxw);
28116                         h = oh * (w/ow);
28117                     break;
28118                     case  "north":
28119                         var  tw = w;
28120                         w = ow * (h/oh);
28121                         w = Math.min(Math.max(mw, w), mxw);
28122                         h = oh * (w/ow);
28123                         x += (tw - w) / 2;
28124                         break;
28125                     case  "southwest":
28126                         h = oh * (w/ow);
28127                         h = Math.min(Math.max(mh, h), mxh);
28128                         var  tw = w;
28129                         w = ow * (h/oh);
28130                         x += tw - w;
28131                         break;
28132                     case  "west":
28133                         var  th = h;
28134                         h = oh * (w/ow);
28135                         h = Math.min(Math.max(mh, h), mxh);
28136                         y += (th - h) / 2;
28137                         var  tw = w;
28138                         w = ow * (h/oh);
28139                         x += tw - w;
28140                        break;
28141                     case  "northwest":
28142                         var  tw = w;
28143                         var  th = h;
28144                         h = oh * (w/ow);
28145                         h = Math.min(Math.max(mh, h), mxh);
28146                         w = ow * (h/oh);
28147                         y += th - h;
28148                          x += tw - w;
28149                        break;
28150
28151                 }
28152             }
28153
28154             this.proxy.setBounds(x, y, w, h);
28155             if(this.dynamic){
28156                 this.resizeElement();
28157             }
28158             }catch(e){}
28159         }
28160     },
28161
28162     // private
28163     handleOver : function(){
28164         if(this.enabled){
28165             this.el.addClass("x-resizable-over");
28166         }
28167     },
28168
28169     // private
28170     handleOut : function(){
28171         if(!this.resizing){
28172             this.el.removeClass("x-resizable-over");
28173         }
28174     },
28175
28176     /**
28177      * Returns the element this component is bound to.
28178      * @return {Roo.Element}
28179      */
28180     getEl : function(){
28181         return  this.el;
28182     },
28183
28184     /**
28185      * Returns the resizeChild element (or null).
28186      * @return {Roo.Element}
28187      */
28188     getResizeChild : function(){
28189         return  this.resizeChild;
28190     },
28191
28192     /**
28193      * Destroys this resizable. If the element was wrapped and
28194      * removeEl is not true then the element remains.
28195      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28196      */
28197     destroy : function(N){
28198         this.proxy.remove();
28199         if(this.overlay){
28200             this.overlay.removeAllListeners();
28201             this.overlay.remove();
28202         }
28203         var  ps = Roo.Resizable.positions;
28204         for(var  k  in  ps){
28205             if(typeof  ps[k] != "function" && this[ps[k]]){
28206                 var  h = this[ps[k]];
28207                 h.el.removeAllListeners();
28208                 h.el.remove();
28209             }
28210         }
28211         if(N){
28212             this.el.update("");
28213             this.el.remove();
28214         }
28215     }
28216 });
28217
28218 // private
28219 // hash to map config positions to true positions
28220 Roo.Resizable.positions = {
28221     n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
28222 };
28223
28224 // private
28225 Roo.Resizable.Handle = function(rz, O, P, Q){
28226     if(!this.tpl){
28227         // only initialize the template if resizable is used
28228         var  tpl = Roo.DomHelper.createTemplate(
28229             {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28230         );
28231         tpl.compile();
28232         Roo.Resizable.Handle.prototype.tpl = tpl;
28233     }
28234
28235     this.position = O;
28236     this.rz = rz;
28237     this.el = this.tpl.append(rz.el.dom, [this.position], true);
28238     this.el.unselectable();
28239     if(Q){
28240         this.el.setOpacity(0);
28241     }
28242
28243     this.el.on("mousedown", this.onMouseDown, this);
28244     if(!P){
28245         this.el.on("mouseover", this.onMouseOver, this);
28246         this.el.on("mouseout", this.onMouseOut, this);
28247     }
28248 };
28249
28250 // private
28251 Roo.Resizable.Handle.prototype = {
28252     afterResize : function(rz){
28253         // do nothing
28254     },
28255     // private
28256     onMouseDown : function(e){
28257         this.rz.onMouseDown(this, e);
28258     },
28259     // private
28260     onMouseOver : function(e){
28261         this.rz.handleOver(this, e);
28262     },
28263     // private
28264     onMouseOut : function(e){
28265         this.rz.handleOut(this, e);
28266     }
28267 };
28268 /*
28269  * Based on:
28270  * Ext JS Library 1.1.1
28271  * Copyright(c) 2006-2007, Ext JS, LLC.
28272  *
28273  * Originally Released Under LGPL - original licence link has changed is not relivant.
28274  *
28275  * Fork - LGPL
28276  * <script type="text/javascript">
28277  */
28278
28279 /**
28280  * @class Roo.Editor
28281  * @extends Roo.Component
28282  * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28283  * @constructor
28284  * Create a new Editor
28285  * @param {Roo.form.Field} field The Field object (or descendant)
28286  * @param {Object} config The config object
28287  */
28288 Roo.Editor = function(A, B){
28289     Roo.Editor.superclass.constructor.call(this, B);
28290     this.field = A;
28291     this.addEvents({
28292         /**
28293              * @event beforestartedit
28294              * Fires when editing is initiated, but before the value changes.  Editing can be canceled by returning
28295              * false from the handler of this event.
28296              * @param {Editor} this
28297              * @param {Roo.Element} boundEl The underlying element bound to this editor
28298              * @param {Mixed} value The field value being set
28299              */
28300         "beforestartedit" : true,
28301         /**
28302              * @event startedit
28303              * Fires when this editor is displayed
28304              * @param {Roo.Element} boundEl The underlying element bound to this editor
28305              * @param {Mixed} value The starting field value
28306              */
28307         "startedit" : true,
28308         /**
28309              * @event beforecomplete
28310              * Fires after a change has been made to the field, but before the change is reflected in the underlying
28311              * field.  Saving the change to the field can be canceled by returning false from the handler of this event.
28312              * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28313              * event will not fire since no edit actually occurred.
28314              * @param {Editor} this
28315              * @param {Mixed} value The current field value
28316              * @param {Mixed} startValue The original field value
28317              */
28318         "beforecomplete" : true,
28319         /**
28320              * @event complete
28321              * Fires after editing is complete and any changed value has been written to the underlying field.
28322              * @param {Editor} this
28323              * @param {Mixed} value The current field value
28324              * @param {Mixed} startValue The original field value
28325              */
28326         "complete" : true,
28327         /**
28328          * @event specialkey
28329          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
28330          * {@link Roo.EventObject#getKey} to determine which key was pressed.
28331          * @param {Roo.form.Field} this
28332          * @param {Roo.EventObject} e The event object
28333          */
28334         "specialkey" : true
28335     });
28336 };
28337
28338 Roo.extend(Roo.Editor, Roo.Component, {
28339     /**
28340      * @cfg {Boolean/String} autosize
28341      * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28342      * or "height" to adopt the height only (defaults to false)
28343      */
28344     /**
28345      * @cfg {Boolean} revertInvalid
28346      * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28347      * validation fails (defaults to true)
28348      */
28349     /**
28350      * @cfg {Boolean} ignoreNoChange
28351      * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28352      * the value has not changed (defaults to false).  Applies only to string values - edits for other data types
28353      * will never be ignored.
28354      */
28355     /**
28356      * @cfg {Boolean} hideEl
28357      * False to keep the bound element visible while the editor is displayed (defaults to true)
28358      */
28359     /**
28360      * @cfg {Mixed} value
28361      * The data value of the underlying field (defaults to "")
28362      */
28363     value : "",
28364     /**
28365      * @cfg {String} alignment
28366      * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28367      */
28368     alignment: "c-c?",
28369     /**
28370      * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28371      * for bottom-right shadow (defaults to "frame")
28372      */
28373     shadow : "frame",
28374     /**
28375      * @cfg {Boolean} constrain True to constrain the editor to the viewport
28376      */
28377     constrain : false,
28378     /**
28379      * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28380      */
28381     completeOnEnter : false,
28382     /**
28383      * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28384      */
28385     cancelOnEsc : false,
28386     /**
28387      * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28388      */
28389     updateEl : false,
28390
28391     // private
28392     onRender : function(ct, C){
28393         this.el = new  Roo.Layer({
28394             shadow: this.shadow,
28395             cls: "x-editor",
28396             parentEl : ct,
28397             shim : this.shim,
28398             shadowOffset:4,
28399             id: this.id,
28400             constrain: this.constrain
28401         });
28402         this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28403         if(this.field.msgTarget != 'title'){
28404             this.field.msgTarget = 'qtip';
28405         }
28406
28407         this.field.render(this.el);
28408         if(Roo.isGecko){
28409             this.field.el.dom.setAttribute('autocomplete', 'off');
28410         }
28411
28412         this.field.on("specialkey", this.onSpecialKey, this);
28413         if(this.swallowKeys){
28414             this.field.el.swallowEvent(['keydown','keypress']);
28415         }
28416
28417         this.field.show();
28418         this.field.on("blur", this.onBlur, this);
28419         if(this.field.grow){
28420             this.field.on("autosize", this.el.sync,  this.el, {delay:1});
28421         }
28422     },
28423
28424     onSpecialKey : function(D, e){
28425         if(this.completeOnEnter && e.getKey() == e.ENTER){
28426             e.stopEvent();
28427             this.completeEdit();
28428         }else  if(this.cancelOnEsc && e.getKey() == e.ESC){
28429             this.cancelEdit();
28430         }else {
28431             this.fireEvent('specialkey', D, e);
28432         }
28433     },
28434
28435     /**
28436      * Starts the editing process and shows the editor.
28437      * @param {String/HTMLElement/Element} el The element to edit
28438      * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28439       * to the innerHTML of el.
28440      */
28441     startEdit : function(el, E){
28442         if(this.editing){
28443             this.completeEdit();
28444         }
28445
28446         this.boundEl = Roo.get(el);
28447         var  v = E !== undefined ? E : this.boundEl.dom.innerHTML;
28448         if(!this.rendered){
28449             this.render(this.parentEl || document.body);
28450         }
28451         if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28452             return;
28453         }
28454
28455         this.startValue = v;
28456         this.field.setValue(v);
28457         if(this.autoSize){
28458             var  sz = this.boundEl.getSize();
28459             switch(this.autoSize){
28460                 case  "width":
28461                 this.setSize(sz.width,  "");
28462                 break;
28463                 case  "height":
28464                 this.setSize("",  sz.height);
28465                 break;
28466                 default:
28467                 this.setSize(sz.width,  sz.height);
28468             }
28469         }
28470
28471         this.el.alignTo(this.boundEl, this.alignment);
28472         this.editing = true;
28473         if(Roo.QuickTips){
28474             Roo.QuickTips.disable();
28475         }
28476
28477         this.show();
28478     },
28479
28480     /**
28481      * Sets the height and width of this editor.
28482      * @param {Number} width The new width
28483      * @param {Number} height The new height
28484      */
28485     setSize : function(w, h){
28486         this.field.setSize(w, h);
28487         if(this.el){
28488             this.el.sync();
28489         }
28490     },
28491
28492     /**
28493      * Realigns the editor to the bound field based on the current alignment config value.
28494      */
28495     realign : function(){
28496         this.el.alignTo(this.boundEl, this.alignment);
28497     },
28498
28499     /**
28500      * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28501      * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28502      */
28503     completeEdit : function(F){
28504         if(!this.editing){
28505             return;
28506         }
28507         var  v = this.getValue();
28508         if(this.revertInvalid !== false && !this.field.isValid()){
28509             v = this.startValue;
28510             this.cancelEdit(true);
28511         }
28512         if(String(v) === String(this.startValue) && this.ignoreNoChange){
28513             this.editing = false;
28514             this.hide();
28515             return;
28516         }
28517         if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28518             this.editing = false;
28519             if(this.updateEl && this.boundEl){
28520                 this.boundEl.update(v);
28521             }
28522             if(F !== true){
28523                 this.hide();
28524             }
28525
28526             this.fireEvent("complete", this, v, this.startValue);
28527         }
28528     },
28529
28530     // private
28531     onShow : function(){
28532         this.el.show();
28533         if(this.hideEl !== false){
28534             this.boundEl.hide();
28535         }
28536
28537         this.field.show();
28538         if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28539             this.fixIEFocus = true;
28540             this.deferredFocus.defer(50, this);
28541         }else {
28542             this.field.focus();
28543         }
28544
28545         this.fireEvent("startedit", this.boundEl, this.startValue);
28546     },
28547
28548     deferredFocus : function(){
28549         if(this.editing){
28550             this.field.focus();
28551         }
28552     },
28553
28554     /**
28555      * Cancels the editing process and hides the editor without persisting any changes.  The field value will be
28556      * reverted to the original starting value.
28557      * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28558      * cancel (defaults to false)
28559      */
28560     cancelEdit : function(G){
28561         if(this.editing){
28562             this.setValue(this.startValue);
28563             if(G !== true){
28564                 this.hide();
28565             }
28566         }
28567     },
28568
28569     // private
28570     onBlur : function(){
28571         if(this.allowBlur !== true && this.editing){
28572             this.completeEdit();
28573         }
28574     },
28575
28576     // private
28577     onHide : function(){
28578         if(this.editing){
28579             this.completeEdit();
28580             return;
28581         }
28582
28583         this.field.blur();
28584         if(this.field.collapse){
28585             this.field.collapse();
28586         }
28587
28588         this.el.hide();
28589         if(this.hideEl !== false){
28590             this.boundEl.show();
28591         }
28592         if(Roo.QuickTips){
28593             Roo.QuickTips.enable();
28594         }
28595     },
28596
28597     /**
28598      * Sets the data value of the editor
28599      * @param {Mixed} value Any valid value supported by the underlying field
28600      */
28601     setValue : function(v){
28602         this.field.setValue(v);
28603     },
28604
28605     /**
28606      * Gets the data value of the editor
28607      * @return {Mixed} The data value
28608      */
28609     getValue : function(){
28610         return  this.field.getValue();
28611     }
28612 });
28613 /*
28614  * Based on:
28615  * Ext JS Library 1.1.1
28616  * Copyright(c) 2006-2007, Ext JS, LLC.
28617  *
28618  * Originally Released Under LGPL - original licence link has changed is not relivant.
28619  *
28620  * Fork - LGPL
28621  * <script type="text/javascript">
28622  */
28623  
28624 /**
28625  * @class Roo.BasicDialog
28626  * @extends Roo.util.Observable
28627  * Lightweight Dialog Class.  The code below shows the creation of a typical dialog using existing HTML markup:
28628  * <pre><code>
28629 var dlg = new Roo.BasicDialog("my-dlg", {
28630     height: 200,
28631     width: 300,
28632     minHeight: 100,
28633     minWidth: 150,
28634     modal: true,
28635     proxyDrag: true,
28636     shadow: true
28637 });
28638 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28639 dlg.addButton('OK', dlg.hide, dlg);    // Could call a save function instead of hiding
28640 dlg.addButton('Cancel', dlg.hide, dlg);
28641 dlg.show();
28642 </code></pre>
28643   <b>A Dialog should always be a direct child of the body element.</b>
28644  * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28645  * @cfg {String} title Default text to display in the title bar (defaults to null)
28646  * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
28647  * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
28648  * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28649  * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28650  * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28651  * (defaults to null with no animation)
28652  * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28653  * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28654  * property for valid values (defaults to 'all')
28655  * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28656  * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28657  * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28658  * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28659  * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28660  * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28661  * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28662  * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28663  * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28664  * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28665  * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28666  * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28667  * draggable = true (defaults to false)
28668  * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28669  * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28670  * shadow (defaults to false)
28671  * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28672  * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28673  * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28674  * @cfg {Array} buttons Array of buttons
28675  * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28676  * @constructor
28677  * Create a new BasicDialog.
28678  * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28679  * @param {Object} config Configuration options
28680  */
28681 Roo.BasicDialog = function(el, A){
28682     this.el = Roo.get(el);
28683     var  dh = Roo.DomHelper;
28684     if(!this.el && A && A.autoCreate){
28685         if(typeof  A.autoCreate == "object"){
28686             if(!A.autoCreate.id){
28687                 A.autoCreate.id = el;
28688             }
28689
28690             this.el = dh.append(document.body,
28691                         A.autoCreate, true);
28692         }else {
28693             this.el = dh.append(document.body,
28694                         {tag: "div", id: el, style:'visibility:hidden;'}, true);
28695         }
28696     }
28697
28698     el = this.el;
28699     el.setDisplayed(true);
28700     el.hide = this.hideAction;
28701     this.id = el.id;
28702     el.addClass("x-dlg");
28703
28704     Roo.apply(this, A);
28705
28706     this.proxy = el.createProxy("x-dlg-proxy");
28707     this.proxy.hide = this.hideAction;
28708     this.proxy.setOpacity(.5);
28709     this.proxy.hide();
28710
28711     if(A.width){
28712         el.setWidth(A.width);
28713     }
28714     if(A.height){
28715         el.setHeight(A.height);
28716     }
28717
28718     this.size = el.getSize();
28719     if(typeof  A.x != "undefined" && typeof  A.y != "undefined"){
28720         this.xy = [A.x,A.y];
28721     }else {
28722         this.xy = el.getCenterXY(true);
28723     }
28724
28725     /** The header element @type Roo.Element */
28726     this.header = el.child("> .x-dlg-hd");
28727     /** The body element @type Roo.Element */
28728     this.body = el.child("> .x-dlg-bd");
28729     /** The footer element @type Roo.Element */
28730     this.footer = el.child("> .x-dlg-ft");
28731
28732     if(!this.header){
28733         this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: "&#160;"}, this.body ? this.body.dom : null);
28734     }
28735     if(!this.body){
28736         this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28737     }
28738
28739
28740     this.header.unselectable();
28741     if(this.title){
28742         this.header.update(this.title);
28743     }
28744
28745     // this element allows the dialog to be focused for keyboard event
28746     this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28747     this.focusEl.swallowEvent("click", true);
28748
28749     this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28750
28751     // wrap the body and footer for special rendering
28752     this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28753     if(this.footer){
28754         this.bwrap.dom.appendChild(this.footer.dom);
28755     }
28756
28757
28758     this.bg = this.el.createChild({
28759         tag: "div", cls:"x-dlg-bg",
28760         html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center">&#160;</div></div></div>'
28761     });
28762     this.centerBg = this.bg.child("div.x-dlg-bg-center");
28763
28764
28765     if(this.autoScroll !== false && !this.autoTabs){
28766         this.body.setStyle("overflow", "auto");
28767     }
28768
28769
28770     this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28771
28772     if(this.closable !== false){
28773         this.el.addClass("x-dlg-closable");
28774         this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28775         this.close.on("click", this.closeClick, this);
28776         this.close.addClassOnOver("x-dlg-close-over");
28777     }
28778     if(this.collapsible !== false){
28779         this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28780         this.collapseBtn.on("click", this.collapseClick, this);
28781         this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28782         this.header.on("dblclick", this.collapseClick, this);
28783     }
28784     if(this.resizable !== false){
28785         this.el.addClass("x-dlg-resizable");
28786         this.resizer = new  Roo.Resizable(el, {
28787             minWidth: this.minWidth || 80,
28788             minHeight:this.minHeight || 80,
28789             handles: this.resizeHandles || "all",
28790             pinned: true
28791         });
28792         this.resizer.on("beforeresize", this.beforeResize, this);
28793         this.resizer.on("resize", this.onResize, this);
28794     }
28795     if(this.draggable !== false){
28796         el.addClass("x-dlg-draggable");
28797         if (!this.proxyDrag) {
28798             var  dd = new  Roo.dd.DD(el.dom.id, "WindowDrag");
28799         }
28800         else  {
28801             var  dd = new  Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28802         }
28803
28804         dd.setHandleElId(this.header.id);
28805         dd.endDrag = this.endMove.createDelegate(this);
28806         dd.startDrag = this.startMove.createDelegate(this);
28807         dd.onDrag = this.onDrag.createDelegate(this);
28808         dd.scroll = false;
28809         this.dd = dd;
28810     }
28811     if(this.modal){
28812         this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28813         this.mask.enableDisplayMode("block");
28814         this.mask.hide();
28815         this.el.addClass("x-dlg-modal");
28816     }
28817     if(this.shadow){
28818         this.shadow = new  Roo.Shadow({
28819             mode : typeof  this.shadow == "string" ? this.shadow : "sides",
28820             offset : this.shadowOffset
28821         });
28822     }else {
28823         this.shadowOffset = 0;
28824     }
28825     if(Roo.useShims && this.shim !== false){
28826         this.shim = this.el.createShim();
28827         this.shim.hide = this.hideAction;
28828         this.shim.hide();
28829     }else {
28830         this.shim = false;
28831     }
28832     if(this.autoTabs){
28833         this.initTabs();
28834     }
28835     if (this.buttons) { 
28836         var  bts= this.buttons;
28837         this.buttons = [];
28838         Roo.each(bts, function(b) {
28839             this.addButton(b);
28840         }, this);
28841     }
28842
28843     
28844     
28845     this.addEvents({
28846         /**
28847          * @event keydown
28848          * Fires when a key is pressed
28849          * @param {Roo.BasicDialog} this
28850          * @param {Roo.EventObject} e
28851          */
28852         "keydown" : true,
28853         /**
28854          * @event move
28855          * Fires when this dialog is moved by the user.
28856          * @param {Roo.BasicDialog} this
28857          * @param {Number} x The new page X
28858          * @param {Number} y The new page Y
28859          */
28860         "move" : true,
28861         /**
28862          * @event resize
28863          * Fires when this dialog is resized by the user.
28864          * @param {Roo.BasicDialog} this
28865          * @param {Number} width The new width
28866          * @param {Number} height The new height
28867          */
28868         "resize" : true,
28869         /**
28870          * @event beforehide
28871          * Fires before this dialog is hidden.
28872          * @param {Roo.BasicDialog} this
28873          */
28874         "beforehide" : true,
28875         /**
28876          * @event hide
28877          * Fires when this dialog is hidden.
28878          * @param {Roo.BasicDialog} this
28879          */
28880         "hide" : true,
28881         /**
28882          * @event beforeshow
28883          * Fires before this dialog is shown.
28884          * @param {Roo.BasicDialog} this
28885          */
28886         "beforeshow" : true,
28887         /**
28888          * @event show
28889          * Fires when this dialog is shown.
28890          * @param {Roo.BasicDialog} this
28891          */
28892         "show" : true
28893     });
28894     el.on("keydown", this.onKeyDown, this);
28895     el.on("mousedown", this.toFront, this);
28896     Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28897     this.el.hide();
28898     Roo.DialogManager.register(this);
28899     Roo.BasicDialog.superclass.constructor.call(this);
28900 };
28901
28902 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28903     shadowOffset: Roo.isIE ? 6 : 5,
28904     minHeight: 80,
28905     minWidth: 200,
28906     minButtonWidth: 75,
28907     defaultButton: null,
28908     buttonAlign: "right",
28909     tabTag: 'div',
28910     firstShow: true,
28911
28912     /**
28913      * Sets the dialog title text
28914      * @param {String} text The title text to display
28915      * @return {Roo.BasicDialog} this
28916      */
28917     setTitle : function(B){
28918         this.header.update(B);
28919         return  this;
28920     },
28921
28922     // private
28923     closeClick : function(){
28924         this.hide();
28925     },
28926
28927     // private
28928     collapseClick : function(){
28929         this[this.collapsed ? "expand" : "collapse"]();
28930     },
28931
28932     /**
28933      * Collapses the dialog to its minimized state (only the title bar is visible).
28934      * Equivalent to the user clicking the collapse dialog button.
28935      */
28936     collapse : function(){
28937         if(!this.collapsed){
28938             this.collapsed = true;
28939             this.el.addClass("x-dlg-collapsed");
28940             this.restoreHeight = this.el.getHeight();
28941             this.resizeTo(this.el.getWidth(), this.header.getHeight());
28942         }
28943     },
28944
28945     /**
28946      * Expands a collapsed dialog back to its normal state.  Equivalent to the user
28947      * clicking the expand dialog button.
28948      */
28949     expand : function(){
28950         if(this.collapsed){
28951             this.collapsed = false;
28952             this.el.removeClass("x-dlg-collapsed");
28953             this.resizeTo(this.el.getWidth(), this.restoreHeight);
28954         }
28955     },
28956
28957     /**
28958      * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28959      * @return {Roo.TabPanel} The tabs component
28960      */
28961     initTabs : function(){
28962         var  C = this.getTabs();
28963         while(C.getTab(0)){
28964             C.removeTab(0);
28965         }
28966
28967         this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28968             var  D = el.dom;
28969             C.addTab(Roo.id(D), D.title);
28970             D.title = "";
28971         });
28972         C.activate(0);
28973         return  C;
28974     },
28975
28976     // private
28977     beforeResize : function(){
28978         this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28979     },
28980
28981     // private
28982     onResize : function(){
28983         this.refreshSize();
28984         this.syncBodyHeight();
28985         this.adjustAssets();
28986         this.focus();
28987         this.fireEvent("resize", this, this.size.width, this.size.height);
28988     },
28989
28990     // private
28991     onKeyDown : function(e){
28992         if(this.isVisible()){
28993             this.fireEvent("keydown", this, e);
28994         }
28995     },
28996
28997     /**
28998      * Resizes the dialog.
28999      * @param {Number} width
29000      * @param {Number} height
29001      * @return {Roo.BasicDialog} this
29002      */
29003     resizeTo : function(D, E){
29004         this.el.setSize(D, E);
29005         this.size = {width: D, height: E};
29006         this.syncBodyHeight();
29007         if(this.fixedcenter){
29008             this.center();
29009         }
29010         if(this.isVisible()){
29011             this.constrainXY();
29012             this.adjustAssets();
29013         }
29014
29015         this.fireEvent("resize", this, D, E);
29016         return  this;
29017     },
29018
29019
29020     /**
29021      * Resizes the dialog to fit the specified content size.
29022      * @param {Number} width
29023      * @param {Number} height
29024      * @return {Roo.BasicDialog} this
29025      */
29026     setContentSize : function(w, h){
29027         h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29028         w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29029         //if(!this.el.isBorderBox()){
29030             h +=  this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29031             w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29032         //}
29033         if(this.tabs){
29034             h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29035             w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29036         }
29037
29038         this.resizeTo(w, h);
29039         return  this;
29040     },
29041
29042     /**
29043      * Adds a key listener for when this dialog is displayed.  This allows you to hook in a function that will be
29044      * executed in response to a particular key being pressed while the dialog is active.
29045      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29046      *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29047      * @param {Function} fn The function to call
29048      * @param {Object} scope (optional) The scope of the function
29049      * @return {Roo.BasicDialog} this
29050      */
29051     addKeyListener : function(F, fn, G){
29052         var  H, I, J, K;
29053         if(typeof  F == "object" && !(F  instanceof  Array)){
29054             H = F["key"];
29055             I = F["shift"];
29056             J = F["ctrl"];
29057             K = F["alt"];
29058         }else {
29059             H = F;
29060         }
29061         var  L = function(M, e){
29062             if((!I || e.shiftKey) && (!J || e.ctrlKey) &&  (!K || e.altKey)){
29063                 var  k = e.getKey();
29064                 if(H  instanceof  Array){
29065                     for(var  i = 0, len = H.length; i < len; i++){
29066                         if(H[i] == k){
29067                           fn.call(G || window, M, k, e);
29068                           return;
29069                         }
29070                     }
29071                 }else {
29072                     if(k == H){
29073                         fn.call(G || window, M, k, e);
29074                     }
29075                 }
29076             }
29077         };
29078         this.on("keydown", L);
29079         return  this;
29080     },
29081
29082     /**
29083      * Returns the TabPanel component (creates it if it doesn't exist).
29084      * Note: If you wish to simply check for the existence of tabs without creating them,
29085      * check for a null 'tabs' property.
29086      * @return {Roo.TabPanel} The tabs component
29087      */
29088     getTabs : function(){
29089         if(!this.tabs){
29090             this.el.addClass("x-dlg-auto-tabs");
29091             this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29092             this.tabs = new  Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29093         }
29094         return  this.tabs;
29095     },
29096
29097     /**
29098      * Adds a button to the footer section of the dialog.
29099      * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29100      * object or a valid Roo.DomHelper element config
29101      * @param {Function} handler The function called when the button is clicked
29102      * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29103      * @return {Roo.Button} The new button
29104      */
29105     addButton : function(M, N, O){
29106         var  dh = Roo.DomHelper;
29107         if(!this.footer){
29108             this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29109         }
29110         if(!this.btnContainer){
29111             var  tb = this.footer.createChild({
29112
29113                 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29114                 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29115             }, null, true);
29116             this.btnContainer = tb.firstChild.firstChild.firstChild;
29117         }
29118         var  P = {
29119             handler: N,
29120             scope: O,
29121             minWidth: this.minButtonWidth,
29122             hideParent:true
29123         };
29124         if(typeof  M == "string"){
29125             P.text = M;
29126         }else {
29127             if(M.tag){
29128                 P.dhconfig = M;
29129             }else {
29130                 Roo.apply(P, M);
29131             }
29132         }
29133         var  fc = false;
29134         if ((typeof(P.position) != 'undefined') && P.position < this.btnContainer.childNodes.length-1) {
29135             P.position = Math.max(0, P.position);
29136             fc = this.btnContainer.childNodes[P.position];
29137         }
29138          
29139         var  Q = new  Roo.Button(
29140             fc ? 
29141                 this.btnContainer.insertBefore(document.createElement("td"),fc)
29142                 : this.btnContainer.appendChild(document.createElement("td")),
29143             //Roo.get(this.btnContainer).createChild( { tag: 'td'},  fc ),
29144             P
29145         );
29146         this.syncBodyHeight();
29147         if(!this.buttons){
29148             /**
29149              * Array of all the buttons that have been added to this dialog via addButton
29150              * @type Array
29151              */
29152             this.buttons = [];
29153         }
29154
29155         this.buttons.push(Q);
29156         return  Q;
29157     },
29158
29159     /**
29160      * Sets the default button to be focused when the dialog is displayed.
29161      * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29162      * @return {Roo.BasicDialog} this
29163      */
29164     setDefaultButton : function(R){
29165         this.defaultButton = R;
29166         return  this;
29167     },
29168
29169     // private
29170     getHeaderFooterHeight : function(S){
29171         var  T = 0;
29172         if(this.header){
29173            T += this.header.getHeight();
29174         }
29175         if(this.footer){
29176            var  fm = this.footer.getMargins();
29177             T += (this.footer.getHeight()+fm.top+fm.bottom);
29178         }
29179
29180         T += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29181         T += this.centerBg.getPadding("tb");
29182         return  T;
29183     },
29184
29185     // private
29186     syncBodyHeight : function(){
29187         var  bd = this.body, cb = this.centerBg, bw = this.bwrap;
29188         var  U = this.size.height - this.getHeaderFooterHeight(false);
29189         bd.setHeight(U-bd.getMargins("tb"));
29190         var  hh = this.header.getHeight();
29191         var  h = this.size.height-hh;
29192         cb.setHeight(h);
29193         bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29194         bw.setHeight(h-cb.getPadding("tb"));
29195         bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29196         bd.setWidth(bw.getWidth(true));
29197         if(this.tabs){
29198             this.tabs.syncHeight();
29199             if(Roo.isIE){
29200                 this.tabs.el.repaint();
29201             }
29202         }
29203     },
29204
29205     /**
29206      * Restores the previous state of the dialog if Roo.state is configured.
29207      * @return {Roo.BasicDialog} this
29208      */
29209     restoreState : function(){
29210         var  V = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29211         if(V && V.width){
29212             this.xy = [V.x, V.y];
29213             this.resizeTo(V.width, V.height);
29214         }
29215         return  this;
29216     },
29217
29218     // private
29219     beforeShow : function(){
29220         this.expand();
29221         if(this.fixedcenter){
29222             this.xy = this.el.getCenterXY(true);
29223         }
29224         if(this.modal){
29225             Roo.get(document.body).addClass("x-body-masked");
29226             this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29227             this.mask.show();
29228         }
29229
29230         this.constrainXY();
29231     },
29232
29233     // private
29234     animShow : function(){
29235         var  b = Roo.get(this.animateTarget, true).getBox();
29236         this.proxy.setSize(b.width, b.height);
29237         this.proxy.setLocation(b.x, b.y);
29238         this.proxy.show();
29239         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29240                     true, .35, this.showEl.createDelegate(this));
29241     },
29242
29243     /**
29244      * Shows the dialog.
29245      * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29246      * @return {Roo.BasicDialog} this
29247      */
29248     show : function(W){
29249         if (this.fireEvent("beforeshow", this) === false){
29250             return;
29251         }
29252         if(this.syncHeightBeforeShow){
29253             this.syncBodyHeight();
29254         }else  if(this.firstShow){
29255             this.firstShow = false;
29256             this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29257         }
29258
29259         this.animateTarget = W || this.animateTarget;
29260         if(!this.el.isVisible()){
29261             this.beforeShow();
29262             if(this.animateTarget){
29263                 this.animShow();
29264             }else {
29265                 this.showEl();
29266             }
29267         }
29268         return  this;
29269     },
29270
29271     // private
29272     showEl : function(){
29273         this.proxy.hide();
29274         this.el.setXY(this.xy);
29275         this.el.show();
29276         this.adjustAssets(true);
29277         this.toFront();
29278         this.focus();
29279         // IE peekaboo bug - fix found by Dave Fenwick
29280         if(Roo.isIE){
29281             this.el.repaint();
29282         }
29283
29284         this.fireEvent("show", this);
29285     },
29286
29287     /**
29288      * Focuses the dialog.  If a defaultButton is set, it will receive focus, otherwise the
29289      * dialog itself will receive focus.
29290      */
29291     focus : function(){
29292         if(this.defaultButton){
29293             this.defaultButton.focus();
29294         }else {
29295             this.focusEl.focus();
29296         }
29297     },
29298
29299     // private
29300     constrainXY : function(){
29301         if(this.constraintoviewport !== false){
29302             if(!this.viewSize){
29303                 if(this.container){
29304                     var  s = this.container.getSize();
29305                     this.viewSize = [s.width, s.height];
29306                 }else {
29307                     this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29308                 }
29309             }
29310             var  s = Roo.get(this.container||document).getScroll();
29311
29312             var  x = this.xy[0], y = this.xy[1];
29313             var  w = this.size.width, h = this.size.height;
29314             var  vw = this.viewSize[0], vh = this.viewSize[1];
29315             // only move it if it needs it
29316             var  moved = false;
29317             // first validate right/bottom
29318             if(x + w > vw+s.left){
29319                 x = vw - w;
29320                 moved = true;
29321             }
29322             if(y + h > vh+s.top){
29323                 y = vh - h;
29324                 moved = true;
29325             }
29326             // then make sure top/left isn't negative
29327             if(x < s.left){
29328                 x = s.left;
29329                 moved = true;
29330             }
29331             if(y < s.top){
29332                 y = s.top;
29333                 moved = true;
29334             }
29335             if(moved){
29336                 // cache xy
29337                 this.xy = [x, y];
29338                 if(this.isVisible()){
29339                     this.el.setLocation(x, y);
29340                     this.adjustAssets();
29341                 }
29342             }
29343         }
29344     },
29345
29346     // private
29347     onDrag : function(){
29348         if(!this.proxyDrag){
29349             this.xy = this.el.getXY();
29350             this.adjustAssets();
29351         }
29352     },
29353
29354     // private
29355     adjustAssets : function(X){
29356         var  x = this.xy[0], y = this.xy[1];
29357         var  w = this.size.width, h = this.size.height;
29358         if(X === true){
29359             if(this.shadow){
29360                 this.shadow.show(this.el);
29361             }
29362             if(this.shim){
29363                 this.shim.show();
29364             }
29365         }
29366         if(this.shadow && this.shadow.isVisible()){
29367             this.shadow.show(this.el);
29368         }
29369         if(this.shim && this.shim.isVisible()){
29370             this.shim.setBounds(x, y, w, h);
29371         }
29372     },
29373
29374     // private
29375     adjustViewport : function(w, h){
29376         if(!w || !h){
29377             w = Roo.lib.Dom.getViewWidth();
29378             h = Roo.lib.Dom.getViewHeight();
29379         }
29380
29381         // cache the size
29382         this.viewSize = [w, h];
29383         if(this.modal && this.mask.isVisible()){
29384             this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29385             this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29386         }
29387         if(this.isVisible()){
29388             this.constrainXY();
29389         }
29390     },
29391
29392     /**
29393      * Destroys this dialog and all its supporting elements (including any tabs, shim,
29394      * shadow, proxy, mask, etc.)  Also removes all event listeners.
29395      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29396      */
29397     destroy : function(Y){
29398         if(this.isVisible()){
29399             this.animateTarget = null;
29400             this.hide();
29401         }
29402
29403         Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29404         if(this.tabs){
29405             this.tabs.destroy(Y);
29406         }
29407
29408         Roo.destroy(
29409              this.shim,
29410              this.proxy,
29411              this.resizer,
29412              this.close,
29413              this.mask
29414         );
29415         if(this.dd){
29416             this.dd.unreg();
29417         }
29418         if(this.buttons){
29419            for(var  i = 0, len = this.buttons.length; i < len; i++){
29420                this.buttons[i].destroy();
29421            }
29422         }
29423
29424         this.el.removeAllListeners();
29425         if(Y === true){
29426             this.el.update("");
29427             this.el.remove();
29428         }
29429
29430         Roo.DialogManager.unregister(this);
29431     },
29432
29433     // private
29434     startMove : function(){
29435         if(this.proxyDrag){
29436             this.proxy.show();
29437         }
29438         if(this.constraintoviewport !== false){
29439             this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29440         }
29441     },
29442
29443     // private
29444     endMove : function(){
29445         if(!this.proxyDrag){
29446             Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29447         }else {
29448             Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29449             this.proxy.hide();
29450         }
29451
29452         this.refreshSize();
29453         this.adjustAssets();
29454         this.focus();
29455         this.fireEvent("move", this, this.xy[0], this.xy[1]);
29456     },
29457
29458     /**
29459      * Brings this dialog to the front of any other visible dialogs
29460      * @return {Roo.BasicDialog} this
29461      */
29462     toFront : function(){
29463         Roo.DialogManager.bringToFront(this);
29464         return  this;
29465     },
29466
29467     /**
29468      * Sends this dialog to the back (under) of any other visible dialogs
29469      * @return {Roo.BasicDialog} this
29470      */
29471     toBack : function(){
29472         Roo.DialogManager.sendToBack(this);
29473         return  this;
29474     },
29475
29476     /**
29477      * Centers this dialog in the viewport
29478      * @return {Roo.BasicDialog} this
29479      */
29480     center : function(){
29481         var  xy = this.el.getCenterXY(true);
29482         this.moveTo(xy[0], xy[1]);
29483         return  this;
29484     },
29485
29486     /**
29487      * Moves the dialog's top-left corner to the specified point
29488      * @param {Number} x
29489      * @param {Number} y
29490      * @return {Roo.BasicDialog} this
29491      */
29492     moveTo : function(x, y){
29493         this.xy = [x,y];
29494         if(this.isVisible()){
29495             this.el.setXY(this.xy);
29496             this.adjustAssets();
29497         }
29498         return  this;
29499     },
29500
29501     /**
29502      * Aligns the dialog to the specified element
29503      * @param {String/HTMLElement/Roo.Element} element The element to align to.
29504      * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29505      * @param {Array} offsets (optional) Offset the positioning by [x, y]
29506      * @return {Roo.BasicDialog} this
29507      */
29508     alignTo : function(Z, a, c){
29509         this.xy = this.el.getAlignToXY(Z, a, c);
29510         if(this.isVisible()){
29511             this.el.setXY(this.xy);
29512             this.adjustAssets();
29513         }
29514         return  this;
29515     },
29516
29517     /**
29518      * Anchors an element to another element and realigns it when the window is resized.
29519      * @param {String/HTMLElement/Roo.Element} element The element to align to.
29520      * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29521      * @param {Array} offsets (optional) Offset the positioning by [x, y]
29522      * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29523      * is a number, it is used as the buffer delay (defaults to 50ms).
29524      * @return {Roo.BasicDialog} this
29525      */
29526     anchorTo : function(el, d, f, g){
29527         var  j = function(){
29528             this.alignTo(el, d, f);
29529         };
29530         Roo.EventManager.onWindowResize(j, this);
29531         var  tm = typeof  g;
29532         if(tm != 'undefined'){
29533             Roo.EventManager.on(window, 'scroll', j, this,
29534                 {buffer: tm == 'number' ? g : 50});
29535         }
29536
29537         j.call(this);
29538         return  this;
29539     },
29540
29541     /**
29542      * Returns true if the dialog is visible
29543      * @return {Boolean}
29544      */
29545     isVisible : function(){
29546         return  this.el.isVisible();
29547     },
29548
29549     // private
29550     animHide : function(l){
29551         var  b = Roo.get(this.animateTarget).getBox();
29552         this.proxy.show();
29553         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29554         this.el.hide();
29555         this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29556                     this.hideEl.createDelegate(this, [l]));
29557     },
29558
29559     /**
29560      * Hides the dialog.
29561      * @param {Function} callback (optional) Function to call when the dialog is hidden
29562      * @return {Roo.BasicDialog} this
29563      */
29564     hide : function(m){
29565         if (this.fireEvent("beforehide", this) === false){
29566             return;
29567         }
29568         if(this.shadow){
29569             this.shadow.hide();
29570         }
29571         if(this.shim) {
29572           this.shim.hide();
29573         }
29574         if(this.animateTarget){
29575            this.animHide(m);
29576         }else {
29577             this.el.hide();
29578             this.hideEl(m);
29579         }
29580         return  this;
29581     },
29582
29583     // private
29584     hideEl : function(n){
29585         this.proxy.hide();
29586         if(this.modal){
29587             this.mask.hide();
29588             Roo.get(document.body).removeClass("x-body-masked");
29589         }
29590
29591         this.fireEvent("hide", this);
29592         if(typeof  n == "function"){
29593             n();
29594         }
29595     },
29596
29597     // private
29598     hideAction : function(){
29599         this.setLeft("-10000px");
29600         this.setTop("-10000px");
29601         this.setStyle("visibility", "hidden");
29602     },
29603
29604     // private
29605     refreshSize : function(){
29606         this.size = this.el.getSize();
29607         this.xy = this.el.getXY();
29608         Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29609     },
29610
29611     // private
29612     // z-index is managed by the DialogManager and may be overwritten at any time
29613     setZIndex : function(o){
29614         if(this.modal){
29615             this.mask.setStyle("z-index", o);
29616         }
29617         if(this.shim){
29618             this.shim.setStyle("z-index", ++o);
29619         }
29620         if(this.shadow){
29621             this.shadow.setZIndex(++o);
29622         }
29623
29624         this.el.setStyle("z-index", ++o);
29625         if(this.proxy){
29626             this.proxy.setStyle("z-index", ++o);
29627         }
29628         if(this.resizer){
29629             this.resizer.proxy.setStyle("z-index", ++o);
29630         }
29631
29632
29633         this.lastZIndex = o;
29634     },
29635
29636     /**
29637      * Returns the element for this dialog
29638      * @return {Roo.Element} The underlying dialog Element
29639      */
29640     getEl : function(){
29641         return  this.el;
29642     }
29643 });
29644
29645 /**
29646  * @class Roo.DialogManager
29647  * Provides global access to BasicDialogs that have been created and
29648  * support for z-indexing (layering) multiple open dialogs.
29649  */
29650 Roo.DialogManager = function(){
29651     var  p = {};
29652     var  q = [];
29653     var  r = null;
29654
29655     // private
29656     var  t = function(d1, d2){
29657         return  (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29658     };
29659
29660     // private
29661     var  u = function(){
29662         q.sort(t);
29663         var  v = Roo.DialogManager.zseed;
29664         for(var  i = 0, len = q.length; i < len; i++){
29665             var  dlg = q[i];
29666             if(dlg){
29667                 dlg.setZIndex(v + (i*10));
29668             }
29669         }
29670     };
29671
29672     return  {
29673         /**
29674          * The starting z-index for BasicDialogs (defaults to 9000)
29675          * @type Number The z-index value
29676          */
29677         zseed : 9000,
29678
29679         // private
29680         register : function(AD){
29681             p[AD.id] = AD;
29682             q.push(AD);
29683         },
29684
29685         // private
29686         unregister : function(AE){
29687             delete  p[AE.id];
29688             var  i=0;
29689             var  AF=0;
29690             if(!q.indexOf){
29691                 for(  i = 0, AF = q.length; i < AF; i++){
29692                     if(q[i] == AE){
29693                         q.splice(i, 1);
29694                         return;
29695                     }
29696                 }
29697             }else {
29698                  i = q.indexOf(AE);
29699                 if(i != -1){
29700                     q.splice(i, 1);
29701                 }
29702             }
29703         },
29704
29705         /**
29706          * Gets a registered dialog by id
29707          * @param {String/Object} id The id of the dialog or a dialog
29708          * @return {Roo.BasicDialog} this
29709          */
29710         get : function(id){
29711             return  typeof  id == "object" ? id : p[id];
29712         },
29713
29714         /**
29715          * Brings the specified dialog to the front
29716          * @param {String/Object} dlg The id of the dialog or a dialog
29717          * @return {Roo.BasicDialog} this
29718          */
29719         bringToFront : function(AG){
29720             AG = this.get(AG);
29721             if(AG != r){
29722                 r = AG;
29723                 AG._lastAccess = new  Date().getTime();
29724                 u();
29725             }
29726             return  AG;
29727         },
29728
29729         /**
29730          * Sends the specified dialog to the back
29731          * @param {String/Object} dlg The id of the dialog or a dialog
29732          * @return {Roo.BasicDialog} this
29733          */
29734         sendToBack : function(AH){
29735             AH = this.get(AH);
29736             AH._lastAccess = -(new  Date().getTime());
29737             u();
29738             return  AH;
29739         },
29740
29741         /**
29742          * Hides all dialogs
29743          */
29744         hideAll : function(){
29745             for(var  id  in  p){
29746                 if(p[id] && typeof  p[id] != "function" && p[id].isVisible()){
29747                     p[id].hide();
29748                 }
29749             }
29750         }
29751     };
29752 }();
29753
29754 /**
29755  * @class Roo.LayoutDialog
29756  * @extends Roo.BasicDialog
29757  * Dialog which provides adjustments for working with a layout in a Dialog.
29758  * Add your necessary layout config options to the dialog's config.<br>
29759  * Example usage (including a nested layout):
29760  * <pre><code>
29761 if(!dialog){
29762     dialog = new Roo.LayoutDialog("download-dlg", {
29763         modal: true,
29764         width:600,
29765         height:450,
29766         shadow:true,
29767         minWidth:500,
29768         minHeight:350,
29769         autoTabs:true,
29770         proxyDrag:true,
29771         // layout config merges with the dialog config
29772         center:{
29773             tabPosition: "top",
29774             alwaysShowTabs: true
29775         }
29776     });
29777     dialog.addKeyListener(27, dialog.hide, dialog);
29778     dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29779     dialog.addButton("Build It!", this.getDownload, this);
29780
29781     // we can even add nested layouts
29782     var innerLayout = new Roo.BorderLayout("dl-inner", {
29783         east: {
29784             initialSize: 200,
29785             autoScroll:true,
29786             split:true
29787         },
29788         center: {
29789             autoScroll:true
29790         }
29791     });
29792     innerLayout.beginUpdate();
29793     innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29794     innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29795     innerLayout.endUpdate(true);
29796
29797     var layout = dialog.getLayout();
29798     layout.beginUpdate();
29799     layout.add("center", new Roo.ContentPanel("standard-panel",
29800                         {title: "Download the Source", fitToFrame:true}));
29801     layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29802                {title: "Build your own roo.js"}));
29803     layout.getRegion("center").showPanel(sp);
29804     layout.endUpdate();
29805 }
29806 </code></pre>
29807     * @constructor
29808     * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29809     * @param {Object} config configuration options
29810   */
29811 Roo.LayoutDialog = function(el, v){
29812     
29813     var  z=  v;
29814     if (typeof(v) == 'undefined') {
29815         z = Roo.apply({}, el);
29816         el = Roo.get( document.documentElement || document.body).createChild();
29817         //config.autoCreate = true;
29818     }
29819
29820     
29821     
29822     z.autoTabs = false;
29823     Roo.LayoutDialog.superclass.constructor.call(this, el, z);
29824     this.body.setStyle({overflow:"hidden", position:"relative"});
29825     this.layout = new  Roo.BorderLayout(this.body.dom, z);
29826     this.layout.monitorWindowResize = false;
29827     this.el.addClass("x-dlg-auto-layout");
29828     // fix case when center region overwrites center function
29829     this.center = Roo.BasicDialog.prototype.center;
29830     this.on("show", this.layout.layout, this.layout, true);
29831     if (z.items) {
29832         var  xitems = z.items;
29833         delete  z.items;
29834         Roo.each(xitems, this.addxtype, this);
29835     }
29836     
29837     
29838 };
29839 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29840     /**
29841      * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29842      * @deprecated
29843      */
29844     endUpdate : function(){
29845         this.layout.endUpdate();
29846     },
29847
29848     /**
29849      * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29850      *  @deprecated
29851      */
29852     beginUpdate : function(){
29853         this.layout.beginUpdate();
29854     },
29855
29856     /**
29857      * Get the BorderLayout for this dialog
29858      * @return {Roo.BorderLayout}
29859      */
29860     getLayout : function(){
29861         return  this.layout;
29862     },
29863
29864     showEl : function(){
29865         Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29866         if(Roo.isIE7){
29867             this.layout.layout();
29868         }
29869     },
29870
29871     // private
29872     // Use the syncHeightBeforeShow config option to control this automatically
29873     syncBodyHeight : function(){
29874         Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29875         if(this.layout){this.layout.layout();}
29876     },
29877     
29878       /**
29879      * Add an xtype element (actually adds to the layout.)
29880      * @return {Object} xdata xtype object data.
29881      */
29882     
29883     addxtype : function(c) {
29884         return  this.layout.addxtype(c);
29885     }
29886 });
29887 /*
29888  * Based on:
29889  * Ext JS Library 1.1.1
29890  * Copyright(c) 2006-2007, Ext JS, LLC.
29891  *
29892  * Originally Released Under LGPL - original licence link has changed is not relivant.
29893  *
29894  * Fork - LGPL
29895  * <script type="text/javascript">
29896  */
29897  
29898 /**
29899  * @class Roo.MessageBox
29900  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
29901  * Example usage:
29902  *<pre><code>
29903 // Basic alert:
29904 Roo.Msg.alert('Status', 'Changes saved successfully.');
29905
29906 // Prompt for user data:
29907 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29908     if (btn == 'ok'){
29909         // process text value...
29910     }
29911 });
29912
29913 // Show a dialog using config options:
29914 Roo.Msg.show({
29915    title:'Save Changes?',
29916    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29917    buttons: Roo.Msg.YESNOCANCEL,
29918    fn: processResult,
29919    animEl: 'elId'
29920 });
29921 </code></pre>
29922  * @singleton
29923  */
29924 Roo.MessageBox = function(){
29925     var  A, B, C, D;
29926     var  E, F, G, H, I, pp;
29927     var  J, K, L;
29928
29929     // private
29930     var  M = function(Q){
29931         A.hide();
29932         Roo.callback(B.fn, B.scope||window, [Q, K.dom.value], 1);
29933     };
29934
29935     // private
29936     var  N = function(){
29937         if(B && B.cls){
29938             A.el.removeClass(B.cls);
29939         }
29940         if(D){
29941             Roo.TaskMgr.stop(D);
29942             D = null;
29943         }
29944     };
29945
29946     // private
29947     var  O = function(b){
29948         var  Q = 0;
29949         if(!b){
29950             J["ok"].hide();
29951             J["cancel"].hide();
29952             J["yes"].hide();
29953             J["no"].hide();
29954             A.footer.dom.style.display = 'none';
29955             return  Q;
29956         }
29957
29958         A.footer.dom.style.display = '';
29959         for(var  k  in  J){
29960             if(typeof  J[k] != "function"){
29961                 if(b[k]){
29962                     J[k].show();
29963                     J[k].setText(typeof  b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29964                     Q += J[k].el.getWidth()+15;
29965                 }else {
29966                     J[k].hide();
29967                 }
29968             }
29969         }
29970         return  Q;
29971     };
29972
29973     // private
29974     var  P = function(d, k, e){
29975         if(B && B.closable !== false){
29976             A.hide();
29977         }
29978         if(e){
29979             e.stopEvent();
29980         }
29981     };
29982
29983     return  {
29984         /**
29985          * Returns a reference to the underlying {@link Roo.BasicDialog} element
29986          * @return {Roo.BasicDialog} The BasicDialog element
29987          */
29988         getDialog : function(){
29989            if(!A){
29990                 A = new  Roo.BasicDialog("x-msg-box", {
29991                     autoCreate : true,
29992                     shadow: true,
29993                     draggable: true,
29994                     resizable:false,
29995                     constraintoviewport:false,
29996                     fixedcenter:true,
29997                     collapsible : false,
29998                     shim:true,
29999                     modal: true,
30000                     width:400, height:100,
30001                     buttonAlign:"center",
30002                     closeClick : function(){
30003                         if(B && B.buttons && B.buttons.no && !B.buttons.cancel){
30004                             M("no");
30005                         }else {
30006                             M("cancel");
30007                         }
30008                     }
30009                 });
30010                 A.on("hide", N);
30011                 C = A.mask;
30012                 A.addKeyListener(27, P);
30013                 J = {};
30014                 var  bt = this.buttonText;
30015                 J["ok"] = A.addButton(bt["ok"], M.createCallback("ok"));
30016                 J["yes"] = A.addButton(bt["yes"], M.createCallback("yes"));
30017                 J["no"] = A.addButton(bt["no"], M.createCallback("no"));
30018                 J["cancel"] = A.addButton(bt["cancel"], M.createCallback("cancel"));
30019                 E = A.body.createChild({
30020
30021                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
30022                 });
30023                 F = E.dom.firstChild;
30024                 G = Roo.get(E.dom.childNodes[2]);
30025                 G.enableDisplayMode();
30026                 G.addKeyListener([10,13], function(){
30027                     if(A.isVisible() && B && B.buttons){
30028                         if(B.buttons.ok){
30029                             M("ok");
30030                         }else  if(B.buttons.yes){
30031                             M("yes");
30032                         }
30033                     }
30034                 });
30035                 H = Roo.get(E.dom.childNodes[3]);
30036                 H.enableDisplayMode();
30037                 I = Roo.get(E.dom.childNodes[4]);
30038                 I.enableDisplayMode();
30039                 var  pf = I.dom.firstChild;
30040                 if (pf) {
30041                     pp = Roo.get(pf.firstChild);
30042                     pp.setHeight(pf.offsetHeight);
30043                 }
30044                 
30045             }
30046             return  A;
30047         },
30048
30049         /**
30050          * Updates the message box body text
30051          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30052          * the XHTML-compliant non-breaking space character '&amp;#160;')
30053          * @return {Roo.MessageBox} This message box
30054          */
30055         updateText : function(j){
30056             if(!A.isVisible() && !B.width){
30057                 A.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30058             }
30059
30060             F.innerHTML = j || '&#160;';
30061             var  w = Math.max(Math.min(B.width || F.offsetWidth, this.maxWidth), 
30062                         Math.max(B.minWidth || this.minWidth, L));
30063             if(B.prompt){
30064                 K.setWidth(w);
30065             }
30066             if(A.isVisible()){
30067                 A.fixedcenter = false;
30068             }
30069
30070             A.setContentSize(w, E.getHeight());
30071             if(A.isVisible()){
30072                 A.fixedcenter = true;
30073             }
30074             return  this;
30075         },
30076
30077         /**
30078          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
30079          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30080          * @param {Number} value Any number between 0 and 1 (e.g., .5)
30081          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30082          * @return {Roo.MessageBox} This message box
30083          */
30084         updateProgress : function(l, m){
30085             if(m){
30086                 this.updateText(m);
30087             }
30088             if (pp) { // weird bug on my firefox - for some reason this is not defined
30089                 pp.setWidth(Math.floor(l*I.dom.firstChild.offsetWidth));
30090             }
30091             return  this;
30092         },        
30093
30094         /**
30095          * Returns true if the message box is currently displayed
30096          * @return {Boolean} True if the message box is visible, else false
30097          */
30098         isVisible : function(){
30099             return  A && A.isVisible();  
30100         },
30101
30102         /**
30103          * Hides the message box if it is displayed
30104          */
30105         hide : function(){
30106             if(this.isVisible()){
30107                 A.hide();
30108             }  
30109         },
30110
30111         /**
30112          * Displays a new message box, or reinitializes an existing message box, based on the config options
30113          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30114          * The following config object properties are supported:
30115          * <pre>
30116 Property    Type             Description
30117 ----------  ---------------  ------------------------------------------------------------------------------------
30118 animEl            String/Element   An id or Element from which the message box should animate as it opens and
30119                                    closes (defaults to undefined)
30120 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30121                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
30122 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
30123                                    progress and wait dialogs will ignore this property and always hide the
30124                                    close button as they can only be closed programmatically.
30125 cls               String           A custom CSS class to apply to the message box element
30126 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
30127                                    displayed (defaults to 75)
30128 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
30129                                    function will be btn (the name of the button that was clicked, if applicable,
30130                                    e.g. "ok"), and text (the value of the active text field, if applicable).
30131                                    Progress and wait dialogs will ignore this option since they do not respond to
30132                                    user actions and can only be closed programmatically, so any required function
30133                                    should be called by the same code after it closes the dialog.
30134 icon              String           A CSS class that provides a background image to be used as an icon for
30135                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30136 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
30137 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
30138 modal             Boolean          False to allow user interaction with the page while the message box is
30139                                    displayed (defaults to true)
30140 msg               String           A string that will replace the existing message box body text (defaults
30141                                    to the XHTML-compliant non-breaking space character '&#160;')
30142 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
30143 progress          Boolean          True to display a progress bar (defaults to false)
30144 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
30145 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
30146 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
30147 title             String           The title text
30148 value             String           The string value to set into the active textbox element if displayed
30149 wait              Boolean          True to display a progress bar (defaults to false)
30150 width             Number           The width of the dialog in pixels
30151 </pre>
30152          *
30153          * Example usage:
30154          * <pre><code>
30155 Roo.Msg.show({
30156    title: 'Address',
30157    msg: 'Please enter your address:',
30158    width: 300,
30159    buttons: Roo.MessageBox.OKCANCEL,
30160    multiline: true,
30161    fn: saveAddress,
30162    animEl: 'addAddressBtn'
30163 });
30164 </code></pre>
30165          * @param {Object} config Configuration options
30166          * @return {Roo.MessageBox} This message box
30167          */
30168         show : function(n){
30169             if(this.isVisible()){
30170                 this.hide();
30171             }
30172             var  d = this.getDialog();
30173             B = n;
30174             d.setTitle(B.title || "&#160;");
30175             d.close.setDisplayed(B.closable !== false);
30176             K = G;
30177             B.prompt = B.prompt || (B.multiline ? true : false);
30178             if(B.prompt){
30179                 if(B.multiline){
30180                     G.hide();
30181                     H.show();
30182                     H.setHeight(typeof  B.multiline == "number" ?
30183                         B.multiline : this.defaultTextHeight);
30184                     K = H;
30185                 }else {
30186                     G.show();
30187                     H.hide();
30188                 }
30189             }else {
30190                 G.hide();
30191                 H.hide();
30192             }
30193
30194             I.setDisplayed(B.progress === true);
30195             this.updateProgress(0);
30196             K.dom.value = B.value || "";
30197             if(B.prompt){
30198                 A.setDefaultButton(K);
30199             }else {
30200                 var  bs = B.buttons;
30201                 var  db = null;
30202                 if(bs && bs.ok){
30203                     db = J["ok"];
30204                 }else  if(bs && bs.yes){
30205                     db = J["yes"];
30206                 }
30207
30208                 A.setDefaultButton(db);
30209             }
30210
30211             L = O(B.buttons);
30212             this.updateText(B.msg);
30213             if(B.cls){
30214                 d.el.addClass(B.cls);
30215             }
30216
30217             d.proxyDrag = B.proxyDrag === true;
30218             d.modal = B.modal !== false;
30219             d.mask = B.modal !== false ? C : false;
30220             if(!d.isVisible()){
30221                 // force it to the end of the z-index stack so it gets a cursor in FF
30222                 document.body.appendChild(A.el.dom);
30223                 d.animateTarget = null;
30224                 d.show(n.animEl);
30225             }
30226             return  this;
30227         },
30228
30229         /**
30230          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
30231          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30232          * and closing the message box when the process is complete.
30233          * @param {String} title The title bar text
30234          * @param {String} msg The message box body text
30235          * @return {Roo.MessageBox} This message box
30236          */
30237         progress : function(o, p){
30238             this.show({
30239                 title : o,
30240                 msg : p,
30241                 buttons: false,
30242                 progress:true,
30243                 closable:false,
30244                 minWidth: this.minProgressWidth,
30245                 modal : true
30246             });
30247             return  this;
30248         },
30249
30250         /**
30251          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30252          * If a callback function is passed it will be called after the user clicks the button, and the
30253          * id of the button that was clicked will be passed as the only parameter to the callback
30254          * (could also be the top-right close button).
30255          * @param {String} title The title bar text
30256          * @param {String} msg The message box body text
30257          * @param {Function} fn (optional) The callback function invoked after the message box is closed
30258          * @param {Object} scope (optional) The scope of the callback function
30259          * @return {Roo.MessageBox} This message box
30260          */
30261         alert : function(q, r, fn, s){
30262             this.show({
30263                 title : q,
30264                 msg : r,
30265                 buttons: this.OK,
30266                 fn: fn,
30267                 scope : s,
30268                 modal : true
30269             });
30270             return  this;
30271         },
30272
30273         /**
30274          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
30275          * interaction while waiting for a long-running process to complete that does not have defined intervals.
30276          * You are responsible for closing the message box when the process is complete.
30277          * @param {String} msg The message box body text
30278          * @param {String} title (optional) The title bar text
30279          * @return {Roo.MessageBox} This message box
30280          */
30281         wait : function(t, u){
30282             this.show({
30283                 title : u,
30284                 msg : t,
30285                 buttons: false,
30286                 closable:false,
30287                 progress:true,
30288                 modal:true,
30289                 width:300,
30290                 wait:true
30291             });
30292             D = Roo.TaskMgr.start({
30293                 run: function(i){
30294                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30295                 },
30296                 interval: 1000
30297             });
30298             return  this;
30299         },
30300
30301         /**
30302          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30303          * If a callback function is passed it will be called after the user clicks either button, and the id of the
30304          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30305          * @param {String} title The title bar text
30306          * @param {String} msg The message box body text
30307          * @param {Function} fn (optional) The callback function invoked after the message box is closed
30308          * @param {Object} scope (optional) The scope of the callback function
30309          * @return {Roo.MessageBox} This message box
30310          */
30311         confirm : function(v, x, fn, y){
30312             this.show({
30313                 title : v,
30314                 msg : x,
30315                 buttons: this.YESNO,
30316                 fn: fn,
30317                 scope : y,
30318                 modal : true
30319             });
30320             return  this;
30321         },
30322
30323         /**
30324          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30325          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
30326          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30327          * (could also be the top-right close button) and the text that was entered will be passed as the two
30328          * parameters to the callback.
30329          * @param {String} title The title bar text
30330          * @param {String} msg The message box body text
30331          * @param {Function} fn (optional) The callback function invoked after the message box is closed
30332          * @param {Object} scope (optional) The scope of the callback function
30333          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30334          * property, or the height in pixels to create the textbox (defaults to false / single-line)
30335          * @return {Roo.MessageBox} This message box
30336          */
30337         prompt : function(z, AA, fn, AB, AC){
30338             this.show({
30339                 title : z,
30340                 msg : AA,
30341                 buttons: this.OKCANCEL,
30342                 fn: fn,
30343                 minWidth:250,
30344                 scope : AB,
30345                 prompt:true,
30346                 multiline: AC,
30347                 modal : true
30348             });
30349             return  this;
30350         },
30351
30352         /**
30353          * Button config that displays a single OK button
30354          * @type Object
30355          */
30356         OK : {ok:true},
30357         /**
30358          * Button config that displays Yes and No buttons
30359          * @type Object
30360          */
30361         YESNO : {yes:true, no:true},
30362         /**
30363          * Button config that displays OK and Cancel buttons
30364          * @type Object
30365          */
30366         OKCANCEL : {ok:true, cancel:true},
30367         /**
30368          * Button config that displays Yes, No and Cancel buttons
30369          * @type Object
30370          */
30371         YESNOCANCEL : {yes:true, no:true, cancel:true},
30372
30373         /**
30374          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30375          * @type Number
30376          */
30377         defaultTextHeight : 75,
30378         /**
30379          * The maximum width in pixels of the message box (defaults to 600)
30380          * @type Number
30381          */
30382         maxWidth : 600,
30383         /**
30384          * The minimum width in pixels of the message box (defaults to 100)
30385          * @type Number
30386          */
30387         minWidth : 100,
30388         /**
30389          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
30390          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30391          * @type Number
30392          */
30393         minProgressWidth : 250,
30394         /**
30395          * An object containing the default button text strings that can be overriden for localized language support.
30396          * Supported properties are: ok, cancel, yes and no.
30397          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30398          * @type Object
30399          */
30400         buttonText : {
30401             ok : "OK",
30402             cancel : "Cancel",
30403             yes : "Yes",
30404             no : "No"
30405         }
30406     };
30407 }();
30408
30409 /**
30410  * Shorthand for {@link Roo.MessageBox}
30411  */
30412 Roo.Msg = Roo.MessageBox;
30413 /*
30414  * Based on:
30415  * Ext JS Library 1.1.1
30416  * Copyright(c) 2006-2007, Ext JS, LLC.
30417  *
30418  * Originally Released Under LGPL - original licence link has changed is not relivant.
30419  *
30420  * Fork - LGPL
30421  * <script type="text/javascript">
30422  */
30423 /**
30424  * @class Roo.QuickTips
30425  * Provides attractive and customizable tooltips for any element.
30426  * @singleton
30427  */
30428 Roo.QuickTips = function(){
30429     var  el, A, B, C, tm, D, E, F = {}, esc, removeCls = null, bdLeft, bdRight;
30430     var  ce, bd, xy, dd;
30431     var  G = false, H = true, I = false;
30432     var  J = 1, K = 1, L = 1, M = [];
30433     
30434     var  N = function(e){
30435         if(H){
30436             return;
30437         }
30438         var  t = e.getTarget();
30439         if(!t || t.nodeType !== 1 || t == document || t == document.body){
30440             return;
30441         }
30442         if(ce && t == ce.el){
30443             clearTimeout(K);
30444             return;
30445         }
30446         if(t && F[t.id]){
30447             F[t.id].el = t;
30448             J = S.defer(tm.showDelay, tm, [F[t.id]]);
30449             return;
30450         }
30451         var  W, et = Roo.fly(t);
30452         var  ns = D.namespace;
30453         if(tm.interceptTitles && t.title){
30454             W = t.title;
30455             t.qtip = W;
30456             t.removeAttribute("title");
30457             e.preventDefault();
30458         }else {
30459             W = t.qtip || et.getAttributeNS(ns, D.attribute);
30460         }
30461         if(W){
30462             J = S.defer(tm.showDelay, tm, [{
30463                 el: t, 
30464                 text: W, 
30465                 width: et.getAttributeNS(ns, D.width),
30466                 autoHide: et.getAttributeNS(ns, D.hide) != "user",
30467                 title: et.getAttributeNS(ns, D.title),
30468                     cls: et.getAttributeNS(ns, D.cls)
30469             }]);
30470         }
30471     };
30472     
30473     var  O = function(e){
30474         clearTimeout(J);
30475         var  t = e.getTarget();
30476         if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30477             K = setTimeout(U, tm.hideDelay);
30478         }
30479     };
30480     
30481     var  P = function(e){
30482         if(H){
30483             return;
30484         }
30485
30486         xy = e.getXY();
30487         xy[1] += 18;
30488         if(tm.trackMouse && ce){
30489             el.setXY(xy);
30490         }
30491     };
30492     
30493     var  Q = function(e){
30494         clearTimeout(J);
30495         clearTimeout(K);
30496         if(!e.within(el)){
30497             if(tm.hideOnClick){
30498                 U();
30499                 tm.disable();
30500                 tm.enable.defer(100, tm);
30501             }
30502         }
30503     };
30504     
30505     var  R = function(){
30506         return  2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30507     };
30508
30509     var  S = function(o){
30510         if(H){
30511             return;
30512         }
30513
30514         clearTimeout(L);
30515         ce = o;
30516         if(removeCls){ // in case manually hidden
30517             el.removeClass(removeCls);
30518             removeCls = null;
30519         }
30520         if(ce.cls){
30521             el.addClass(ce.cls);
30522             removeCls = ce.cls;
30523         }
30524         if(ce.title){
30525             C.update(ce.title);
30526             C.show();
30527         }else {
30528             C.update('');
30529             C.hide();
30530         }
30531
30532         el.dom.style.width  = tm.maxWidth+'px';
30533         //tipBody.dom.style.width = '';
30534         B.update(o.text);
30535         var  p = R(), w = ce.width;
30536         if(!w){
30537             var  td = B.dom;
30538             var  aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30539             if(aw > tm.maxWidth){
30540                 w = tm.maxWidth;
30541             }else  if(aw < tm.minWidth){
30542                 w = tm.minWidth;
30543             }else {
30544                 w = aw;
30545             }
30546         }
30547
30548         //tipBody.setWidth(w);
30549         el.setWidth(parseInt(w, 10) + p);
30550         if(ce.autoHide === false){
30551             E.setDisplayed(true);
30552             if(dd){
30553                 dd.unlock();
30554             }
30555         }else {
30556             E.setDisplayed(false);
30557             if(dd){
30558                 dd.lock();
30559             }
30560         }
30561         if(xy){
30562             el.avoidY = xy[1]-18;
30563             el.setXY(xy);
30564         }
30565         if(tm.animate){
30566             el.setOpacity(.1);
30567             el.setStyle("visibility", "visible");
30568             el.fadeIn({callback: T});
30569         }else {
30570             T();
30571         }
30572     };
30573     
30574     var  T = function(){
30575         if(ce){
30576             el.show();
30577             esc.enable();
30578             if(tm.autoDismiss && ce.autoHide !== false){
30579                 L = setTimeout(U, tm.autoDismissDelay);
30580             }
30581         }
30582     };
30583     
30584     var  U = function(W){
30585         clearTimeout(L);
30586         clearTimeout(K);
30587         ce = null;
30588         if(el.isVisible()){
30589             esc.disable();
30590             if(W !== true && tm.animate){
30591                 el.fadeOut({callback: V});
30592             }else {
30593                 V();
30594             } 
30595         }
30596     };
30597     
30598     var  V = function(){
30599         el.hide();
30600         if(removeCls){
30601             el.removeClass(removeCls);
30602             removeCls = null;
30603         }
30604     };
30605     
30606     return  {
30607         /**
30608         * @cfg {Number} minWidth
30609         * The minimum width of the quick tip (defaults to 40)
30610         */
30611        minWidth : 40,
30612         /**
30613         * @cfg {Number} maxWidth
30614         * The maximum width of the quick tip (defaults to 300)
30615         */
30616        maxWidth : 300,
30617         /**
30618         * @cfg {Boolean} interceptTitles
30619         * True to automatically use the element's DOM title value if available (defaults to false)
30620         */
30621        interceptTitles : false,
30622         /**
30623         * @cfg {Boolean} trackMouse
30624         * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30625         */
30626        trackMouse : false,
30627         /**
30628         * @cfg {Boolean} hideOnClick
30629         * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30630         */
30631        hideOnClick : true,
30632         /**
30633         * @cfg {Number} showDelay
30634         * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30635         */
30636        showDelay : 500,
30637         /**
30638         * @cfg {Number} hideDelay
30639         * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30640         */
30641        hideDelay : 200,
30642         /**
30643         * @cfg {Boolean} autoHide
30644         * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30645         * Used in conjunction with hideDelay.
30646         */
30647        autoHide : true,
30648         /**
30649         * @cfg {Boolean}
30650         * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30651         * (defaults to true).  Used in conjunction with autoDismissDelay.
30652         */
30653        autoDismiss : true,
30654         /**
30655         * @cfg {Number}
30656         * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30657         */
30658        autoDismissDelay : 5000,
30659        /**
30660         * @cfg {Boolean} animate
30661         * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30662         */
30663        animate : false,
30664
30665        /**
30666         * @cfg {String} title
30667         * Title text to display (defaults to '').  This can be any valid HTML markup.
30668         */
30669         title: '',
30670        /**
30671         * @cfg {String} text
30672         * Body text to display (defaults to '').  This can be any valid HTML markup.
30673         */
30674         text : '',
30675        /**
30676         * @cfg {String} cls
30677         * A CSS class to apply to the base quick tip element (defaults to '').
30678         */
30679         cls : '',
30680        /**
30681         * @cfg {Number} width
30682         * Width in pixels of the quick tip (defaults to auto).  Width will be ignored if it exceeds the bounds of
30683         * minWidth or maxWidth.
30684         */
30685         width : null,
30686
30687     /**
30688      * Initialize and enable QuickTips for first use.  This should be called once before the first attempt to access
30689      * or display QuickTips in a page.
30690      */
30691        init : function(){
30692           tm = Roo.QuickTips;
30693           D = tm.tagConfig;
30694           if(!I){
30695               if(!Roo.isReady){ // allow calling of init() before onReady
30696                   Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30697                   return;
30698               }
30699
30700               el = new  Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30701               el.fxDefaults = {stopFx: true};
30702               // maximum custom styling
30703               //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
30704               el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');              
30705               C = el.child('h3');
30706               C.enableDisplayMode("block");
30707               A = el.child('div.x-tip-bd');
30708               B = el.child('div.x-tip-bd-inner');
30709               //bdLeft = el.child('div.x-tip-bd-left');
30710               //bdRight = el.child('div.x-tip-bd-right');
30711               E = el.child('div.x-tip-close');
30712               E.enableDisplayMode("block");
30713               E.on("click", U);
30714               var  d = Roo.get(document);
30715               d.on("mousedown", Q);
30716               d.on("mouseover", N);
30717               d.on("mouseout", O);
30718               d.on("mousemove", P);
30719               esc = d.addKeyListener(27, U);
30720               esc.disable();
30721               if(Roo.dd.DD){
30722                   dd = el.initDD("default", null, {
30723                       onDrag : function(){
30724                           el.sync();  
30725                       }
30726                   });
30727                   dd.setHandleElId(C.id);
30728                   dd.lock();
30729               }
30730
30731               I = true;
30732           }
30733
30734           this.enable(); 
30735        },
30736
30737     /**
30738      * Configures a new quick tip instance and assigns it to a target element.  The following config options
30739      * are supported:
30740      * <pre>
30741 Property    Type                   Description
30742 ----------  ---------------------  ------------------------------------------------------------------------
30743 target      Element/String/Array   An Element, id or array of ids that this quick tip should be tied to
30744      * </ul>
30745      * @param {Object} config The config object
30746      */
30747        register : function(X){
30748            var  cs = X  instanceof  Array ? X : arguments;
30749            for(var  i = 0, len = cs.length; i < len; i++) {
30750                var  c = cs[i];
30751                var  target = c.target;
30752                if(target){
30753                    if(target  instanceof  Array){
30754                        for(var  j = 0, jlen = target.length; j < jlen; j++){
30755                            F[target[j]] = c;
30756                        }
30757                    }else {
30758                        F[typeof  target == 'string' ? target : Roo.id(target)] = c;
30759                    }
30760                }
30761            }
30762        },
30763
30764     /**
30765      * Removes this quick tip from its element and destroys it.
30766      * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30767      */
30768        unregister : function(el){
30769            delete  F[Roo.id(el)];
30770        },
30771
30772     /**
30773      * Enable this quick tip.
30774      */
30775        enable : function(){
30776            if(I && H){
30777                M.pop();
30778                if(M.length < 1){
30779                    H = false;
30780                }
30781            }
30782        },
30783
30784     /**
30785      * Disable this quick tip.
30786      */
30787        disable : function(){
30788           H = true;
30789           clearTimeout(J);
30790           clearTimeout(K);
30791           clearTimeout(L);
30792           if(ce){
30793               U(true);
30794           }
30795
30796           M.push(1);
30797        },
30798
30799     /**
30800      * Returns true if the quick tip is enabled, else false.
30801      */
30802        isEnabled : function(){
30803             return  !H;
30804        },
30805
30806         // private
30807        tagConfig : {
30808            namespace : "ext",
30809            attribute : "qtip",
30810            width : "width",
30811            target : "target",
30812            title : "qtitle",
30813            hide : "hide",
30814            cls : "qclass"
30815        }
30816    };
30817 }();
30818
30819 // backwards compat
30820 Roo.QuickTips.tips = Roo.QuickTips.register;
30821 /*
30822  * Based on:
30823  * Ext JS Library 1.1.1
30824  * Copyright(c) 2006-2007, Ext JS, LLC.
30825  *
30826  * Originally Released Under LGPL - original licence link has changed is not relivant.
30827  *
30828  * Fork - LGPL
30829  * <script type="text/javascript">
30830  */
30831  
30832
30833 /**
30834  * @class Roo.tree.TreePanel
30835  * @extends Roo.data.Tree
30836
30837  * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30838  * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30839  * @cfg {Boolean} enableDD true to enable drag and drop
30840  * @cfg {Boolean} enableDrag true to enable just drag
30841  * @cfg {Boolean} enableDrop true to enable just drop
30842  * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30843  * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30844  * @cfg {String} ddGroup The DD group this TreePanel belongs to
30845  * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30846  * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30847  * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30848  * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30849  * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30850  * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30851  * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30852  * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30853  * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30854  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30855  * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30856  * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30857  * 
30858  * @constructor
30859  * @param {String/HTMLElement/Element} el The container element
30860  * @param {Object} config
30861  */
30862 Roo.tree.TreePanel = function(el, A){
30863     var  B = false;
30864     var  C = false;
30865     if (A.root) {
30866         B = A.root;
30867         delete  A.root;
30868     }
30869     if (A.loader) {
30870         C = A.loader;
30871         delete  A.loader;
30872     }
30873
30874     
30875     Roo.apply(this, A);
30876     Roo.tree.TreePanel.superclass.constructor.call(this);
30877     this.el = Roo.get(el);
30878     this.el.addClass('x-tree');
30879     //console.log(root);
30880     if (B) {
30881         this.setRootNode( Roo.factory(B, Roo.tree));
30882     }
30883     if (C) {
30884         this.loader = Roo.factory(C, Roo.tree);
30885     }
30886
30887    /**
30888     * Read-only. The id of the container element becomes this TreePanel's id.
30889     */
30890    this.id = this.el.id;
30891    this.addEvents({
30892         /**
30893         * @event beforeload
30894         * Fires before a node is loaded, return false to cancel
30895         * @param {Node} node The node being loaded
30896         */
30897         "beforeload" : true,
30898         /**
30899         * @event load
30900         * Fires when a node is loaded
30901         * @param {Node} node The node that was loaded
30902         */
30903         "load" : true,
30904         /**
30905         * @event textchange
30906         * Fires when the text for a node is changed
30907         * @param {Node} node The node
30908         * @param {String} text The new text
30909         * @param {String} oldText The old text
30910         */
30911         "textchange" : true,
30912         /**
30913         * @event beforeexpand
30914         * Fires before a node is expanded, return false to cancel.
30915         * @param {Node} node The node
30916         * @param {Boolean} deep
30917         * @param {Boolean} anim
30918         */
30919         "beforeexpand" : true,
30920         /**
30921         * @event beforecollapse
30922         * Fires before a node is collapsed, return false to cancel.
30923         * @param {Node} node The node
30924         * @param {Boolean} deep
30925         * @param {Boolean} anim
30926         */
30927         "beforecollapse" : true,
30928         /**
30929         * @event expand
30930         * Fires when a node is expanded
30931         * @param {Node} node The node
30932         */
30933         "expand" : true,
30934         /**
30935         * @event disabledchange
30936         * Fires when the disabled status of a node changes
30937         * @param {Node} node The node
30938         * @param {Boolean} disabled
30939         */
30940         "disabledchange" : true,
30941         /**
30942         * @event collapse
30943         * Fires when a node is collapsed
30944         * @param {Node} node The node
30945         */
30946         "collapse" : true,
30947         /**
30948         * @event beforeclick
30949         * Fires before click processing on a node. Return false to cancel the default action.
30950         * @param {Node} node The node
30951         * @param {Roo.EventObject} e The event object
30952         */
30953         "beforeclick":true,
30954         /**
30955         * @event checkchange
30956         * Fires when a node with a checkbox's checked property changes
30957         * @param {Node} this This node
30958         * @param {Boolean} checked
30959         */
30960         "checkchange":true,
30961         /**
30962         * @event click
30963         * Fires when a node is clicked
30964         * @param {Node} node The node
30965         * @param {Roo.EventObject} e The event object
30966         */
30967         "click":true,
30968         /**
30969         * @event dblclick
30970         * Fires when a node is double clicked
30971         * @param {Node} node The node
30972         * @param {Roo.EventObject} e The event object
30973         */
30974         "dblclick":true,
30975         /**
30976         * @event contextmenu
30977         * Fires when a node is right clicked
30978         * @param {Node} node The node
30979         * @param {Roo.EventObject} e The event object
30980         */
30981         "contextmenu":true,
30982         /**
30983         * @event beforechildrenrendered
30984         * Fires right before the child nodes for a node are rendered
30985         * @param {Node} node The node
30986         */
30987         "beforechildrenrendered":true,
30988        /**
30989              * @event startdrag
30990              * Fires when a node starts being dragged
30991              * @param {Roo.tree.TreePanel} this
30992              * @param {Roo.tree.TreeNode} node
30993              * @param {event} e The raw browser event
30994              */ 
30995             "startdrag" : true,
30996             /**
30997              * @event enddrag
30998              * Fires when a drag operation is complete
30999              * @param {Roo.tree.TreePanel} this
31000              * @param {Roo.tree.TreeNode} node
31001              * @param {event} e The raw browser event
31002              */
31003             "enddrag" : true,
31004             /**
31005              * @event dragdrop
31006              * Fires when a dragged node is dropped on a valid DD target
31007              * @param {Roo.tree.TreePanel} this
31008              * @param {Roo.tree.TreeNode} node
31009              * @param {DD} dd The dd it was dropped on
31010              * @param {event} e The raw browser event
31011              */
31012             "dragdrop" : true,
31013             /**
31014              * @event beforenodedrop
31015              * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31016              * passed to handlers has the following properties:<br />
31017              * <ul style="padding:5px;padding-left:16px;">
31018              * <li>tree - The TreePanel</li>
31019              * <li>target - The node being targeted for the drop</li>
31020              * <li>data - The drag data from the drag source</li>
31021              * <li>point - The point of the drop - append, above or below</li>
31022              * <li>source - The drag source</li>
31023              * <li>rawEvent - Raw mouse event</li>
31024              * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31025              * to be inserted by setting them on this object.</li>
31026              * <li>cancel - Set this to true to cancel the drop.</li>
31027              * </ul>
31028              * @param {Object} dropEvent
31029              */
31030             "beforenodedrop" : true,
31031             /**
31032              * @event nodedrop
31033              * Fires after a DD object is dropped on a node in this tree. The dropEvent
31034              * passed to handlers has the following properties:<br />
31035              * <ul style="padding:5px;padding-left:16px;">
31036              * <li>tree - The TreePanel</li>
31037              * <li>target - The node being targeted for the drop</li>
31038              * <li>data - The drag data from the drag source</li>
31039              * <li>point - The point of the drop - append, above or below</li>
31040              * <li>source - The drag source</li>
31041              * <li>rawEvent - Raw mouse event</li>
31042              * <li>dropNode - Dropped node(s).</li>
31043              * </ul>
31044              * @param {Object} dropEvent
31045              */
31046             "nodedrop" : true,
31047              /**
31048              * @event nodedragover
31049              * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31050              * passed to handlers has the following properties:<br />
31051              * <ul style="padding:5px;padding-left:16px;">
31052              * <li>tree - The TreePanel</li>
31053              * <li>target - The node being targeted for the drop</li>
31054              * <li>data - The drag data from the drag source</li>
31055              * <li>point - The point of the drop - append, above or below</li>
31056              * <li>source - The drag source</li>
31057              * <li>rawEvent - Raw mouse event</li>
31058              * <li>dropNode - Drop node(s) provided by the source.</li>
31059              * <li>cancel - Set this to true to signal drop not allowed.</li>
31060              * </ul>
31061              * @param {Object} dragOverEvent
31062              */
31063             "nodedragover" : true
31064         
31065    });
31066    if(this.singleExpand){
31067        this.on("beforeexpand", this.restrictExpand, this);
31068    }
31069 };
31070 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31071     rootVisible : true,
31072     animate: Roo.enableFx,
31073     lines : true,
31074     enableDD : false,
31075     hlDrop : Roo.enableFx,
31076   
31077     renderer: false,
31078     
31079     rendererTip: false,
31080     // private
31081     restrictExpand : function(D){
31082         var  p = D.parentNode;
31083         if(p){
31084             if(p.expandedChild && p.expandedChild.parentNode == p){
31085                 p.expandedChild.collapse();
31086             }
31087
31088             p.expandedChild = D;
31089         }
31090     },
31091
31092     // private override
31093     setRootNode : function(E){
31094         Roo.tree.TreePanel.superclass.setRootNode.call(this, E);
31095         if(!this.rootVisible){
31096             E.ui = new  Roo.tree.RootTreeNodeUI(E);
31097         }
31098         return  E;
31099     },
31100
31101     /**
31102      * Returns the container element for this TreePanel
31103      */
31104     getEl : function(){
31105         return  this.el;
31106     },
31107
31108     /**
31109      * Returns the default TreeLoader for this TreePanel
31110      */
31111     getLoader : function(){
31112         return  this.loader;
31113     },
31114
31115     /**
31116      * Expand all nodes
31117      */
31118     expandAll : function(){
31119         this.root.expand(true);
31120     },
31121
31122     /**
31123      * Collapse all nodes
31124      */
31125     collapseAll : function(){
31126         this.root.collapse(true);
31127     },
31128
31129     /**
31130      * Returns the selection model used by this TreePanel
31131      */
31132     getSelectionModel : function(){
31133         if(!this.selModel){
31134             this.selModel = new  Roo.tree.DefaultSelectionModel();
31135         }
31136         return  this.selModel;
31137     },
31138
31139     /**
31140      * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31141      * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31142      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31143      * @return {Array}
31144      */
31145     getChecked : function(a, F){
31146         F = F || this.root;
31147         var  r = [];
31148         var  f = function(){
31149             if(this.attributes.checked){
31150                 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31151             }
31152         }
31153
31154         F.cascade(f);
31155         return  r;
31156     },
31157
31158     /**
31159      * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31160      * @param {String} path
31161      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31162      * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31163      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31164      */
31165     expandPath : function(G, H, I){
31166         H = H || "id";
31167         var  J = G.split(this.pathSeparator);
31168         var  K = this.root;
31169         if(K.attributes[H] != J[1]){ // invalid root
31170             if(I){
31171                 I(false, null);
31172             }
31173             return;
31174         }
31175         var  L = 1;
31176         var  f = function(){
31177             if(++L == J.length){
31178                 if(I){
31179                     I(true, K);
31180                 }
31181                 return;
31182             }
31183             var  c = K.findChild(H, J[L]);
31184             if(!c){
31185                 if(I){
31186                     I(false, K);
31187                 }
31188                 return;
31189             }
31190
31191             K = c;
31192             c.expand(false, false, f);
31193         };
31194         K.expand(false, false, f);
31195     },
31196
31197     /**
31198      * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31199      * @param {String} path
31200      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31201      * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31202      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31203      */
31204     selectPath : function(M, N, O){
31205         N = N || "id";
31206         var  P = M.split(this.pathSeparator);
31207         var  v = P.pop();
31208         if(P.length > 0){
31209             var  f = function(Q, R){
31210                 if(Q && R){
31211                     var  n = R.findChild(N, v);
31212                     if(n){
31213                         n.select();
31214                         if(O){
31215                             O(true, n);
31216                         }
31217                     }else  if(O){
31218                         O(false, n);
31219                     }
31220                 }else {
31221                     if(O){
31222                         O(false, n);
31223                     }
31224                 }
31225             };
31226             this.expandPath(P.join(this.pathSeparator), N, f);
31227         }else {
31228             this.root.select();
31229             if(O){
31230                 O(true, this.root);
31231             }
31232         }
31233     },
31234
31235     getTreeEl : function(){
31236         return  this.el;
31237     },
31238
31239     /**
31240      * Trigger rendering of this TreePanel
31241      */
31242     render : function(){
31243         if (this.innerCt) {
31244             return  this; // stop it rendering more than once!!
31245         }
31246
31247         
31248         this.innerCt = this.el.createChild({tag:"ul",
31249                cls:"x-tree-root-ct " +
31250                (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31251
31252         if(this.containerScroll){
31253             Roo.dd.ScrollManager.register(this.el);
31254         }
31255         if((this.enableDD || this.enableDrop) && !this.dropZone){
31256            /**
31257             * The dropZone used by this tree if drop is enabled
31258             * @type Roo.tree.TreeDropZone
31259             */
31260              this.dropZone = new  Roo.tree.TreeDropZone(this, this.dropConfig || {
31261                ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31262            });
31263         }
31264         if((this.enableDD || this.enableDrag) && !this.dragZone){
31265            /**
31266             * The dragZone used by this tree if drag is enabled
31267             * @type Roo.tree.TreeDragZone
31268             */
31269             this.dragZone = new  Roo.tree.TreeDragZone(this, this.dragConfig || {
31270                ddGroup: this.ddGroup || "TreeDD",
31271                scroll: this.ddScroll
31272            });
31273         }
31274
31275         this.getSelectionModel().init(this);
31276         if (!this.root) {
31277             console.log("ROOT not set in tree");
31278             return;
31279         }
31280
31281         this.root.render();
31282         if(!this.rootVisible){
31283             this.root.renderChildren();
31284         }
31285         return  this;
31286     }
31287 });
31288 /*
31289  * Based on:
31290  * Ext JS Library 1.1.1
31291  * Copyright(c) 2006-2007, Ext JS, LLC.
31292  *
31293  * Originally Released Under LGPL - original licence link has changed is not relivant.
31294  *
31295  * Fork - LGPL
31296  * <script type="text/javascript">
31297  */
31298  
31299
31300 /**
31301  * @class Roo.tree.DefaultSelectionModel
31302  * @extends Roo.util.Observable
31303  * The default single selection for a TreePanel.
31304  */
31305 Roo.tree.DefaultSelectionModel = function(){
31306    this.selNode = null;
31307    
31308    this.addEvents({
31309        /**
31310         * @event selectionchange
31311         * Fires when the selected node changes
31312         * @param {DefaultSelectionModel} this
31313         * @param {TreeNode} node the new selection
31314         */
31315        "selectionchange" : true,
31316
31317        /**
31318         * @event beforeselect
31319         * Fires before the selected node changes, return false to cancel the change
31320         * @param {DefaultSelectionModel} this
31321         * @param {TreeNode} node the new selection
31322         * @param {TreeNode} node the old selection
31323         */
31324        "beforeselect" : true
31325    });
31326 };
31327
31328 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31329     init : function(A){
31330         this.tree = A;
31331         A.getTreeEl().on("keydown", this.onKeyDown, this);
31332         A.on("click", this.onNodeClick, this);
31333     },
31334     
31335     onNodeClick : function(B, e){
31336         if (e.ctrlKey && this.selNode == B)  {
31337             this.unselect(B);
31338             return;
31339         }
31340
31341         this.select(B);
31342     },
31343     
31344     /**
31345      * Select a node.
31346      * @param {TreeNode} node The node to select
31347      * @return {TreeNode} The selected node
31348      */
31349     select : function(C){
31350         var  D = this.selNode;
31351         if(D != C && this.fireEvent('beforeselect', this, C, D) !== false){
31352             if(D){
31353                 D.ui.onSelectedChange(false);
31354             }
31355
31356             this.selNode = C;
31357             C.ui.onSelectedChange(true);
31358             this.fireEvent("selectionchange", this, C, D);
31359         }
31360         return  C;
31361     },
31362     
31363     /**
31364      * Deselect a node.
31365      * @param {TreeNode} node The node to unselect
31366      */
31367     unselect : function(E){
31368         if(this.selNode == E){
31369             this.clearSelections();
31370         }    
31371     },
31372     
31373     /**
31374      * Clear all selections
31375      */
31376     clearSelections : function(){
31377         var  n = this.selNode;
31378         if(n){
31379             n.ui.onSelectedChange(false);
31380             this.selNode = null;
31381             this.fireEvent("selectionchange", this, null);
31382         }
31383         return  n;
31384     },
31385     
31386     /**
31387      * Get the selected node
31388      * @return {TreeNode} The selected node
31389      */
31390     getSelectedNode : function(){
31391         return  this.selNode;    
31392     },
31393     
31394     /**
31395      * Returns true if the node is selected
31396      * @param {TreeNode} node The node to check
31397      * @return {Boolean}
31398      */
31399     isSelected : function(F){
31400         return  this.selNode == F;  
31401     },
31402
31403     /**
31404      * Selects the node above the selected node in the tree, intelligently walking the nodes
31405      * @return TreeNode The new selection
31406      */
31407     selectPrevious : function(){
31408         var  s = this.selNode || this.lastSelNode;
31409         if(!s){
31410             return  null;
31411         }
31412         var  ps = s.previousSibling;
31413         if(ps){
31414             if(!ps.isExpanded() || ps.childNodes.length < 1){
31415                 return  this.select(ps);
31416             } else {
31417                 var  lc = ps.lastChild;
31418                 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31419                     lc = lc.lastChild;
31420                 }
31421                 return  this.select(lc);
31422             }
31423         } else  if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31424             return  this.select(s.parentNode);
31425         }
31426         return  null;
31427     },
31428
31429     /**
31430      * Selects the node above the selected node in the tree, intelligently walking the nodes
31431      * @return TreeNode The new selection
31432      */
31433     selectNext : function(){
31434         var  s = this.selNode || this.lastSelNode;
31435         if(!s){
31436             return  null;
31437         }
31438         if(s.firstChild && s.isExpanded()){
31439              return  this.select(s.firstChild);
31440          }else  if(s.nextSibling){
31441              return  this.select(s.nextSibling);
31442          }else  if(s.parentNode){
31443             var  newS = null;
31444             s.parentNode.bubble(function(){
31445                 if(this.nextSibling){
31446                     newS = this.getOwnerTree().selModel.select(this.nextSibling);
31447                     return  false;
31448                 }
31449             });
31450             return  newS;
31451          }
31452         return  null;
31453     },
31454
31455     onKeyDown : function(e){
31456         var  s = this.selNode || this.lastSelNode;
31457         // undesirable, but required
31458         var  sm = this;
31459         if(!s){
31460             return;
31461         }
31462         var  k = e.getKey();
31463         switch(k){
31464              case  e.DOWN:
31465                  e.stopEvent();
31466                  this.selectNext();
31467              break;
31468              case  e.UP:
31469                  e.stopEvent();
31470                  this.selectPrevious();
31471              break;
31472              case  e.RIGHT:
31473                  e.preventDefault();
31474                  if(s.hasChildNodes()){
31475                      if(!s.isExpanded()){
31476                          s.expand();
31477                      }else  if(s.firstChild){
31478                          this.select(s.firstChild, e);
31479                      }
31480                  }
31481              break;
31482              case  e.LEFT:
31483                  e.preventDefault();
31484                  if(s.hasChildNodes() && s.isExpanded()){
31485                      s.collapse();
31486                  }else  if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31487                      this.select(s.parentNode, e);
31488                  }
31489              break;
31490         };
31491     }
31492 });
31493
31494 /**
31495  * @class Roo.tree.MultiSelectionModel
31496  * @extends Roo.util.Observable
31497  * Multi selection for a TreePanel.
31498  */
31499 Roo.tree.MultiSelectionModel = function(){
31500    this.selNodes = [];
31501    this.selMap = {};
31502    this.addEvents({
31503        /**
31504         * @event selectionchange
31505         * Fires when the selected nodes change
31506         * @param {MultiSelectionModel} this
31507         * @param {Array} nodes Array of the selected nodes
31508         */
31509        "selectionchange" : true
31510    });
31511 };
31512
31513 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31514     init : function(G){
31515         this.tree = G;
31516         G.getTreeEl().on("keydown", this.onKeyDown, this);
31517         G.on("click", this.onNodeClick, this);
31518     },
31519     
31520     onNodeClick : function(H, e){
31521         this.select(H, e, e.ctrlKey);
31522     },
31523     
31524     /**
31525      * Select a node.
31526      * @param {TreeNode} node The node to select
31527      * @param {EventObject} e (optional) An event associated with the selection
31528      * @param {Boolean} keepExisting True to retain existing selections
31529      * @return {TreeNode} The selected node
31530      */
31531     select : function(I, e, J){
31532         if(J !== true){
31533             this.clearSelections(true);
31534         }
31535         if(this.isSelected(I)){
31536             this.lastSelNode = I;
31537             return  I;
31538         }
31539
31540         this.selNodes.push(I);
31541         this.selMap[I.id] = I;
31542         this.lastSelNode = I;
31543         I.ui.onSelectedChange(true);
31544         this.fireEvent("selectionchange", this, this.selNodes);
31545         return  I;
31546     },
31547     
31548     /**
31549      * Deselect a node.
31550      * @param {TreeNode} node The node to unselect
31551      */
31552     unselect : function(K){
31553         if(this.selMap[K.id]){
31554             K.ui.onSelectedChange(false);
31555             var  sn = this.selNodes;
31556             var  index = -1;
31557             if(sn.indexOf){
31558                 index = sn.indexOf(K);
31559             }else {
31560                 for(var  i = 0, len = sn.length; i < len; i++){
31561                     if(sn[i] == K){
31562                         index = i;
31563                         break;
31564                     }
31565                 }
31566             }
31567             if(index != -1){
31568                 this.selNodes.splice(index, 1);
31569             }
31570             delete  this.selMap[K.id];
31571             this.fireEvent("selectionchange", this, this.selNodes);
31572         }
31573     },
31574     
31575     /**
31576      * Clear all selections
31577      */
31578     clearSelections : function(L){
31579         var  sn = this.selNodes;
31580         if(sn.length > 0){
31581             for(var  i = 0, len = sn.length; i < len; i++){
31582                 sn[i].ui.onSelectedChange(false);
31583             }
31584
31585             this.selNodes = [];
31586             this.selMap = {};
31587             if(L !== true){
31588                 this.fireEvent("selectionchange", this, this.selNodes);
31589             }
31590         }
31591     },
31592     
31593     /**
31594      * Returns true if the node is selected
31595      * @param {TreeNode} node The node to check
31596      * @return {Boolean}
31597      */
31598     isSelected : function(M){
31599         return  this.selMap[M.id] ? true : false;  
31600     },
31601     
31602     /**
31603      * Returns an array of the selected nodes
31604      * @return {Array}
31605      */
31606     getSelectedNodes : function(){
31607         return  this.selNodes;    
31608     },
31609
31610     onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31611
31612     selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31613
31614     selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31615 });
31616 /*
31617  * Based on:
31618  * Ext JS Library 1.1.1
31619  * Copyright(c) 2006-2007, Ext JS, LLC.
31620  *
31621  * Originally Released Under LGPL - original licence link has changed is not relivant.
31622  *
31623  * Fork - LGPL
31624  * <script type="text/javascript">
31625  */
31626  
31627 /**
31628  * @class Roo.tree.TreeNode
31629  * @extends Roo.data.Node
31630  * @cfg {String} text The text for this node
31631  * @cfg {Boolean} expanded true to start the node expanded
31632  * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31633  * @cfg {Boolean} allowDrop false if this node cannot be drop on
31634  * @cfg {Boolean} disabled true to start the node disabled
31635  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31636  * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31637  * @cfg {String} cls A css class to be added to the node
31638  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31639  * @cfg {String} href URL of the link used for the node (defaults to #)
31640  * @cfg {String} hrefTarget target frame for the link
31641  * @cfg {String} qtip An Ext QuickTip for the node
31642  * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31643  * @cfg {Boolean} singleClickExpand True for single click expand on this node
31644  * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31645  * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31646  * (defaults to undefined with no checkbox rendered)
31647  * @constructor
31648  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31649  */
31650 Roo.tree.TreeNode = function(A){
31651     A = A || {};
31652     if(typeof  A == "string"){
31653         A = {text: A};
31654     }
31655
31656     this.childrenRendered = false;
31657     this.rendered = false;
31658     Roo.tree.TreeNode.superclass.constructor.call(this, A);
31659     this.expanded = A.expanded === true;
31660     this.isTarget = A.isTarget !== false;
31661     this.draggable = A.draggable !== false && A.allowDrag !== false;
31662     this.allowChildren = A.allowChildren !== false && A.allowDrop !== false;
31663
31664     /**
31665      * Read-only. The text for this node. To change it use setText().
31666      * @type String
31667      */
31668     this.text = A.text;
31669     /**
31670      * True if this node is disabled.
31671      * @type Boolean
31672      */
31673     this.disabled = A.disabled === true;
31674
31675     this.addEvents({
31676         /**
31677         * @event textchange
31678         * Fires when the text for this node is changed
31679         * @param {Node} this This node
31680         * @param {String} text The new text
31681         * @param {String} oldText The old text
31682         */
31683         "textchange" : true,
31684         /**
31685         * @event beforeexpand
31686         * Fires before this node is expanded, return false to cancel.
31687         * @param {Node} this This node
31688         * @param {Boolean} deep
31689         * @param {Boolean} anim
31690         */
31691         "beforeexpand" : true,
31692         /**
31693         * @event beforecollapse
31694         * Fires before this node is collapsed, return false to cancel.
31695         * @param {Node} this This node
31696         * @param {Boolean} deep
31697         * @param {Boolean} anim
31698         */
31699         "beforecollapse" : true,
31700         /**
31701         * @event expand
31702         * Fires when this node is expanded
31703         * @param {Node} this This node
31704         */
31705         "expand" : true,
31706         /**
31707         * @event disabledchange
31708         * Fires when the disabled status of this node changes
31709         * @param {Node} this This node
31710         * @param {Boolean} disabled
31711         */
31712         "disabledchange" : true,
31713         /**
31714         * @event collapse
31715         * Fires when this node is collapsed
31716         * @param {Node} this This node
31717         */
31718         "collapse" : true,
31719         /**
31720         * @event beforeclick
31721         * Fires before click processing. Return false to cancel the default action.
31722         * @param {Node} this This node
31723         * @param {Roo.EventObject} e The event object
31724         */
31725         "beforeclick":true,
31726         /**
31727         * @event checkchange
31728         * Fires when a node with a checkbox's checked property changes
31729         * @param {Node} this This node
31730         * @param {Boolean} checked
31731         */
31732         "checkchange":true,
31733         /**
31734         * @event click
31735         * Fires when this node is clicked
31736         * @param {Node} this This node
31737         * @param {Roo.EventObject} e The event object
31738         */
31739         "click":true,
31740         /**
31741         * @event dblclick
31742         * Fires when this node is double clicked
31743         * @param {Node} this This node
31744         * @param {Roo.EventObject} e The event object
31745         */
31746         "dblclick":true,
31747         /**
31748         * @event contextmenu
31749         * Fires when this node is right clicked
31750         * @param {Node} this This node
31751         * @param {Roo.EventObject} e The event object
31752         */
31753         "contextmenu":true,
31754         /**
31755         * @event beforechildrenrendered
31756         * Fires right before the child nodes for this node are rendered
31757         * @param {Node} this This node
31758         */
31759         "beforechildrenrendered":true
31760     });
31761
31762     var  B = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31763
31764     /**
31765      * Read-only. The UI for this node
31766      * @type TreeNodeUI
31767      */
31768     this.ui = new  B(this);
31769 };
31770 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31771     preventHScroll: true,
31772     /**
31773      * Returns true if this node is expanded
31774      * @return {Boolean}
31775      */
31776     isExpanded : function(){
31777         return  this.expanded;
31778     },
31779
31780     /**
31781      * Returns the UI object for this node
31782      * @return {TreeNodeUI}
31783      */
31784     getUI : function(){
31785         return  this.ui;
31786     },
31787
31788     // private override
31789     setFirstChild : function(C){
31790         var  of = this.firstChild;
31791         Roo.tree.TreeNode.superclass.setFirstChild.call(this, C);
31792         if(this.childrenRendered && of && C != of){
31793             of.renderIndent(true, true);
31794         }
31795         if(this.rendered){
31796             this.renderIndent(true, true);
31797         }
31798     },
31799
31800     // private override
31801     setLastChild : function(D){
31802         var  ol = this.lastChild;
31803         Roo.tree.TreeNode.superclass.setLastChild.call(this, D);
31804         if(this.childrenRendered && ol && D != ol){
31805             ol.renderIndent(true, true);
31806         }
31807         if(this.rendered){
31808             this.renderIndent(true, true);
31809         }
31810     },
31811
31812     // these methods are overridden to provide lazy rendering support
31813     // private override
31814     appendChild : function(){
31815         var  E = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31816         if(E && this.childrenRendered){
31817             E.render();
31818         }
31819
31820         this.ui.updateExpandIcon();
31821         return  E;
31822     },
31823
31824     // private override
31825     removeChild : function(F){
31826         this.ownerTree.getSelectionModel().unselect(F);
31827         Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31828         // if it's been rendered remove dom node
31829         if(this.childrenRendered){
31830             F.ui.remove();
31831         }
31832         if(this.childNodes.length < 1){
31833             this.collapse(false, false);
31834         }else {
31835             this.ui.updateExpandIcon();
31836         }
31837         if(!this.firstChild) {
31838             this.childrenRendered = false;
31839         }
31840         return  F;
31841     },
31842
31843     // private override
31844     insertBefore : function(G, H){
31845         var  I = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31846         if(I && H && this.childrenRendered){
31847             G.render();
31848         }
31849
31850         this.ui.updateExpandIcon();
31851         return  I;
31852     },
31853
31854     /**
31855      * Sets the text for this node
31856      * @param {String} text
31857      */
31858     setText : function(J){
31859         var  K = this.text;
31860         this.text = J;
31861         this.attributes.text = J;
31862         if(this.rendered){ // event without subscribing
31863             this.ui.onTextChange(this, J, K);
31864         }
31865
31866         this.fireEvent("textchange", this, J, K);
31867     },
31868
31869     /**
31870      * Triggers selection of this node
31871      */
31872     select : function(){
31873         this.getOwnerTree().getSelectionModel().select(this);
31874     },
31875
31876     /**
31877      * Triggers deselection of this node
31878      */
31879     unselect : function(){
31880         this.getOwnerTree().getSelectionModel().unselect(this);
31881     },
31882
31883     /**
31884      * Returns true if this node is selected
31885      * @return {Boolean}
31886      */
31887     isSelected : function(){
31888         return  this.getOwnerTree().getSelectionModel().isSelected(this);
31889     },
31890
31891     /**
31892      * Expand this node.
31893      * @param {Boolean} deep (optional) True to expand all children as well
31894      * @param {Boolean} anim (optional) false to cancel the default animation
31895      * @param {Function} callback (optional) A callback to be called when
31896      * expanding this node completes (does not wait for deep expand to complete).
31897      * Called with 1 parameter, this node.
31898      */
31899     expand : function(L, M, N){
31900         if(!this.expanded){
31901             if(this.fireEvent("beforeexpand", this, L, M) === false){
31902                 return;
31903             }
31904             if(!this.childrenRendered){
31905                 this.renderChildren();
31906             }
31907
31908             this.expanded = true;
31909             if(!this.isHiddenRoot() && (this.getOwnerTree().animate && M !== false) || M){
31910                 this.ui.animExpand(function(){
31911                     this.fireEvent("expand", this);
31912                     if(typeof  N == "function"){
31913                         N(this);
31914                     }
31915                     if(L === true){
31916                         this.expandChildNodes(true);
31917                     }
31918                 }.createDelegate(this));
31919                 return;
31920             }else {
31921                 this.ui.expand();
31922                 this.fireEvent("expand", this);
31923                 if(typeof  N == "function"){
31924                     N(this);
31925                 }
31926             }
31927         }else {
31928            if(typeof  N == "function"){
31929                N(this);
31930            }
31931         }
31932         if(L === true){
31933             this.expandChildNodes(true);
31934         }
31935     },
31936
31937     isHiddenRoot : function(){
31938         return  this.isRoot && !this.getOwnerTree().rootVisible;
31939     },
31940
31941     /**
31942      * Collapse this node.
31943      * @param {Boolean} deep (optional) True to collapse all children as well
31944      * @param {Boolean} anim (optional) false to cancel the default animation
31945      */
31946     collapse : function(O, P){
31947         if(this.expanded && !this.isHiddenRoot()){
31948             if(this.fireEvent("beforecollapse", this, O, P) === false){
31949                 return;
31950             }
31951
31952             this.expanded = false;
31953             if((this.getOwnerTree().animate && P !== false) || P){
31954                 this.ui.animCollapse(function(){
31955                     this.fireEvent("collapse", this);
31956                     if(O === true){
31957                         this.collapseChildNodes(true);
31958                     }
31959                 }.createDelegate(this));
31960                 return;
31961             }else {
31962                 this.ui.collapse();
31963                 this.fireEvent("collapse", this);
31964             }
31965         }
31966         if(O === true){
31967             var  cs = this.childNodes;
31968             for(var  i = 0, len = cs.length; i < len; i++) {
31969                 cs[i].collapse(true, false);
31970             }
31971         }
31972     },
31973
31974     // private
31975     delayedExpand : function(Q){
31976         if(!this.expandProcId){
31977             this.expandProcId = this.expand.defer(Q, this);
31978         }
31979     },
31980
31981     // private
31982     cancelExpand : function(){
31983         if(this.expandProcId){
31984             clearTimeout(this.expandProcId);
31985         }
31986
31987         this.expandProcId = false;
31988     },
31989
31990     /**
31991      * Toggles expanded/collapsed state of the node
31992      */
31993     toggle : function(){
31994         if(this.expanded){
31995             this.collapse();
31996         }else {
31997             this.expand();
31998         }
31999     },
32000
32001     /**
32002      * Ensures all parent nodes are expanded
32003      */
32004     ensureVisible : function(R){
32005         var  S = this.getOwnerTree();
32006         S.expandPath(this.parentNode.getPath(), false, function(){
32007             S.getTreeEl().scrollChildIntoView(this.ui.anchor);
32008             Roo.callback(R);
32009         }.createDelegate(this));
32010     },
32011
32012     /**
32013      * Expand all child nodes
32014      * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32015      */
32016     expandChildNodes : function(T){
32017         var  cs = this.childNodes;
32018         for(var  i = 0, len = cs.length; i < len; i++) {
32019                 cs[i].expand(T);
32020         }
32021     },
32022
32023     /**
32024      * Collapse all child nodes
32025      * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32026      */
32027     collapseChildNodes : function(U){
32028         var  cs = this.childNodes;
32029         for(var  i = 0, len = cs.length; i < len; i++) {
32030                 cs[i].collapse(U);
32031         }
32032     },
32033
32034     /**
32035      * Disables this node
32036      */
32037     disable : function(){
32038         this.disabled = true;
32039         this.unselect();
32040         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32041             this.ui.onDisableChange(this, true);
32042         }
32043
32044         this.fireEvent("disabledchange", this, true);
32045     },
32046
32047     /**
32048      * Enables this node
32049      */
32050     enable : function(){
32051         this.disabled = false;
32052         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32053             this.ui.onDisableChange(this, false);
32054         }
32055
32056         this.fireEvent("disabledchange", this, false);
32057     },
32058
32059     // private
32060     renderChildren : function(V){
32061         if(V !== false){
32062             this.fireEvent("beforechildrenrendered", this);
32063         }
32064         var  cs = this.childNodes;
32065         for(var  i = 0, len = cs.length; i < len; i++){
32066             cs[i].render(true);
32067         }
32068
32069         this.childrenRendered = true;
32070     },
32071
32072     // private
32073     sort : function(fn, W){
32074         Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32075         if(this.childrenRendered){
32076             var  cs = this.childNodes;
32077             for(var  i = 0, len = cs.length; i < len; i++){
32078                 cs[i].render(true);
32079             }
32080         }
32081     },
32082
32083     // private
32084     render : function(X){
32085         this.ui.render(X);
32086         if(!this.rendered){
32087             this.rendered = true;
32088             if(this.expanded){
32089                 this.expanded = false;
32090                 this.expand(false, false);
32091             }
32092         }
32093     },
32094
32095     // private
32096     renderIndent : function(Y, Z){
32097         if(Z){
32098             this.ui.childIndent = null;
32099         }
32100
32101         this.ui.renderIndent();
32102         if(Y === true && this.childrenRendered){
32103             var  cs = this.childNodes;
32104             for(var  i = 0, len = cs.length; i < len; i++){
32105                 cs[i].renderIndent(true, Z);
32106             }
32107         }
32108     }
32109 });
32110 /*
32111  * Based on:
32112  * Ext JS Library 1.1.1
32113  * Copyright(c) 2006-2007, Ext JS, LLC.
32114  *
32115  * Originally Released Under LGPL - original licence link has changed is not relivant.
32116  *
32117  * Fork - LGPL
32118  * <script type="text/javascript">
32119  */
32120  
32121 /**
32122  * @class Roo.tree.AsyncTreeNode
32123  * @extends Roo.tree.TreeNode
32124  * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32125  * @constructor
32126  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node 
32127  */
32128  Roo.tree.AsyncTreeNode = function(A){
32129     this.loaded = false;
32130     this.loading = false;
32131     Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32132     /**
32133     * @event beforeload
32134     * Fires before this node is loaded, return false to cancel
32135     * @param {Node} this This node
32136     */
32137     this.addEvents({'beforeload':true, 'load': true});
32138     /**
32139     * @event load
32140     * Fires when this node is loaded
32141     * @param {Node} this This node
32142     */
32143     /**
32144      * The loader used by this node (defaults to using the tree's defined loader)
32145      * @type TreeLoader
32146      * @property loader
32147      */
32148 };
32149 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32150     expand : function(B, C, D){
32151         if(this.loading){ // if an async load is already running, waiting til it's done
32152             var  timer;
32153             var  f = function(){
32154                 if(!this.loading){ // done loading
32155                     clearInterval(timer);
32156                     this.expand(B, C, D);
32157                 }
32158             }.createDelegate(this);
32159             timer = setInterval(f, 200);
32160             return;
32161         }
32162         if(!this.loaded){
32163             if(this.fireEvent("beforeload", this) === false){
32164                 return;
32165             }
32166
32167             this.loading = true;
32168             this.ui.beforeLoad(this);
32169             var  loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32170             if(loader){
32171                 loader.load(this, this.loadComplete.createDelegate(this, [B, C, D]));
32172                 return;
32173             }
32174         }
32175
32176         Roo.tree.AsyncTreeNode.superclass.expand.call(this, B, C, D);
32177     },
32178     
32179     /**
32180      * Returns true if this node is currently loading
32181      * @return {Boolean}
32182      */
32183     isLoading : function(){
32184         return  this.loading;  
32185     },
32186     
32187     loadComplete : function(E, F, G){
32188         this.loading = false;
32189         this.loaded = true;
32190         this.ui.afterLoad(this);
32191         this.fireEvent("load", this);
32192         this.expand(E, F, G);
32193     },
32194     
32195     /**
32196      * Returns true if this node has been loaded
32197      * @return {Boolean}
32198      */
32199     isLoaded : function(){
32200         return  this.loaded;
32201     },
32202     
32203     hasChildNodes : function(){
32204         if(!this.isLeaf() && !this.loaded){
32205             return  true;
32206         }else {
32207             return  Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32208         }
32209     },
32210
32211     /**
32212      * Trigger a reload for this node
32213      * @param {Function} callback
32214      */
32215     reload : function(H){
32216         this.collapse(false, false);
32217         while(this.firstChild){
32218             this.removeChild(this.firstChild);
32219         }
32220
32221         this.childrenRendered = false;
32222         this.loaded = false;
32223         if(this.isHiddenRoot()){
32224             this.expanded = false;
32225         }
32226
32227         this.expand(false, false, H);
32228     }
32229 });
32230 /*
32231  * Based on:
32232  * Ext JS Library 1.1.1
32233  * Copyright(c) 2006-2007, Ext JS, LLC.
32234  *
32235  * Originally Released Under LGPL - original licence link has changed is not relivant.
32236  *
32237  * Fork - LGPL
32238  * <script type="text/javascript">
32239  */
32240  
32241 /**
32242  * @class Roo.tree.TreeNodeUI
32243  * @constructor
32244  * @param {Object} node The node to render
32245  * The TreeNode UI implementation is separate from the
32246  * tree implementation. Unless you are customizing the tree UI,
32247  * you should never have to use this directly.
32248  */
32249 Roo.tree.TreeNodeUI = function(A){
32250     this.node = A;
32251     this.rendered = false;
32252     this.animating = false;
32253     this.emptyIcon = Roo.BLANK_IMAGE_URL;
32254 };
32255
32256 Roo.tree.TreeNodeUI.prototype = {
32257     removeChild : function(B){
32258         if(this.rendered){
32259             this.ctNode.removeChild(B.ui.getEl());
32260         }
32261     },
32262
32263     beforeLoad : function(){
32264          this.addClass("x-tree-node-loading");
32265     },
32266
32267     afterLoad : function(){
32268          this.removeClass("x-tree-node-loading");
32269     },
32270
32271     onTextChange : function(C, D, E){
32272         if(this.rendered){
32273             this.textNode.innerHTML = D;
32274         }
32275     },
32276
32277     onDisableChange : function(F, G){
32278         this.disabled = G;
32279         if(G){
32280             this.addClass("x-tree-node-disabled");
32281         }else {
32282             this.removeClass("x-tree-node-disabled");
32283         }
32284     },
32285
32286     onSelectedChange : function(H){
32287         if(H){
32288             this.focus();
32289             this.addClass("x-tree-selected");
32290         }else {
32291             //this.blur();
32292             this.removeClass("x-tree-selected");
32293         }
32294     },
32295
32296     onMove : function(I, J, K, L, M, N){
32297         this.childIndent = null;
32298         if(this.rendered){
32299             var  targetNode = L.ui.getContainer();
32300             if(!targetNode){//target not rendered
32301                 this.holder = document.createElement("div");
32302                 this.holder.appendChild(this.wrap);
32303                 return;
32304             }
32305             var  insertBefore = N ? N.ui.getEl() : null;
32306             if(insertBefore){
32307                 targetNode.insertBefore(this.wrap, insertBefore);
32308             }else {
32309                 targetNode.appendChild(this.wrap);
32310             }
32311
32312             this.node.renderIndent(true);
32313         }
32314     },
32315
32316     addClass : function(O){
32317         if(this.elNode){
32318             Roo.fly(this.elNode).addClass(O);
32319         }
32320     },
32321
32322     removeClass : function(P){
32323         if(this.elNode){
32324             Roo.fly(this.elNode).removeClass(P);
32325         }
32326     },
32327
32328     remove : function(){
32329         if(this.rendered){
32330             this.holder = document.createElement("div");
32331             this.holder.appendChild(this.wrap);
32332         }
32333     },
32334
32335     fireEvent : function(){
32336         return  this.node.fireEvent.apply(this.node, arguments);
32337     },
32338
32339     initEvents : function(){
32340         this.node.on("move", this.onMove, this);
32341         var  E = Roo.EventManager;
32342         var  a = this.anchor;
32343
32344         var  el = Roo.fly(a, '_treeui');
32345
32346         if(Roo.isOpera){ // opera render bug ignores the CSS
32347             el.setStyle("text-decoration", "none");
32348         }
32349
32350
32351         el.on("click", this.onClick, this);
32352         el.on("dblclick", this.onDblClick, this);
32353
32354         if(this.checkbox){
32355             Roo.EventManager.on(this.checkbox,
32356                     Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32357         }
32358
32359
32360         el.on("contextmenu", this.onContextMenu, this);
32361
32362         var  Q = Roo.fly(this.iconNode);
32363         Q.on("click", this.onClick, this);
32364         Q.on("dblclick", this.onDblClick, this);
32365         Q.on("contextmenu", this.onContextMenu, this);
32366         E.on(this.ecNode, "click", this.ecClick, this, true);
32367
32368         if(this.node.disabled){
32369             this.addClass("x-tree-node-disabled");
32370         }
32371         if(this.node.hidden){
32372             this.addClass("x-tree-node-disabled");
32373         }
32374         var  ot = this.node.getOwnerTree();
32375         var  dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32376         if(dd && (!this.node.isRoot || ot.rootVisible)){
32377             Roo.dd.Registry.register(this.elNode, {
32378                 node: this.node,
32379                 handles: this.getDDHandles(),
32380                 isHandle: false
32381             });
32382         }
32383     },
32384
32385     getDDHandles : function(){
32386         return  [this.iconNode, this.textNode];
32387     },
32388
32389     hide : function(){
32390         if(this.rendered){
32391             this.wrap.style.display = "none";
32392         }
32393     },
32394
32395     show : function(){
32396         if(this.rendered){
32397             this.wrap.style.display = "";
32398         }
32399     },
32400
32401     onContextMenu : function(e){
32402         if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32403             e.preventDefault();
32404             this.focus();
32405             this.fireEvent("contextmenu", this.node, e);
32406         }
32407     },
32408
32409     onClick : function(e){
32410         if(this.dropping){
32411             e.stopEvent();
32412             return;
32413         }
32414         if(this.fireEvent("beforeclick", this.node, e) !== false){
32415             if(!this.disabled && this.node.attributes.href){
32416                 this.fireEvent("click", this.node, e);
32417                 return;
32418             }
32419
32420             e.preventDefault();
32421             if(this.disabled){
32422                 return;
32423             }
32424
32425             if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32426                 this.node.toggle();
32427             }
32428
32429
32430             this.fireEvent("click", this.node, e);
32431         }else {
32432             e.stopEvent();
32433         }
32434     },
32435
32436     onDblClick : function(e){
32437         e.preventDefault();
32438         if(this.disabled){
32439             return;
32440         }
32441         if(this.checkbox){
32442             this.toggleCheck();
32443         }
32444         if(!this.animating && this.node.hasChildNodes()){
32445             this.node.toggle();
32446         }
32447
32448         this.fireEvent("dblclick", this.node, e);
32449     },
32450
32451     onCheckChange : function(){
32452         var  R = this.checkbox.checked;
32453         this.node.attributes.checked = R;
32454         this.fireEvent('checkchange', this.node, R);
32455     },
32456
32457     ecClick : function(e){
32458         if(!this.animating && this.node.hasChildNodes()){
32459             this.node.toggle();
32460         }
32461     },
32462
32463     startDrop : function(){
32464         this.dropping = true;
32465     },
32466
32467     // delayed drop so the click event doesn't get fired on a drop
32468     endDrop : function(){
32469        setTimeout(function(){
32470            this.dropping = false;
32471        }.createDelegate(this), 50);
32472     },
32473
32474     expand : function(){
32475         this.updateExpandIcon();
32476         this.ctNode.style.display = "";
32477     },
32478
32479     focus : function(){
32480         if(!this.node.preventHScroll){
32481             try{this.anchor.focus();
32482             }catch(e){}
32483         }else  if(!Roo.isIE){
32484             try{
32485                 var  noscroll = this.node.getOwnerTree().getTreeEl().dom;
32486                 var  l = noscroll.scrollLeft;
32487                 this.anchor.focus();
32488                 noscroll.scrollLeft = l;
32489             }catch(e){}
32490         }
32491     },
32492
32493     toggleCheck : function(S){
32494         var  cb = this.checkbox;
32495         if(cb){
32496             cb.checked = (S === undefined ? !cb.checked : S);
32497         }
32498     },
32499
32500     blur : function(){
32501         try{
32502             this.anchor.blur();
32503         }catch(e){}
32504     },
32505
32506     animExpand : function(T){
32507         var  ct = Roo.get(this.ctNode);
32508         ct.stopFx();
32509         if(!this.node.hasChildNodes()){
32510             this.updateExpandIcon();
32511             this.ctNode.style.display = "";
32512             Roo.callback(T);
32513             return;
32514         }
32515
32516         this.animating = true;
32517         this.updateExpandIcon();
32518
32519         ct.slideIn('t', {
32520            callback : function(){
32521                this.animating = false;
32522                Roo.callback(T);
32523             },
32524             scope: this,
32525             duration: this.node.ownerTree.duration || .25
32526         });
32527     },
32528
32529     highlight : function(){
32530         var  U = this.node.getOwnerTree();
32531         Roo.fly(this.wrap).highlight(
32532             U.hlColor || "C3DAF9",
32533             {endColor: U.hlBaseColor}
32534         );
32535     },
32536
32537     collapse : function(){
32538         this.updateExpandIcon();
32539         this.ctNode.style.display = "none";
32540     },
32541
32542     animCollapse : function(V){
32543         var  ct = Roo.get(this.ctNode);
32544         ct.enableDisplayMode('block');
32545         ct.stopFx();
32546
32547         this.animating = true;
32548         this.updateExpandIcon();
32549
32550         ct.slideOut('t', {
32551             callback : function(){
32552                this.animating = false;
32553                Roo.callback(V);
32554             },
32555             scope: this,
32556             duration: this.node.ownerTree.duration || .25
32557         });
32558     },
32559
32560     getContainer : function(){
32561         return  this.ctNode;
32562     },
32563
32564     getEl : function(){
32565         return  this.wrap;
32566     },
32567
32568     appendDDGhost : function(W){
32569         W.appendChild(this.elNode.cloneNode(true));
32570     },
32571
32572     getDDRepairXY : function(){
32573         return  Roo.lib.Dom.getXY(this.iconNode);
32574     },
32575
32576     onRender : function(){
32577         this.render();
32578     },
32579
32580     render : function(X){
32581         var  n = this.node, a = n.attributes;
32582         var  Y = n.parentNode ?
32583               n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32584
32585         if(!this.rendered){
32586             this.rendered = true;
32587
32588             this.renderElements(n, a, Y, X);
32589
32590             if(a.qtip){
32591                if(this.textNode.setAttributeNS){
32592                    this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32593                    if(a.qtipTitle){
32594                        this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32595                    }
32596                }else {
32597                    this.textNode.setAttribute("ext:qtip", a.qtip);
32598                    if(a.qtipTitle){
32599                        this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32600                    }
32601                }
32602             }else  if(a.qtipCfg){
32603                 a.qtipCfg.target = Roo.id(this.textNode);
32604                 Roo.QuickTips.register(a.qtipCfg);
32605             }
32606
32607             this.initEvents();
32608             if(!this.node.expanded){
32609                 this.updateExpandIcon();
32610             }
32611         }else {
32612             if(X === true) {
32613                 Y.appendChild(this.wrap);
32614             }
32615         }
32616     },
32617
32618     renderElements : function(n, a, Z, b){
32619         // add some indent caching, this helps performance when rendering a large tree
32620         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32621         var  t = n.getOwnerTree();
32622         var  c = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32623         var  d = t.rendererTip ? t.rendererTip(n.attributes) : c;
32624         var  cb = typeof  a.checked == 'boolean';
32625         var  f = a.href ? a.href : Roo.isGecko ? "" : "#";
32626         var  g = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32627             '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32628             '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32629             '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32630             cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32631             '<a hidefocus="on" href="',f,'" tabIndex="1" ',
32632              a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", 
32633                 '><span unselectable="on" qtip="' , d ,'">',c,"</span></a></div>",
32634             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32635             "</li>"];
32636
32637         if(b !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32638             this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32639                                 n.nextSibling.ui.getEl(), g.join(""));
32640         }else {
32641             this.wrap = Roo.DomHelper.insertHtml("beforeEnd", Z, g.join(""));
32642         }
32643
32644
32645         this.elNode = this.wrap.childNodes[0];
32646         this.ctNode = this.wrap.childNodes[1];
32647         var  cs = this.elNode.childNodes;
32648         this.indentNode = cs[0];
32649         this.ecNode = cs[1];
32650         this.iconNode = cs[2];
32651         var  h = 3;
32652         if(cb){
32653             this.checkbox = cs[3];
32654             h++;
32655         }
32656
32657         this.anchor = cs[h];
32658         this.textNode = cs[h].firstChild;
32659     },
32660
32661     getAnchor : function(){
32662         return  this.anchor;
32663     },
32664
32665     getTextEl : function(){
32666         return  this.textNode;
32667     },
32668
32669     getIconEl : function(){
32670         return  this.iconNode;
32671     },
32672
32673     isChecked : function(){
32674         return  this.checkbox ? this.checkbox.checked : false;
32675     },
32676
32677     updateExpandIcon : function(){
32678         if(this.rendered){
32679             var  n = this.node, c1, c2;
32680             var  P = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32681             var  hasChild = n.hasChildNodes();
32682             if(hasChild){
32683                 if(n.expanded){
32684                     P += "-minus";
32685                     c1 = "x-tree-node-collapsed";
32686                     c2 = "x-tree-node-expanded";
32687                 }else {
32688                     P += "-plus";
32689                     c1 = "x-tree-node-expanded";
32690                     c2 = "x-tree-node-collapsed";
32691                 }
32692                 if(this.wasLeaf){
32693                     this.removeClass("x-tree-node-leaf");
32694                     this.wasLeaf = false;
32695                 }
32696                 if(this.c1 != c1 || this.c2 != c2){
32697                     Roo.fly(this.elNode).replaceClass(c1, c2);
32698                     this.c1 = c1; this.c2 = c2;
32699                 }
32700             }else {
32701                 if(!this.wasLeaf){
32702                     Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32703                     delete  this.c1;
32704                     delete  this.c2;
32705                     this.wasLeaf = true;
32706                 }
32707             }
32708             var  ecc = "x-tree-ec-icon "+P;
32709             if(this.ecc != ecc){
32710                 this.ecNode.className = ecc;
32711                 this.ecc = ecc;
32712             }
32713         }
32714     },
32715
32716     getChildIndent : function(){
32717         if(!this.childIndent){
32718             var  g = [];
32719             var  p = this.node;
32720             while(p){
32721                 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32722                     if(!p.isLast()) {
32723                         g.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32724                     } else  {
32725                         g.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32726                     }
32727                 }
32728
32729                 p = p.parentNode;
32730             }
32731
32732             this.childIndent = g.join("");
32733         }
32734         return  this.childIndent;
32735     },
32736
32737     renderIndent : function(){
32738         if(this.rendered){
32739             var  indent = "";
32740             var  p = this.node.parentNode;
32741             if(p){
32742                 indent = p.ui.getChildIndent();
32743             }
32744             if(this.indentMarkup != indent){ // don't rerender if not required
32745                 this.indentNode.innerHTML = indent;
32746                 this.indentMarkup = indent;
32747             }
32748
32749             this.updateExpandIcon();
32750         }
32751     }
32752 };
32753
32754 Roo.tree.RootTreeNodeUI = function(){
32755     Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32756 };
32757 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32758     render : function(){
32759         if(!this.rendered){
32760             var  Z = this.node.ownerTree.innerCt.dom;
32761             this.node.expanded = true;
32762             Z.innerHTML = '<div class="x-tree-root-node"></div>';
32763             this.wrap = this.ctNode = Z.firstChild;
32764         }
32765     },
32766     collapse : function(){
32767     },
32768     expand : function(){
32769     }
32770 });
32771 /*
32772  * Based on:
32773  * Ext JS Library 1.1.1
32774  * Copyright(c) 2006-2007, Ext JS, LLC.
32775  *
32776  * Originally Released Under LGPL - original licence link has changed is not relivant.
32777  *
32778  * Fork - LGPL
32779  * <script type="text/javascript">
32780  */
32781 /**
32782  * @class Roo.tree.TreeLoader
32783  * @extends Roo.util.Observable
32784  * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32785  * nodes from a specified URL. The response must be a javascript Array definition
32786  * who's elements are node definition objects. eg:
32787  * <pre><code>
32788    [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32789     { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32790 </code></pre>
32791  * <br><br>
32792  * A server request is sent, and child nodes are loaded only when a node is expanded.
32793  * The loading node's id is passed to the server under the parameter name "node" to
32794  * enable the server to produce the correct child nodes.
32795  * <br><br>
32796  * To pass extra parameters, an event handler may be attached to the "beforeload"
32797  * event, and the parameters specified in the TreeLoader's baseParams property:
32798  * <pre><code>
32799     myTreeLoader.on("beforeload", function(treeLoader, node) {
32800         this.baseParams.category = node.attributes.category;
32801     }, this);
32802 </code></pre><
32803  * This would pass an HTTP parameter called "category" to the server containing
32804  * the value of the Node's "category" attribute.
32805  * @constructor
32806  * Creates a new Treeloader.
32807  * @param {Object} config A config object containing config properties.
32808  */
32809 Roo.tree.TreeLoader = function(A){
32810     this.baseParams = {};
32811     this.requestMethod = "POST";
32812     Roo.apply(this, A);
32813
32814     this.addEvents({
32815         /**
32816          * @event beforeload
32817          * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32818          * @param {Object} This TreeLoader object.
32819          * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32820          * @param {Object} callback The callback function specified in the {@link #load} call.
32821          */
32822         "beforeload" : true,
32823         /**
32824          * @event load
32825          * Fires when the node has been successfuly loaded.
32826          * @param {Object} This TreeLoader object.
32827          * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32828          * @param {Object} response The response object containing the data from the server.
32829          */
32830         "load" : true,
32831         /**
32832          * @event loadexception
32833          * Fires if the network request failed.
32834          * @param {Object} This TreeLoader object.
32835          * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32836          * @param {Object} response The response object containing the data from the server.
32837          */
32838         "loadexception" : true,
32839           /**
32840          * @event create
32841          * Fires before a node is created, enabling you to return custom Node types 
32842          * @param {Object} This TreeLoader object.
32843          * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32844          */
32845         "create" : true
32846     });
32847
32848     Roo.tree.TreeLoader.superclass.constructor.call(this);
32849 };
32850
32851 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32852     /**
32853     * @cfg {String} dataUrl The URL from which to request a Json string which
32854     * specifies an array of node definition object representing the child nodes
32855     * to be loaded.
32856     */
32857     /**
32858     * @cfg {Object} baseParams (optional) An object containing properties which
32859     * specify HTTP parameters to be passed to each request for child nodes.
32860     */
32861     /**
32862     * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32863     * created by this loader. If the attributes sent by the server have an attribute in this object,
32864     * they take priority.
32865     */
32866     /**
32867     * @cfg {Object} uiProviders (optional) An object containing properties which
32868     * 
32869     * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32870     * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32871     * <i>uiProvider</i> attribute of a returned child node is a string rather
32872     * than a reference to a TreeNodeUI implementation, this that string value
32873     * is used as a property name in the uiProviders object. You can define the provider named
32874     * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32875     */
32876     uiProviders : {},
32877
32878     /**
32879     * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32880     * child nodes before loading.
32881     */
32882     clearOnLoad : true,
32883
32884     /**
32885     * @cfg {String} root (optional) Default to false. Use this to read data from an object 
32886     * property on loading, rather than expecting an array. (eg. more compatible to a standard
32887     * Grid query { data : [ .....] }
32888     */
32889     
32890     root : false,
32891      /**
32892     * @cfg {String} queryParam (optional) 
32893     * Name of the query as it will be passed on the querystring (defaults to 'node')
32894     * eg. the request will be ?node=[id]
32895     */
32896     
32897     
32898     queryParam: false,
32899     
32900     /**
32901      * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32902      * This is called automatically when a node is expanded, but may be used to reload
32903      * a node (or append new children if the {@link #clearOnLoad} option is false.)
32904      * @param {Roo.tree.TreeNode} node
32905      * @param {Function} callback
32906      */
32907     load : function(B, C){
32908         if(this.clearOnLoad){
32909             while(B.firstChild){
32910                 B.removeChild(B.firstChild);
32911             }
32912         }
32913         if(B.attributes.children){ // preloaded json children
32914             var  cs = B.attributes.children;
32915             for(var  i = 0, len = cs.length; i < len; i++){
32916                 B.appendChild(this.createNode(cs[i]));
32917             }
32918             if(typeof  C == "function"){
32919                 C();
32920             }
32921         }else  if(this.dataUrl){
32922             this.requestData(B, C);
32923         }
32924     },
32925
32926     getParams: function(D){
32927         var  E = [], bp = this.baseParams;
32928         for(var  key  in  bp){
32929             if(typeof  bp[key] != "function"){
32930                 E.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32931             }
32932         }
32933         var  n = this.queryParam === false ? 'node' : this.queryParam;
32934         E.push(n + "=", encodeURIComponent(D.id));
32935         return  E.join("");
32936     },
32937
32938     requestData : function(F, G){
32939         if(this.fireEvent("beforeload", this, F, G) !== false){
32940             this.transId = Roo.Ajax.request({
32941                 method:this.requestMethod,
32942                 url: this.dataUrl||this.url,
32943                 success: this.handleResponse,
32944                 failure: this.handleFailure,
32945                 scope: this,
32946                 argument: {callback: G, node: F},
32947                 params: this.getParams(F)
32948             });
32949         }else {
32950             // if the load is cancelled, make sure we notify
32951             // the node that we are done
32952             if(typeof  G == "function"){
32953                 G();
32954             }
32955         }
32956     },
32957
32958     isLoading : function(){
32959         return  this.transId ? true : false;
32960     },
32961
32962     abort : function(){
32963         if(this.isLoading()){
32964             Roo.Ajax.abort(this.transId);
32965         }
32966     },
32967
32968     /**
32969     * Override this function for custom TreeNode node implementation
32970     */
32971     createNode : function(H){
32972         // apply baseAttrs, nice idea Corey!
32973         if(this.baseAttrs){
32974             Roo.applyIf(H, this.baseAttrs);
32975         }
32976         if(this.applyLoader !== false){
32977             H.loader = this;
32978         }
32979         // uiProvider = depreciated..
32980         
32981         if(typeof(H.uiProvider) == 'string'){
32982            H.uiProvider = this.uiProviders[H.uiProvider] || 
32983                 /**  eval:var:attr */ eval(H.uiProvider);
32984         }
32985         if(typeof(this.uiProviders['default']) != 'undefined') {
32986             H.uiProvider = this.uiProviders['default'];
32987         }
32988
32989         
32990         this.fireEvent('create', this, H);
32991         
32992         H.leaf  = typeof(H.leaf) == 'string' ? H.leaf * 1 : H.leaf;
32993         return (H.leaf ?
32994                         new  Roo.tree.TreeNode(H) :
32995                         new  Roo.tree.AsyncTreeNode(H));
32996     },
32997
32998     processResponse : function(I, J, K){
32999         var  L = I.responseText;
33000         try {
33001             
33002             var  o = /**  eval:var:zzzzzzzzzz */ eval("("+L+")");
33003             if (this.root !== false) {
33004                 o = o[this.root];
33005             }
33006             
33007             for(var  i = 0, len = o.length; i < len; i++){
33008                 var  n = this.createNode(o[i]);
33009                 if(n){
33010                     J.appendChild(n);
33011                 }
33012             }
33013             if(typeof  K == "function"){
33014                 K(this, J);
33015             }
33016         }catch(e){
33017             this.handleFailure(response);
33018         }
33019     },
33020
33021     handleResponse : function(M){
33022         this.transId = false;
33023         var  a = M.argument;
33024         this.processResponse(M, a.node, a.callback);
33025         this.fireEvent("load", this, a.node, M);
33026     },
33027
33028     handleFailure : function(N){
33029         this.transId = false;
33030         var  a = N.argument;
33031         this.fireEvent("loadexception", this, a.node, N);
33032         if(typeof  a.callback == "function"){
33033             a.callback(this, a.node);
33034         }
33035     }
33036 });
33037 /*
33038  * Based on:
33039  * Ext JS Library 1.1.1
33040  * Copyright(c) 2006-2007, Ext JS, LLC.
33041  *
33042  * Originally Released Under LGPL - original licence link has changed is not relivant.
33043  *
33044  * Fork - LGPL
33045  * <script type="text/javascript">
33046  */
33047
33048 /**
33049 * @class Roo.tree.TreeFilter
33050 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33051 * @param {TreePanel} tree
33052 * @param {Object} config (optional)
33053  */
33054 Roo.tree.TreeFilter = function(A, B){
33055     this.tree = A;
33056     this.filtered = {};
33057     Roo.apply(this, B);
33058 };
33059
33060 Roo.tree.TreeFilter.prototype = {
33061     clearBlank:false,
33062     reverse:false,
33063     autoClear:false,
33064     remove:false,
33065
33066      /**
33067      * Filter the data by a specific attribute.
33068      * @param {String/RegExp} value Either string that the attribute value
33069      * should start with or a RegExp to test against the attribute
33070      * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33071      * @param {TreeNode} startNode (optional) The node to start the filter at.
33072      */
33073     filter : function(C, D, E){
33074         D = D || "text";
33075         var  f;
33076         if(typeof  C == "string"){
33077             var  vlen = C.length;
33078             // auto clear empty filter
33079             if(vlen == 0 && this.clearBlank){
33080                 this.clear();
33081                 return;
33082             }
33083
33084             C = C.toLowerCase();
33085             f = function(n){
33086                 return  n.attributes[D].substr(0, vlen).toLowerCase() == C;
33087             };
33088         }else  if(C.exec){ // regex?
33089             f = function(n){
33090                 return  C.test(n.attributes[D]);
33091             };
33092         }else {
33093             throw  'Illegal filter type, must be string or regex';
33094         }
33095
33096         this.filterBy(f, null, E);
33097         },
33098
33099     /**
33100      * Filter by a function. The passed function will be called with each
33101      * node in the tree (or from the startNode). If the function returns true, the node is kept
33102      * otherwise it is filtered. If a node is filtered, its children are also filtered.
33103      * @param {Function} fn The filter function
33104      * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33105      */
33106     filterBy : function(fn, F, G){
33107         G = G || this.tree.root;
33108         if(this.autoClear){
33109             this.clear();
33110         }
33111         var  af = this.filtered, rv = this.reverse;
33112         var  f = function(n){
33113             if(n == G){
33114                 return  true;
33115             }
33116             if(af[n.id]){
33117                 return  false;
33118             }
33119             var  m = fn.call(F || n, n);
33120             if(!m || rv){
33121                 af[n.id] = n;
33122                 n.ui.hide();
33123                 return  false;
33124             }
33125             return  true;
33126         };
33127         G.cascade(f);
33128         if(this.remove){
33129            for(var  id  in  af){
33130                if(typeof  id != "function"){
33131                    var  n = af[id];
33132                    if(n && n.parentNode){
33133                        n.parentNode.removeChild(n);
33134                    }
33135                }
33136            }
33137         }
33138     },
33139
33140     /**
33141      * Clears the current filter. Note: with the "remove" option
33142      * set a filter cannot be cleared.
33143      */
33144     clear : function(){
33145         var  t = this.tree;
33146         var  af = this.filtered;
33147         for(var  id  in  af){
33148             if(typeof  id != "function"){
33149                 var  n = af[id];
33150                 if(n){
33151                     n.ui.show();
33152                 }
33153             }
33154         }
33155
33156         this.filtered = {};
33157     }
33158 };
33159
33160 /*
33161  * Based on:
33162  * Ext JS Library 1.1.1
33163  * Copyright(c) 2006-2007, Ext JS, LLC.
33164  *
33165  * Originally Released Under LGPL - original licence link has changed is not relivant.
33166  *
33167  * Fork - LGPL
33168  * <script type="text/javascript">
33169  */
33170  
33171
33172 /**
33173  * @class Roo.tree.TreeSorter
33174  * Provides sorting of nodes in a TreePanel
33175  * 
33176  * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33177  * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33178  * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33179  * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33180  * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33181  * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33182  * @constructor
33183  * @param {TreePanel} tree
33184  * @param {Object} config
33185  */
33186 Roo.tree.TreeSorter = function(A, B){
33187     Roo.apply(this, B);
33188     A.on("beforechildrenrendered", this.doSort, this);
33189     A.on("append", this.updateSort, this);
33190     A.on("insert", this.updateSort, this);
33191     
33192     var  C = this.dir && this.dir.toLowerCase() == "desc";
33193     var  p = this.property || "text";
33194     var  D = this.sortType;
33195     var  fs = this.folderSort;
33196     var  cs = this.caseSensitive === true;
33197     var  E = this.leafAttr || 'leaf';
33198
33199     this.sortFn = function(n1, n2){
33200         if(fs){
33201             if(n1.attributes[E] && !n2.attributes[E]){
33202                 return  1;
33203             }
33204             if(!n1.attributes[E] && n2.attributes[E]){
33205                 return  -1;
33206             }
33207         }
33208         var  v1 = D ? D(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33209         var  v2 = D ? D(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33210         if(v1 < v2){
33211                         return  C ? +1 : -1;
33212                 }else  if(v1 > v2){
33213                         return  C ? -1 : +1;
33214         }else {
33215                 return  0;
33216         }
33217     };
33218 };
33219
33220 Roo.tree.TreeSorter.prototype = {
33221     doSort : function(F){
33222         F.sort(this.sortFn);
33223     },
33224     
33225     compareNodes : function(n1, n2){
33226         return  (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33227     },
33228     
33229     updateSort : function(G, H){
33230         if(H.childrenRendered){
33231             this.doSort.defer(1, this, [H]);
33232         }
33233     }
33234 };
33235 /*
33236  * Based on:
33237  * Ext JS Library 1.1.1
33238  * Copyright(c) 2006-2007, Ext JS, LLC.
33239  *
33240  * Originally Released Under LGPL - original licence link has changed is not relivant.
33241  *
33242  * Fork - LGPL
33243  * <script type="text/javascript">
33244  */
33245
33246 if(Roo.dd.DropZone){
33247     
33248 Roo.tree.TreeDropZone = function(A, B){
33249     this.allowParentInsert = false;
33250     this.allowContainerDrop = false;
33251     this.appendOnly = false;
33252     Roo.tree.TreeDropZone.superclass.constructor.call(this, A.innerCt, B);
33253     this.tree = A;
33254     this.lastInsertClass = "x-tree-no-status";
33255     this.dragOverData = {};
33256 };
33257
33258 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33259     ddGroup : "TreeDD",
33260     
33261     expandDelay : 1000,
33262     
33263     expandNode : function(C){
33264         if(C.hasChildNodes() && !C.isExpanded()){
33265             C.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33266         }
33267     },
33268     
33269     queueExpand : function(D){
33270         this.expandProcId = this.expandNode.defer(this.expandDelay, this, [D]);
33271     },
33272     
33273     cancelExpand : function(){
33274         if(this.expandProcId){
33275             clearTimeout(this.expandProcId);
33276             this.expandProcId = false;
33277         }
33278     },
33279     
33280     isValidDropPoint : function(n, pt, dd, e, E){
33281         if(!n || !E){ return  false; }
33282         var  F = n.node;
33283         var  G = E.node;
33284         // default drop rules
33285         if(!(F && F.isTarget && pt)){
33286             return  false;
33287         }
33288         if(pt == "append" && F.allowChildren === false){
33289             return  false;
33290         }
33291         if((pt == "above" || pt == "below") && (F.parentNode && F.parentNode.allowChildren === false)){
33292             return  false;
33293         }
33294         if(G && (F == G || G.contains(F))){
33295             return  false;
33296         }
33297         // reuse the object
33298         var  H = this.dragOverData;
33299         H.tree = this.tree;
33300         H.target = F;
33301         H.data = E;
33302         H.point = pt;
33303         H.source = dd;
33304         H.rawEvent = e;
33305         H.dropNode = G;
33306         H.cancel = false;  
33307         var  I = this.tree.fireEvent("nodedragover", H);
33308         return  H.cancel === false && I !== false;
33309     },
33310     
33311     getDropPoint : function(e, n, dd){
33312         var  tn = n.node;
33313         if(tn.isRoot){
33314             return  tn.allowChildren !== false ? "append" : false; // always append for root
33315         }
33316         var  J = n.ddel;
33317         var  t = Roo.lib.Dom.getY(J), b = t + J.offsetHeight;
33318         var  y = Roo.lib.Event.getPageY(e);
33319         var  K = tn.allowChildren === false || tn.isLeaf();
33320         if(this.appendOnly || tn.parentNode.allowChildren === false){
33321             return  K ? false : "append";
33322         }
33323         var  L = false;
33324         if(!this.allowParentInsert){
33325             L = tn.hasChildNodes() && tn.isExpanded();
33326         }
33327         var  q = (b - t) / (K ? 2 : 3);
33328         if(y >= t && y < (t + q)){
33329             return  "above";
33330         }else  if(!L && (K || y >= b-q && y <= b)){
33331             return  "below";
33332         }else {
33333             return  "append";
33334         }
33335     },
33336     
33337     onNodeEnter : function(n, dd, e, M){
33338         this.cancelExpand();
33339     },
33340     
33341     onNodeOver : function(n, dd, e, N){
33342         var  pt = this.getDropPoint(e, n, dd);
33343         var  O = n.node;
33344         
33345         // auto node expand check
33346         if(!this.expandProcId && pt == "append" && O.hasChildNodes() && !n.node.isExpanded()){
33347             this.queueExpand(O);
33348         }else  if(pt != "append"){
33349             this.cancelExpand();
33350         }
33351         
33352         // set the insert point style on the target node
33353         var  P = this.dropNotAllowed;
33354         if(this.isValidDropPoint(n, pt, dd, e, N)){
33355            if(pt){
33356                var  el = n.ddel;
33357                var  cls;
33358                if(pt == "above"){
33359                    P = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33360                    cls = "x-tree-drag-insert-above";
33361                }else  if(pt == "below"){
33362                    P = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33363                    cls = "x-tree-drag-insert-below";
33364                }else {
33365                    P = "x-tree-drop-ok-append";
33366                    cls = "x-tree-drag-append";
33367                }
33368                if(this.lastInsertClass != cls){
33369                    Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33370                    this.lastInsertClass = cls;
33371                }
33372            }
33373        }
33374        return  P;
33375     },
33376     
33377     onNodeOut : function(n, dd, e, Q){
33378         this.cancelExpand();
33379         this.removeDropIndicators(n);
33380     },
33381     
33382     onNodeDrop : function(n, dd, e, R){
33383         var  S = this.getDropPoint(e, n, dd);
33384         var  T = n.node;
33385         T.ui.startDrop();
33386         if(!this.isValidDropPoint(n, S, dd, e, R)){
33387             T.ui.endDrop();
33388             return  false;
33389         }
33390         // first try to find the drop node
33391         var  U = R.node || (dd.getTreeNode ? dd.getTreeNode(R, T, S, e) : null);
33392         var  V = {
33393             tree : this.tree,
33394             target: T,
33395             data: R,
33396             point: S,
33397             source: dd,
33398             rawEvent: e,
33399             dropNode: U,
33400             cancel: !U   
33401         };
33402         var  W = this.tree.fireEvent("beforenodedrop", V);
33403         if(W === false || V.cancel === true || !V.dropNode){
33404             T.ui.endDrop();
33405             return  false;
33406         }
33407
33408         // allow target changing
33409         T = V.target;
33410         if(S == "append" && !T.isExpanded()){
33411             T.expand(false, null, function(){
33412                 this.completeDrop(V);
33413             }.createDelegate(this));
33414         }else {
33415             this.completeDrop(V);
33416         }
33417         return  true;
33418     },
33419     
33420     completeDrop : function(de){
33421         var  ns = de.dropNode, p = de.point, t = de.target;
33422         if(!(ns  instanceof  Array)){
33423             ns = [ns];
33424         }
33425         var  n;
33426         for(var  i = 0, len = ns.length; i < len; i++){
33427             n = ns[i];
33428             if(p == "above"){
33429                 t.parentNode.insertBefore(n, t);
33430             }else  if(p == "below"){
33431                 t.parentNode.insertBefore(n, t.nextSibling);
33432             }else {
33433                 t.appendChild(n);
33434             }
33435         }
33436
33437         n.ui.focus();
33438         if(this.tree.hlDrop){
33439             n.ui.highlight();
33440         }
33441
33442         t.ui.endDrop();
33443         this.tree.fireEvent("nodedrop", de);
33444     },
33445     
33446     afterNodeMoved : function(dd, X, e, Y, Z){
33447         if(this.tree.hlDrop){
33448             Z.ui.focus();
33449             Z.ui.highlight();
33450         }
33451
33452         this.tree.fireEvent("nodedrop", this.tree, Y, X, dd, e);
33453     },
33454     
33455     getTree : function(){
33456         return  this.tree;
33457     },
33458     
33459     removeDropIndicators : function(n){
33460         if(n && n.ddel){
33461             var  el = n.ddel;
33462             Roo.fly(el).removeClass([
33463                     "x-tree-drag-insert-above",
33464                     "x-tree-drag-insert-below",
33465                     "x-tree-drag-append"]);
33466             this.lastInsertClass = "_noclass";
33467         }
33468     },
33469     
33470     beforeDragDrop : function(a, e, id){
33471         this.cancelExpand();
33472         return  true;
33473     },
33474     
33475     afterRepair : function(c){
33476         if(c && Roo.enableFx){
33477             c.node.ui.highlight();
33478         }
33479
33480         this.hideProxy();
33481     }    
33482 });
33483
33484 }
33485 /*
33486  * Based on:
33487  * Ext JS Library 1.1.1
33488  * Copyright(c) 2006-2007, Ext JS, LLC.
33489  *
33490  * Originally Released Under LGPL - original licence link has changed is not relivant.
33491  *
33492  * Fork - LGPL
33493  * <script type="text/javascript">
33494  */
33495  
33496
33497 if(Roo.dd.DragZone){
33498 Roo.tree.TreeDragZone = function(A, B){
33499     Roo.tree.TreeDragZone.superclass.constructor.call(this, A.getTreeEl(), B);
33500     this.tree = A;
33501 };
33502
33503 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33504     ddGroup : "TreeDD",
33505     
33506     onBeforeDrag : function(C, e){
33507         var  n = C.node;
33508         return  n && n.draggable && !n.disabled;
33509     },
33510     
33511     onInitDrag : function(e){
33512         var  D = this.dragData;
33513         this.tree.getSelectionModel().select(D.node);
33514         this.proxy.update("");
33515         D.node.ui.appendDDGhost(this.proxy.ghost.dom);
33516         this.tree.fireEvent("startdrag", this.tree, D.node, e);
33517     },
33518     
33519     getRepairXY : function(e, E){
33520         return  E.node.ui.getDDRepairXY();
33521     },
33522     
33523     onEndDrag : function(F, e){
33524         this.tree.fireEvent("enddrag", this.tree, F.node, e);
33525     },
33526     
33527     onValidDrop : function(dd, e, id){
33528         this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33529         this.hideProxy();
33530     },
33531     
33532     beforeInvalidDrop : function(e, id){
33533         // this scrolls the original position back into view
33534         var  sm = this.tree.getSelectionModel();
33535         sm.clearSelections();
33536         sm.select(this.dragData.node);
33537     }
33538 });
33539 }
33540 /*
33541  * Based on:
33542  * Ext JS Library 1.1.1
33543  * Copyright(c) 2006-2007, Ext JS, LLC.
33544  *
33545  * Originally Released Under LGPL - original licence link has changed is not relivant.
33546  *
33547  * Fork - LGPL
33548  * <script type="text/javascript">
33549  */
33550 /**
33551  * @class Roo.tree.TreeEditor
33552  * @extends Roo.Editor
33553  * Provides editor functionality for inline tree node editing.  Any valid {@link Roo.form.Field} can be used
33554  * as the editor field.
33555  * @constructor
33556  * @param {TreePanel} tree
33557  * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33558  */
33559 Roo.tree.TreeEditor = function(A, B){
33560     B = B || {};
33561     var  C = B.events ? B : new  Roo.form.TextField(B);
33562     Roo.tree.TreeEditor.superclass.constructor.call(this, C);
33563
33564     this.tree = A;
33565
33566     A.on('beforeclick', this.beforeNodeClick, this);
33567     A.getTreeEl().on('mousedown', this.hide, this);
33568     this.on('complete', this.updateNode, this);
33569     this.on('beforestartedit', this.fitToTree, this);
33570     this.on('startedit', this.bindScroll, this, {delay:10});
33571     this.on('specialkey', this.onSpecialKey, this);
33572 };
33573
33574 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33575     /**
33576      * @cfg {String} alignment
33577      * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33578      */
33579     alignment: "l-l",
33580     // inherit
33581     autoSize: false,
33582     /**
33583      * @cfg {Boolean} hideEl
33584      * True to hide the bound element while the editor is displayed (defaults to false)
33585      */
33586     hideEl : false,
33587     /**
33588      * @cfg {String} cls
33589      * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33590      */
33591     cls: "x-small-editor x-tree-editor",
33592     /**
33593      * @cfg {Boolean} shim
33594      * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33595      */
33596     shim:false,
33597     // inherit
33598     shadow:"frame",
33599     /**
33600      * @cfg {Number} maxWidth
33601      * The maximum width in pixels of the editor field (defaults to 250).  Note that if the maxWidth would exceed
33602      * the containing tree element's size, it will be automatically limited for you to the container width, taking
33603      * scroll and client offsets into account prior to each edit.
33604      */
33605     maxWidth: 250,
33606
33607     editDelay : 350,
33608
33609     // private
33610     fitToTree : function(ed, el){
33611         var  td = this.tree.getTreeEl().dom, nd = el.dom;
33612         if(td.scrollLeft >  nd.offsetLeft){ // ensure the node left point is visible
33613             td.scrollLeft = nd.offsetLeft;
33614         }
33615         var  w = Math.min(
33616                 this.maxWidth,
33617                 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33618         this.setSize(w, '');
33619     },
33620
33621     // private
33622     triggerEdit : function(D){
33623         this.completeEdit();
33624         this.editNode = D;
33625         this.startEdit(D.ui.textNode, D.text);
33626     },
33627
33628     // private
33629     bindScroll : function(){
33630         this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33631     },
33632
33633     // private
33634     beforeNodeClick : function(E, e){
33635         var  F = (this.lastClick ? this.lastClick.getElapsed() : 0);
33636         this.lastClick = new  Date();
33637         if(F > this.editDelay && this.tree.getSelectionModel().isSelected(E)){
33638             e.stopEvent();
33639             this.triggerEdit(E);
33640             return  false;
33641         }
33642     },
33643
33644     // private
33645     updateNode : function(ed, G){
33646         this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33647         this.editNode.setText(G);
33648     },
33649
33650     // private
33651     onHide : function(){
33652         Roo.tree.TreeEditor.superclass.onHide.call(this);
33653         if(this.editNode){
33654             this.editNode.ui.focus();
33655         }
33656     },
33657
33658     // private
33659     onSpecialKey : function(H, e){
33660         var  k = e.getKey();
33661         if(k == e.ESC){
33662             e.stopEvent();
33663             this.cancelEdit();
33664         }else  if(k == e.ENTER && !e.hasModifier()){
33665             e.stopEvent();
33666             this.completeEdit();
33667         }
33668     }
33669 });
33670 //<Script type="text/javascript">
33671 /*
33672  * Based on:
33673  * Ext JS Library 1.1.1
33674  * Copyright(c) 2006-2007, Ext JS, LLC.
33675  *
33676  * Originally Released Under LGPL - original licence link has changed is not relivant.
33677  *
33678  * Fork - LGPL
33679  * <script type="text/javascript">
33680  */
33681  
33682 /**
33683  * Not documented??? - probably should be...
33684  */
33685
33686 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33687     //focus: Roo.emptyFn, // prevent odd scrolling behavior
33688     
33689     renderElements : function(n, a, A, B){
33690         //consel.log("renderElements?");
33691         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33692
33693         var  t = n.getOwnerTree();
33694         var  C = Pman.Tab.Document_TypesTree.tree.el.id;
33695         
33696         var  D = t.columns;
33697         var  bw = t.borderWidth;
33698         var  c = D[0];
33699         var  E = a.href ? a.href : Roo.isGecko ? "" : "#";
33700          var  cb = typeof  a.checked == "boolean";
33701         var  tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33702         var  F = 'x-t-' + C + '-c0';
33703         var  G = [
33704             '<li class="x-tree-node">',
33705             
33706                 
33707                 '<div class="x-tree-node-el ', a.cls,'">',
33708                     // extran...
33709                     '<div class="x-tree-col ', F, '" style="width:', c.width-bw, 'px;">',
33710                 
33711                 
33712                         '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33713                         '<img src="', this.emptyIcon, '" class="x-tree-ec-icon  " />',
33714                         '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33715                            (a.icon ? ' x-tree-node-inline-icon' : ''),
33716                            (a.iconCls ? ' '+a.iconCls : ''),
33717                            '" unselectable="on" />',
33718                         (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + 
33719                              (a.checked ? 'checked="checked" />' : ' />')) : ''),
33720                              
33721                         '<a class="x-tree-node-anchor" hidefocus="on" href="',E,'" tabIndex="1" ',
33722                             (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33723                             '<span unselectable="on" qtip="' + tx + '">',
33724                              tx,
33725                              '</span></a>' ,
33726                     '</div>',
33727                      '<a class="x-tree-node-anchor" hidefocus="on" href="',E,'" tabIndex="1" ',
33728                             (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33729                  ];
33730         
33731         for(var  i = 1, len = D.length; i < len; i++){
33732             c = D[i];
33733             F = 'x-t-' + C + '-c' +i;
33734             tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33735             G.push('<div class="x-tree-col ', F, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33736                         '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33737                       "</div>");
33738          }
33739
33740          
33741          G.push(
33742             '</a>',
33743             '<div class="x-clear"></div></div>',
33744             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33745             "</li>");
33746         
33747         if(B !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33748             this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33749                                 n.nextSibling.ui.getEl(), G.join(""));
33750         }else {
33751             this.wrap = Roo.DomHelper.insertHtml("beforeEnd", A, G.join(""));
33752         }
33753         var  el = this.wrap.firstChild;
33754         this.elRow = el;
33755         this.elNode = el.firstChild;
33756         this.ranchor = el.childNodes[1];
33757         this.ctNode = this.wrap.childNodes[1];
33758         var  cs = el.firstChild.childNodes;
33759         this.indentNode = cs[0];
33760         this.ecNode = cs[1];
33761         this.iconNode = cs[2];
33762         var  H = 3;
33763         if(cb){
33764             this.checkbox = cs[3];
33765             H++;
33766         }
33767
33768         this.anchor = cs[H];
33769         
33770         this.textNode = cs[H].firstChild;
33771         
33772         //el.on("click", this.onClick, this);
33773         //el.on("dblclick", this.onDblClick, this);
33774         
33775         
33776        // console.log(this);
33777     },
33778     initEvents : function(){
33779         Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33780         
33781             
33782         var  a = this.ranchor;
33783
33784         var  el = Roo.get(a);
33785
33786         if(Roo.isOpera){ // opera render bug ignores the CSS
33787             el.setStyle("text-decoration", "none");
33788         }
33789
33790
33791         el.on("click", this.onClick, this);
33792         el.on("dblclick", this.onDblClick, this);
33793         el.on("contextmenu", this.onContextMenu, this);
33794         
33795     },
33796     
33797     /*onSelectedChange : function(state){
33798         if(state){
33799             this.focus();
33800             this.addClass("x-tree-selected");
33801         }else{
33802             //this.blur();
33803             this.removeClass("x-tree-selected");
33804         }
33805     },*/
33806     addClass : function(I){
33807         if(this.elRow){
33808             Roo.fly(this.elRow).addClass(I);
33809         }
33810         
33811     },
33812     
33813     
33814     removeClass : function(J){
33815         if(this.elRow){
33816             Roo.fly(this.elRow).removeClass(J);
33817         }
33818     }
33819
33820     
33821     
33822 });
33823 //<Script type="text/javascript">
33824
33825 /*
33826  * Based on:
33827  * Ext JS Library 1.1.1
33828  * Copyright(c) 2006-2007, Ext JS, LLC.
33829  *
33830  * Originally Released Under LGPL - original licence link has changed is not relivant.
33831  *
33832  * Fork - LGPL
33833  * <script type="text/javascript">
33834  */
33835  
33836
33837 /**
33838  * @class Roo.tree.ColumnTree
33839  * @extends Roo.data.TreePanel
33840  * @cfg {Object} columns  Including width, header, renderer, cls, dataIndex 
33841  * @cfg {int} borderWidth  compined right/left border allowance
33842  * @constructor
33843  * @param {String/HTMLElement/Element} el The container element
33844  * @param {Object} config
33845  */
33846 Roo.tree.ColumnTree =  function(el, A)
33847 {
33848    Roo.tree.ColumnTree.superclass.constructor.call(this, el , A);
33849    this.addEvents({
33850         /**
33851         * @event resize
33852         * Fire this event on a container when it resizes
33853         * @param {int} w Width
33854         * @param {int} h Height
33855         */
33856        "resize" : true
33857     });
33858     this.on('resize', this.onResize, this);
33859 };
33860
33861 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33862     //lines:false,
33863     
33864     
33865     borderWidth: Roo.isBorderBox ? 0 : 2, 
33866     headEls : false,
33867     
33868     render : function(){
33869         // add the header.....
33870        
33871         Roo.tree.ColumnTree.superclass.render.apply(this);
33872         
33873         this.el.addClass('x-column-tree');
33874         
33875         this.headers = this.el.createChild(
33876             {cls:'x-tree-headers'},this.innerCt.dom);
33877    
33878         var  B = this.columns, c;
33879         var  C = 0;
33880         this.headEls = [];
33881         var   D = B.length;
33882         for(var  i = 0; i < D; i++){
33883              c = B[i];
33884              C += c.width;
33885             this.headEls.push(this.headers.createChild({
33886                  cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33887                  cn: {
33888                      cls:'x-tree-hd-text',
33889                      html: c.header
33890                  },
33891                  style:'width:'+(c.width-this.borderWidth)+'px;'
33892              }));
33893         }
33894
33895         this.headers.createChild({cls:'x-clear'});
33896         // prevent floats from wrapping when clipped
33897         this.headers.setWidth(C);
33898         //this.innerCt.setWidth(totalWidth);
33899         this.innerCt.setStyle({ overflow: 'auto' });
33900         this.onResize(this.width, this.height);
33901              
33902         
33903     },
33904     onResize : function(w,h)
33905     {
33906         this.height = h;
33907         this.width = w;
33908         // resize cols..
33909         this.innerCt.setWidth(this.width);
33910         this.innerCt.setHeight(this.height-20);
33911         
33912         // headers...
33913         var  E = this.columns, c;
33914         var  F = 0;
33915         var  G = false;
33916         var  H = E.length;
33917         for(var  i = 0; i < H; i++){
33918             c = E[i];
33919             if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33920                 // it's the expander..
33921                 G  = this.headEls[i];
33922                 continue;
33923             }
33924
33925             F += c.width;
33926             
33927         }
33928         if (G) {
33929             G.setWidth(  ((w - F)-this.borderWidth - 20));
33930         }
33931
33932         this.headers.setWidth(w-20);
33933
33934         
33935         
33936         
33937     }
33938 });
33939
33940 /*
33941  * Based on:
33942  * Ext JS Library 1.1.1
33943  * Copyright(c) 2006-2007, Ext JS, LLC.
33944  *
33945  * Originally Released Under LGPL - original licence link has changed is not relivant.
33946  *
33947  * Fork - LGPL
33948  * <script type="text/javascript">
33949  */
33950  
33951 /**
33952  * @class Roo.menu.Menu
33953  * @extends Roo.util.Observable
33954  * A menu object.  This is the container to which you add all other menu items.  Menu can also serve a as a base class
33955  * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33956  * @constructor
33957  * Creates a new Menu
33958  * @param {Object} config Configuration options
33959  */
33960 Roo.menu.Menu = function(A){
33961     Roo.apply(this, A);
33962     this.id = this.id || Roo.id();
33963     this.addEvents({
33964         /**
33965          * @event beforeshow
33966          * Fires before this menu is displayed
33967          * @param {Roo.menu.Menu} this
33968          */
33969         beforeshow : true,
33970         /**
33971          * @event beforehide
33972          * Fires before this menu is hidden
33973          * @param {Roo.menu.Menu} this
33974          */
33975         beforehide : true,
33976         /**
33977          * @event show
33978          * Fires after this menu is displayed
33979          * @param {Roo.menu.Menu} this
33980          */
33981         show : true,
33982         /**
33983          * @event hide
33984          * Fires after this menu is hidden
33985          * @param {Roo.menu.Menu} this
33986          */
33987         hide : true,
33988         /**
33989          * @event click
33990          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33991          * @param {Roo.menu.Menu} this
33992          * @param {Roo.menu.Item} menuItem The menu item that was clicked
33993          * @param {Roo.EventObject} e
33994          */
33995         click : true,
33996         /**
33997          * @event mouseover
33998          * Fires when the mouse is hovering over this menu
33999          * @param {Roo.menu.Menu} this
34000          * @param {Roo.EventObject} e
34001          * @param {Roo.menu.Item} menuItem The menu item that was clicked
34002          */
34003         mouseover : true,
34004         /**
34005          * @event mouseout
34006          * Fires when the mouse exits this menu
34007          * @param {Roo.menu.Menu} this
34008          * @param {Roo.EventObject} e
34009          * @param {Roo.menu.Item} menuItem The menu item that was clicked
34010          */
34011         mouseout : true,
34012         /**
34013          * @event itemclick
34014          * Fires when a menu item contained in this menu is clicked
34015          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34016          * @param {Roo.EventObject} e
34017          */
34018         itemclick: true
34019     });
34020     if (this.registerMenu) {
34021         Roo.menu.MenuMgr.register(this);
34022     }
34023     
34024     var  B = this.items;
34025     this.items = new  Roo.util.MixedCollection();
34026     if(B){
34027         this.add.apply(this, B);
34028     }
34029 };
34030
34031 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34032     /**
34033      * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34034      */
34035     minWidth : 120,
34036     /**
34037      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34038      * for bottom-right shadow (defaults to "sides")
34039      */
34040     shadow : "sides",
34041     /**
34042      * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34043      * this menu (defaults to "tl-tr?")
34044      */
34045     subMenuAlign : "tl-tr?",
34046     /**
34047      * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34048      * relative to its element of origin (defaults to "tl-bl?")
34049      */
34050     defaultAlign : "tl-bl?",
34051     /**
34052      * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34053      */
34054     allowOtherMenus : false,
34055     /**
34056      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34057      */
34058     registerMenu : true,
34059
34060     hidden:true,
34061
34062     // private
34063     render : function(){
34064         if(this.el){
34065             return;
34066         }
34067         var  el = this.el = new  Roo.Layer({
34068             cls: "x-menu",
34069             shadow:this.shadow,
34070             constrain: false,
34071             parentEl: this.parentEl || document.body,
34072             zindex:15000
34073         });
34074
34075         this.keyNav = new  Roo.menu.MenuNav(this);
34076
34077         if(this.plain){
34078             el.addClass("x-menu-plain");
34079         }
34080         if(this.cls){
34081             el.addClass(this.cls);
34082         }
34083
34084         // generic focus element
34085         this.focusEl = el.createChild({
34086             tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34087         });
34088         var  ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34089         ul.on("click", this.onClick, this);
34090         ul.on("mouseover", this.onMouseOver, this);
34091         ul.on("mouseout", this.onMouseOut, this);
34092         this.items.each(function(C){
34093             var  li = document.createElement("li");
34094             li.className = "x-menu-list-item";
34095             ul.dom.appendChild(li);
34096             C.render(li, this);
34097         }, this);
34098         this.ul = ul;
34099         this.autoWidth();
34100     },
34101
34102     // private
34103     autoWidth : function(){
34104         var  el = this.el, ul = this.ul;
34105         if(!el){
34106             return;
34107         }
34108         var  w = this.width;
34109         if(w){
34110             el.setWidth(w);
34111         }else  if(Roo.isIE){
34112             el.setWidth(this.minWidth);
34113             var  t = el.dom.offsetWidth; // force recalc
34114             el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34115         }
34116     },
34117
34118     // private
34119     delayAutoWidth : function(){
34120         if(this.rendered){
34121             if(!this.awTask){
34122                 this.awTask = new  Roo.util.DelayedTask(this.autoWidth, this);
34123             }
34124
34125             this.awTask.delay(20);
34126         }
34127     },
34128
34129     // private
34130     findTargetItem : function(e){
34131         var  t = e.getTarget(".x-menu-list-item", this.ul,  true);
34132         if(t && t.menuItemId){
34133             return  this.items.get(t.menuItemId);
34134         }
34135     },
34136
34137     // private
34138     onClick : function(e){
34139         var  t;
34140         if(t = this.findTargetItem(e)){
34141             t.onClick(e);
34142             this.fireEvent("click", this, t, e);
34143         }
34144     },
34145
34146     // private
34147     setActiveItem : function(C, D){
34148         if(C != this.activeItem){
34149             if(this.activeItem){
34150                 this.activeItem.deactivate();
34151             }
34152
34153             this.activeItem = C;
34154             C.activate(D);
34155         }else  if(D){
34156             C.expandMenu();
34157         }
34158     },
34159
34160     // private
34161     tryActivate : function(E, F){
34162         var  G = this.items;
34163         for(var  i = E, len = G.length; i >= 0 && i < len; i+= F){
34164             var  C = G.get(i);
34165             if(!C.disabled && C.canActivate){
34166                 this.setActiveItem(C, false);
34167                 return  C;
34168             }
34169         }
34170         return  false;
34171     },
34172
34173     // private
34174     onMouseOver : function(e){
34175         var  t;
34176         if(t = this.findTargetItem(e)){
34177             if(t.canActivate && !t.disabled){
34178                 this.setActiveItem(t, true);
34179             }
34180         }
34181
34182         this.fireEvent("mouseover", this, e, t);
34183     },
34184
34185     // private
34186     onMouseOut : function(e){
34187         var  t;
34188         if(t = this.findTargetItem(e)){
34189             if(t == this.activeItem && t.shouldDeactivate(e)){
34190                 this.activeItem.deactivate();
34191                 delete  this.activeItem;
34192             }
34193         }
34194
34195         this.fireEvent("mouseout", this, e, t);
34196     },
34197
34198     /**
34199      * Read-only.  Returns true if the menu is currently displayed, else false.
34200      * @type Boolean
34201      */
34202     isVisible : function(){
34203         return  this.el && !this.hidden;
34204     },
34205
34206     /**
34207      * Displays this menu relative to another element
34208      * @param {String/HTMLElement/Roo.Element} element The element to align to
34209      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34210      * the element (defaults to this.defaultAlign)
34211      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34212      */
34213     show : function(el, H, I){
34214         this.parentMenu = I;
34215         if(!this.el){
34216             this.render();
34217         }
34218
34219         this.fireEvent("beforeshow", this);
34220         this.showAt(this.el.getAlignToXY(el, H || this.defaultAlign), I, false);
34221     },
34222
34223     /**
34224      * Displays this menu at a specific xy position
34225      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34226      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34227      */
34228     showAt : function(xy, J, /* private: */_e){
34229         this.parentMenu = J;
34230         if(!this.el){
34231             this.render();
34232         }
34233         if(_e !== false){
34234             this.fireEvent("beforeshow", this);
34235             xy = this.el.adjustForConstraints(xy);
34236         }
34237
34238         this.el.setXY(xy);
34239         this.el.show();
34240         this.hidden = false;
34241         this.focus();
34242         this.fireEvent("show", this);
34243     },
34244
34245     focus : function(){
34246         if(!this.hidden){
34247             this.doFocus.defer(50, this);
34248         }
34249     },
34250
34251     doFocus : function(){
34252         if(!this.hidden){
34253             this.focusEl.focus();
34254         }
34255     },
34256
34257     /**
34258      * Hides this menu and optionally all parent menus
34259      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34260      */
34261     hide : function(K){
34262         if(this.el && this.isVisible()){
34263             this.fireEvent("beforehide", this);
34264             if(this.activeItem){
34265                 this.activeItem.deactivate();
34266                 this.activeItem = null;
34267             }
34268
34269             this.el.hide();
34270             this.hidden = true;
34271             this.fireEvent("hide", this);
34272         }
34273         if(K === true && this.parentMenu){
34274             this.parentMenu.hide(true);
34275         }
34276     },
34277
34278     /**
34279      * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34280      * Any of the following are valid:
34281      * <ul>
34282      * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34283      * <li>An HTMLElement object which will be converted to a menu item</li>
34284      * <li>A menu item config object that will be created as a new menu item</li>
34285      * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34286      * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34287      * </ul>
34288      * Usage:
34289      * <pre><code>
34290 // Create the menu
34291 var menu = new Roo.menu.Menu();
34292
34293 // Create a menu item to add by reference
34294 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34295
34296 // Add a bunch of items at once using different methods.
34297 // Only the last item added will be returned.
34298 var item = menu.add(
34299     menuItem,                // add existing item by ref
34300     'Dynamic Item',          // new TextItem
34301     '-',                     // new separator
34302     { text: 'Config Item' }  // new item by config
34303 );
34304 </code></pre>
34305      * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34306      * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34307      */
34308     add : function(){
34309         var  a = arguments, l = a.length, L;
34310         for(var  i = 0; i < l; i++){
34311             var  el = a[i];
34312             if(el.render){ // some kind of Item
34313                 L = this.addItem(el);
34314             }else  if(typeof  el == "string"){ // string
34315                 if(el == "separator" || el == "-"){
34316                     L = this.addSeparator();
34317                 }else {
34318                     L = this.addText(el);
34319                 }
34320             }else  if(el.tagName || el.el){ // element
34321                 L = this.addElement(el);
34322             }else  if(typeof  el == "object"){ // must be menu item config?
34323                 L = this.addMenuItem(el);
34324             }
34325         }
34326         return  L;
34327     },
34328
34329     /**
34330      * Returns this menu's underlying {@link Roo.Element} object
34331      * @return {Roo.Element} The element
34332      */
34333     getEl : function(){
34334         if(!this.el){
34335             this.render();
34336         }
34337         return  this.el;
34338     },
34339
34340     /**
34341      * Adds a separator bar to the menu
34342      * @return {Roo.menu.Item} The menu item that was added
34343      */
34344     addSeparator : function(){
34345         return  this.addItem(new  Roo.menu.Separator());
34346     },
34347
34348     /**
34349      * Adds an {@link Roo.Element} object to the menu
34350      * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34351      * @return {Roo.menu.Item} The menu item that was added
34352      */
34353     addElement : function(el){
34354         return  this.addItem(new  Roo.menu.BaseItem(el));
34355     },
34356
34357     /**
34358      * Adds an existing object based on {@link Roo.menu.Item} to the menu
34359      * @param {Roo.menu.Item} item The menu item to add
34360      * @return {Roo.menu.Item} The menu item that was added
34361      */
34362     addItem : function(M){
34363         this.items.add(M);
34364         if(this.ul){
34365             var  li = document.createElement("li");
34366             li.className = "x-menu-list-item";
34367             this.ul.dom.appendChild(li);
34368             M.render(li, this);
34369             this.delayAutoWidth();
34370         }
34371         return  M;
34372     },
34373
34374     /**
34375      * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34376      * @param {Object} config A MenuItem config object
34377      * @return {Roo.menu.Item} The menu item that was added
34378      */
34379     addMenuItem : function(N){
34380         if(!(N  instanceof  Roo.menu.Item)){
34381             if(typeof  N.checked == "boolean"){ // must be check menu item config?
34382                 N = new  Roo.menu.CheckItem(N);
34383             }else {
34384                 N = new  Roo.menu.Item(N);
34385             }
34386         }
34387         return  this.addItem(N);
34388     },
34389
34390     /**
34391      * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34392      * @param {String} text The text to display in the menu item
34393      * @return {Roo.menu.Item} The menu item that was added
34394      */
34395     addText : function(O){
34396         return  this.addItem(new  Roo.menu.TextItem(O));
34397     },
34398
34399     /**
34400      * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34401      * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34402      * @param {Roo.menu.Item} item The menu item to add
34403      * @return {Roo.menu.Item} The menu item that was added
34404      */
34405     insert : function(P, Q){
34406         this.items.insert(P, Q);
34407         if(this.ul){
34408             var  li = document.createElement("li");
34409             li.className = "x-menu-list-item";
34410             this.ul.dom.insertBefore(li, this.ul.dom.childNodes[P]);
34411             Q.render(li, this);
34412             this.delayAutoWidth();
34413         }
34414         return  Q;
34415     },
34416
34417     /**
34418      * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34419      * @param {Roo.menu.Item} item The menu item to remove
34420      */
34421     remove : function(R){
34422         this.items.removeKey(R.id);
34423         R.destroy();
34424     },
34425
34426     /**
34427      * Removes and destroys all items in the menu
34428      */
34429     removeAll : function(){
34430         var  f;
34431         while(f = this.items.first()){
34432             this.remove(f);
34433         }
34434     }
34435 });
34436
34437 // MenuNav is a private utility class used internally by the Menu
34438 Roo.menu.MenuNav = function(S){
34439     Roo.menu.MenuNav.superclass.constructor.call(this, S.el);
34440     this.scope = this.menu = S;
34441 };
34442
34443 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34444     doRelay : function(e, h){
34445         var  k = e.getKey();
34446         if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN ){
34447             this.menu.tryActivate(0, 1);
34448             return  false;
34449         }
34450         return  h.call(this.scope || this, e, this.menu);
34451     },
34452
34453     up : function(e, m){
34454         if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34455             m.tryActivate(m.items.length-1, -1);
34456         }
34457     },
34458
34459     down : function(e, m){
34460         if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34461             m.tryActivate(0, 1);
34462         }
34463     },
34464
34465     right : function(e, m){
34466         if(m.activeItem){
34467             m.activeItem.expandMenu(true);
34468         }
34469     },
34470
34471     left : function(e, m){
34472         m.hide();
34473         if(m.parentMenu && m.parentMenu.activeItem){
34474             m.parentMenu.activeItem.activate();
34475         }
34476     },
34477
34478     enter : function(e, m){
34479         if(m.activeItem){
34480             e.stopPropagation();
34481             m.activeItem.onClick(e);
34482             m.fireEvent("click", this, m.activeItem);
34483             return  true;
34484         }
34485     }
34486 });
34487 /*
34488  * Based on:
34489  * Ext JS Library 1.1.1
34490  * Copyright(c) 2006-2007, Ext JS, LLC.
34491  *
34492  * Originally Released Under LGPL - original licence link has changed is not relivant.
34493  *
34494  * Fork - LGPL
34495  * <script type="text/javascript">
34496  */
34497  
34498 /**
34499  * @class Roo.menu.MenuMgr
34500  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34501  * @singleton
34502  */
34503 Roo.menu.MenuMgr = function(){
34504    var  A, B, C = {}, attached = false, lastShow = new  Date();
34505
34506    // private - called when first menu is created
34507    function  D(){
34508        A = {};
34509        B = new  Roo.util.MixedCollection();
34510        Roo.get(document).addKeyListener(27, function(){
34511            if(B.length > 0){
34512                E();
34513            }
34514        });
34515    }
34516
34517    // private
34518    function  E(){
34519        if(B && B.length > 0){
34520            var  c = B.clone();
34521            c.each(function(m){
34522                m.hide();
34523            });
34524        }
34525    }
34526
34527    // private
34528    function  F(m){
34529        B.remove(m);
34530        if(B.length < 1){
34531            Roo.get(document).un("mousedown", J);
34532            attached = false;
34533        }
34534    }
34535
34536    // private
34537    function  G(m){
34538        var  L = B.last();
34539        lastShow = new  Date();
34540        B.add(m);
34541        if(!attached){
34542            Roo.get(document).on("mousedown", J);
34543            attached = true;
34544        }
34545        if(m.parentMenu){
34546           m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34547           m.parentMenu.activeChild = m;
34548        }else  if(L && L.isVisible()){
34549           m.getEl().setZIndex(parseInt(L.getEl().getStyle("z-index"), 10) + 3);
34550        }
34551    }
34552
34553    // private
34554    function  H(m){
34555        if(m.activeChild){
34556            m.activeChild.hide();
34557        }
34558        if(m.autoHideTimer){
34559            clearTimeout(m.autoHideTimer);
34560            delete  m.autoHideTimer;
34561        }
34562    }
34563
34564    // private
34565    function  I(m){
34566        var  pm = m.parentMenu;
34567        if(!pm && !m.allowOtherMenus){
34568            E();
34569        }else  if(pm && pm.activeChild && B != m){
34570            pm.activeChild.hide();
34571        }
34572    }
34573
34574    // private
34575    function  J(e){
34576        if(lastShow.getElapsed() > 50 && B.length > 0 && !e.getTarget(".x-menu")){
34577            E();
34578        }
34579    }
34580
34581    // private
34582    function  K(mi, L){
34583        if(L){
34584            var  g = C[mi.group];
34585            for(var  i = 0, l = g.length; i < l; i++){
34586                if(g[i] != mi){
34587                    g[i].setChecked(false);
34588                }
34589            }
34590        }
34591    }
34592
34593    return  {
34594
34595        /**
34596         * Hides all menus that are currently visible
34597         */
34598        hideAll : function(){
34599             E();  
34600        },
34601
34602        // private
34603        register : function(Q){
34604            if(!A){
34605                D();
34606            }
34607
34608            A[Q.id] = Q;
34609            Q.on("beforehide", H);
34610            Q.on("hide", F);
34611            Q.on("beforeshow", I);
34612            Q.on("show", G);
34613            var  g = Q.group;
34614            if(g && Q.events["checkchange"]){
34615                if(!C[g]){
34616                    C[g] = [];
34617                }
34618
34619                C[g].push(Q);
34620                Q.on("checkchange", onCheck);
34621            }
34622        },
34623
34624         /**
34625          * Returns a {@link Roo.menu.Menu} object
34626          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34627          * be used to generate and return a new Menu instance.
34628          */
34629        get : function(R){
34630            if(typeof  R == "string"){ // menu id
34631                return  A[R];
34632            }else  if(R.events){  // menu instance
34633                return  R;
34634            }else  if(typeof  R.length == 'number'){ // array of menu items?
34635                return  new  Roo.menu.Menu({items:R});
34636            }else { // otherwise, must be a config
34637                return  new  Roo.menu.Menu(R);
34638            }
34639        },
34640
34641        // private
34642        unregister : function(S){
34643            delete  A[S.id];
34644            S.un("beforehide", H);
34645            S.un("hide", F);
34646            S.un("beforeshow", I);
34647            S.un("show", G);
34648            var  g = S.group;
34649            if(g && S.events["checkchange"]){
34650                C[g].remove(S);
34651                S.un("checkchange", onCheck);
34652            }
34653        },
34654
34655        // private
34656        registerCheckable : function(T){
34657            var  g = T.group;
34658            if(g){
34659                if(!C[g]){
34660                    C[g] = [];
34661                }
34662
34663                C[g].push(T);
34664                T.on("beforecheckchange", K);
34665            }
34666        },
34667
34668        // private
34669        unregisterCheckable : function(U){
34670            var  g = U.group;
34671            if(g){
34672                C[g].remove(U);
34673                U.un("beforecheckchange", K);
34674            }
34675        }
34676    };
34677 }();
34678 /*
34679  * Based on:
34680  * Ext JS Library 1.1.1
34681  * Copyright(c) 2006-2007, Ext JS, LLC.
34682  *
34683  * Originally Released Under LGPL - original licence link has changed is not relivant.
34684  *
34685  * Fork - LGPL
34686  * <script type="text/javascript">
34687  */
34688  
34689
34690 /**
34691  * @class Roo.menu.BaseItem
34692  * @extends Roo.Component
34693  * The base class for all items that render into menus.  BaseItem provides default rendering, activated state
34694  * management and base configuration options shared by all menu components.
34695  * @constructor
34696  * Creates a new BaseItem
34697  * @param {Object} config Configuration options
34698  */
34699 Roo.menu.BaseItem = function(A){
34700     Roo.menu.BaseItem.superclass.constructor.call(this, A);
34701
34702     this.addEvents({
34703         /**
34704          * @event click
34705          * Fires when this item is clicked
34706          * @param {Roo.menu.BaseItem} this
34707          * @param {Roo.EventObject} e
34708          */
34709         click: true,
34710         /**
34711          * @event activate
34712          * Fires when this item is activated
34713          * @param {Roo.menu.BaseItem} this
34714          */
34715         activate : true,
34716         /**
34717          * @event deactivate
34718          * Fires when this item is deactivated
34719          * @param {Roo.menu.BaseItem} this
34720          */
34721         deactivate : true
34722     });
34723
34724     if(this.handler){
34725         this.on("click", this.handler, this.scope, true);
34726     }
34727 };
34728
34729 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34730     /**
34731      * @cfg {Function} handler
34732      * A function that will handle the click event of this menu item (defaults to undefined)
34733      */
34734     /**
34735      * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34736      */
34737     canActivate : false,
34738     /**
34739      * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34740      */
34741     activeClass : "x-menu-item-active",
34742     /**
34743      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34744      */
34745     hideOnClick : true,
34746     /**
34747      * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34748      */
34749     hideDelay : 100,
34750
34751     // private
34752     ctype: "Roo.menu.BaseItem",
34753
34754     // private
34755     actionMode : "container",
34756
34757     // private
34758     render : function(B, C){
34759         this.parentMenu = C;
34760         Roo.menu.BaseItem.superclass.render.call(this, B);
34761         this.container.menuItemId = this.id;
34762     },
34763
34764     // private
34765     onRender : function(D, E){
34766         this.el = Roo.get(this.el);
34767         D.dom.appendChild(this.el.dom);
34768     },
34769
34770     // private
34771     onClick : function(e){
34772         if(!this.disabled && this.fireEvent("click", this, e) !== false
34773                 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34774             this.handleClick(e);
34775         }else {
34776             e.stopEvent();
34777         }
34778     },
34779
34780     // private
34781     activate : function(){
34782         if(this.disabled){
34783             return  false;
34784         }
34785         var  li = this.container;
34786         li.addClass(this.activeClass);
34787         this.region = li.getRegion().adjust(2, 2, -2, -2);
34788         this.fireEvent("activate", this);
34789         return  true;
34790     },
34791
34792     // private
34793     deactivate : function(){
34794         this.container.removeClass(this.activeClass);
34795         this.fireEvent("deactivate", this);
34796     },
34797
34798     // private
34799     shouldDeactivate : function(e){
34800         return  !this.region || !this.region.contains(e.getPoint());
34801     },
34802
34803     // private
34804     handleClick : function(e){
34805         if(this.hideOnClick){
34806             this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34807         }
34808     },
34809
34810     // private
34811     expandMenu : function(F){
34812         // do nothing
34813     },
34814
34815     // private
34816     hideMenu : function(){
34817         // do nothing
34818     }
34819 });
34820 /*
34821  * Based on:
34822  * Ext JS Library 1.1.1
34823  * Copyright(c) 2006-2007, Ext JS, LLC.
34824  *
34825  * Originally Released Under LGPL - original licence link has changed is not relivant.
34826  *
34827  * Fork - LGPL
34828  * <script type="text/javascript">
34829  */
34830  
34831 /**
34832  * @class Roo.menu.Adapter
34833  * @extends Roo.menu.BaseItem
34834  * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
34835  * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34836  * @constructor
34837  * Creates a new Adapter
34838  * @param {Object} config Configuration options
34839  */
34840 Roo.menu.Adapter = function(A, B){
34841     Roo.menu.Adapter.superclass.constructor.call(this, B);
34842     this.component = A;
34843 };
34844 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34845     // private
34846     canActivate : true,
34847
34848     // private
34849     onRender : function(C, D){
34850         this.component.render(C);
34851         this.el = this.component.getEl();
34852     },
34853
34854     // private
34855     activate : function(){
34856         if(this.disabled){
34857             return  false;
34858         }
34859
34860         this.component.focus();
34861         this.fireEvent("activate", this);
34862         return  true;
34863     },
34864
34865     // private
34866     deactivate : function(){
34867         this.fireEvent("deactivate", this);
34868     },
34869
34870     // private
34871     disable : function(){
34872         this.component.disable();
34873         Roo.menu.Adapter.superclass.disable.call(this);
34874     },
34875
34876     // private
34877     enable : function(){
34878         this.component.enable();
34879         Roo.menu.Adapter.superclass.enable.call(this);
34880     }
34881 });
34882 /*
34883  * Based on:
34884  * Ext JS Library 1.1.1
34885  * Copyright(c) 2006-2007, Ext JS, LLC.
34886  *
34887  * Originally Released Under LGPL - original licence link has changed is not relivant.
34888  *
34889  * Fork - LGPL
34890  * <script type="text/javascript">
34891  */
34892
34893 /**
34894  * @class Roo.menu.TextItem
34895  * @extends Roo.menu.BaseItem
34896  * Adds a static text string to a menu, usually used as either a heading or group separator.
34897  * @constructor
34898  * Creates a new TextItem
34899  * @param {String} text The text to display
34900  */
34901 Roo.menu.TextItem = function(A){
34902     this.text = A;
34903     Roo.menu.TextItem.superclass.constructor.call(this);
34904 };
34905
34906 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34907     /**
34908      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34909      */
34910     hideOnClick : false,
34911     /**
34912      * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34913      */
34914     itemCls : "x-menu-text",
34915
34916     // private
34917     onRender : function(){
34918         var  s = document.createElement("span");
34919         s.className = this.itemCls;
34920         s.innerHTML = this.text;
34921         this.el = s;
34922         Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34923     }
34924 });
34925 /*
34926  * Based on:
34927  * Ext JS Library 1.1.1
34928  * Copyright(c) 2006-2007, Ext JS, LLC.
34929  *
34930  * Originally Released Under LGPL - original licence link has changed is not relivant.
34931  *
34932  * Fork - LGPL
34933  * <script type="text/javascript">
34934  */
34935
34936 /**
34937  * @class Roo.menu.Separator
34938  * @extends Roo.menu.BaseItem
34939  * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34940  * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34941  * @constructor
34942  * @param {Object} config Configuration options
34943  */
34944 Roo.menu.Separator = function(A){
34945     Roo.menu.Separator.superclass.constructor.call(this, A);
34946 };
34947
34948 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34949     /**
34950      * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34951      */
34952     itemCls : "x-menu-sep",
34953     /**
34954      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34955      */
34956     hideOnClick : false,
34957
34958     // private
34959     onRender : function(li){
34960         var  s = document.createElement("span");
34961         s.className = this.itemCls;
34962         s.innerHTML = "&#160;";
34963         this.el = s;
34964         li.addClass("x-menu-sep-li");
34965         Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34966     }
34967 });
34968 /*
34969  * Based on:
34970  * Ext JS Library 1.1.1
34971  * Copyright(c) 2006-2007, Ext JS, LLC.
34972  *
34973  * Originally Released Under LGPL - original licence link has changed is not relivant.
34974  *
34975  * Fork - LGPL
34976  * <script type="text/javascript">
34977  */
34978 /**
34979  * @class Roo.menu.Item
34980  * @extends Roo.menu.BaseItem
34981  * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34982  * display items.  Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34983  * activation and click handling.
34984  * @constructor
34985  * Creates a new Item
34986  * @param {Object} config Configuration options
34987  */
34988 Roo.menu.Item = function(A){
34989     Roo.menu.Item.superclass.constructor.call(this, A);
34990     if(this.menu){
34991         this.menu = Roo.menu.MenuMgr.get(this.menu);
34992     }
34993 };
34994 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34995     /**
34996      * @cfg {String} icon
34997      * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34998      */
34999     /**
35000      * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35001      */
35002     itemCls : "x-menu-item",
35003     /**
35004      * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35005      */
35006     canActivate : true,
35007     /**
35008      * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35009      */
35010     showDelay: 200,
35011     // doc'd in BaseItem
35012     hideDelay: 200,
35013
35014     // private
35015     ctype: "Roo.menu.Item",
35016     
35017     // private
35018     onRender : function(B, C){
35019         var  el = document.createElement("a");
35020         el.hideFocus = true;
35021         el.unselectable = "on";
35022         el.href = this.href || "#";
35023         if(this.hrefTarget){
35024             el.target = this.hrefTarget;
35025         }
35026
35027         el.className = this.itemCls + (this.menu ?  " x-menu-item-arrow" : "") + (this.cls ?  " " + this.cls : "");
35028         el.innerHTML = String.format(
35029                 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
35030                 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
35031         this.el = el;
35032         Roo.menu.Item.superclass.onRender.call(this, B, C);
35033     },
35034
35035     /**
35036      * Sets the text to display in this menu item
35037      * @param {String} text The text to display
35038      */
35039     setText : function(D){
35040         this.text = D;
35041         if(this.rendered){
35042             this.el.update(String.format(
35043                 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
35044                 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35045             this.parentMenu.autoWidth();
35046         }
35047     },
35048
35049     // private
35050     handleClick : function(e){
35051         if(!this.href){ // if no link defined, stop the event automatically
35052             e.stopEvent();
35053         }
35054
35055         Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35056     },
35057
35058     // private
35059     activate : function(E){
35060         if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35061             this.focus();
35062             if(E){
35063                 this.expandMenu();
35064             }
35065         }
35066         return  true;
35067     },
35068
35069     // private
35070     shouldDeactivate : function(e){
35071         if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35072             if(this.menu && this.menu.isVisible()){
35073                 return  !this.menu.getEl().getRegion().contains(e.getPoint());
35074             }
35075             return  true;
35076         }
35077         return  false;
35078     },
35079
35080     // private
35081     deactivate : function(){
35082         Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35083         this.hideMenu();
35084     },
35085
35086     // private
35087     expandMenu : function(F){
35088         if(!this.disabled && this.menu){
35089             clearTimeout(this.hideTimer);
35090             delete  this.hideTimer;
35091             if(!this.menu.isVisible() && !this.showTimer){
35092                 this.showTimer = this.deferExpand.defer(this.showDelay, this, [F]);
35093             }else  if (this.menu.isVisible() && F){
35094                 this.menu.tryActivate(0, 1);
35095             }
35096         }
35097     },
35098
35099     // private
35100     deferExpand : function(G){
35101         delete  this.showTimer;
35102         this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35103         if(G){
35104             this.menu.tryActivate(0, 1);
35105         }
35106     },
35107
35108     // private
35109     hideMenu : function(){
35110         clearTimeout(this.showTimer);
35111         delete  this.showTimer;
35112         if(!this.hideTimer && this.menu && this.menu.isVisible()){
35113             this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35114         }
35115     },
35116
35117     // private
35118     deferHide : function(){
35119         delete  this.hideTimer;
35120         this.menu.hide();
35121     }
35122 });
35123 /*
35124  * Based on:
35125  * Ext JS Library 1.1.1
35126  * Copyright(c) 2006-2007, Ext JS, LLC.
35127  *
35128  * Originally Released Under LGPL - original licence link has changed is not relivant.
35129  *
35130  * Fork - LGPL
35131  * <script type="text/javascript">
35132  */
35133  
35134 /**
35135  * @class Roo.menu.CheckItem
35136  * @extends Roo.menu.Item
35137  * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35138  * @constructor
35139  * Creates a new CheckItem
35140  * @param {Object} config Configuration options
35141  */
35142 Roo.menu.CheckItem = function(A){
35143     Roo.menu.CheckItem.superclass.constructor.call(this, A);
35144     this.addEvents({
35145         /**
35146          * @event beforecheckchange
35147          * Fires before the checked value is set, providing an opportunity to cancel if needed
35148          * @param {Roo.menu.CheckItem} this
35149          * @param {Boolean} checked The new checked value that will be set
35150          */
35151         "beforecheckchange" : true,
35152         /**
35153          * @event checkchange
35154          * Fires after the checked value has been set
35155          * @param {Roo.menu.CheckItem} this
35156          * @param {Boolean} checked The checked value that was set
35157          */
35158         "checkchange" : true
35159     });
35160     if(this.checkHandler){
35161         this.on('checkchange', this.checkHandler, this.scope);
35162     }
35163 };
35164 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35165     /**
35166      * @cfg {String} group
35167      * All check items with the same group name will automatically be grouped into a single-select
35168      * radio button group (defaults to '')
35169      */
35170     /**
35171      * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35172      */
35173     itemCls : "x-menu-item x-menu-check-item",
35174     /**
35175      * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35176      */
35177     groupClass : "x-menu-group-item",
35178
35179     /**
35180      * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false).  Note that
35181      * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35182      * initialized with checked = true will be rendered as checked.
35183      */
35184     checked: false,
35185
35186     // private
35187     ctype: "Roo.menu.CheckItem",
35188
35189     // private
35190     onRender : function(c){
35191         Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35192         if(this.group){
35193             this.el.addClass(this.groupClass);
35194         }
35195
35196         Roo.menu.MenuMgr.registerCheckable(this);
35197         if(this.checked){
35198             this.checked = false;
35199             this.setChecked(true, true);
35200         }
35201     },
35202
35203     // private
35204     destroy : function(){
35205         if(this.rendered){
35206             Roo.menu.MenuMgr.unregisterCheckable(this);
35207         }
35208
35209         Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35210     },
35211
35212     /**
35213      * Set the checked state of this item
35214      * @param {Boolean} checked The new checked value
35215      * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35216      */
35217     setChecked : function(B, C){
35218         if(this.checked != B && this.fireEvent("beforecheckchange", this, B) !== false){
35219             if(this.container){
35220                 this.container[B ? "addClass" : "removeClass"]("x-menu-item-checked");
35221             }
35222
35223             this.checked = B;
35224             if(C !== true){
35225                 this.fireEvent("checkchange", this, B);
35226             }
35227         }
35228     },
35229
35230     // private
35231     handleClick : function(e){
35232        if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35233            this.setChecked(!this.checked);
35234        }
35235
35236        Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35237     }
35238 });
35239 /*
35240  * Based on:
35241  * Ext JS Library 1.1.1
35242  * Copyright(c) 2006-2007, Ext JS, LLC.
35243  *
35244  * Originally Released Under LGPL - original licence link has changed is not relivant.
35245  *
35246  * Fork - LGPL
35247  * <script type="text/javascript">
35248  */
35249  
35250 /**
35251  * @class Roo.menu.DateItem
35252  * @extends Roo.menu.Adapter
35253  * A menu item that wraps the {@link Roo.DatPicker} component.
35254  * @constructor
35255  * Creates a new DateItem
35256  * @param {Object} config Configuration options
35257  */
35258 Roo.menu.DateItem = function(A){
35259     Roo.menu.DateItem.superclass.constructor.call(this, new  Roo.DatePicker(A), A);
35260     /** The Roo.DatePicker object @type Roo.DatePicker */
35261     this.picker = this.component;
35262     this.addEvents({select: true});
35263     
35264     this.picker.on("render", function(B){
35265         B.getEl().swallowEvent("click");
35266         B.container.addClass("x-menu-date-item");
35267     });
35268
35269     this.picker.on("select", this.onSelect, this);
35270 };
35271
35272 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35273     // private
35274     onSelect : function(B, C){
35275         this.fireEvent("select", this, C, B);
35276         Roo.menu.DateItem.superclass.handleClick.call(this);
35277     }
35278 });
35279 /*
35280  * Based on:
35281  * Ext JS Library 1.1.1
35282  * Copyright(c) 2006-2007, Ext JS, LLC.
35283  *
35284  * Originally Released Under LGPL - original licence link has changed is not relivant.
35285  *
35286  * Fork - LGPL
35287  * <script type="text/javascript">
35288  */
35289  
35290 /**
35291  * @class Roo.menu.ColorItem
35292  * @extends Roo.menu.Adapter
35293  * A menu item that wraps the {@link Roo.ColorPalette} component.
35294  * @constructor
35295  * Creates a new ColorItem
35296  * @param {Object} config Configuration options
35297  */
35298 Roo.menu.ColorItem = function(A){
35299     Roo.menu.ColorItem.superclass.constructor.call(this, new  Roo.ColorPalette(A), A);
35300     /** The Roo.ColorPalette object @type Roo.ColorPalette */
35301     this.palette = this.component;
35302     this.relayEvents(this.palette, ["select"]);
35303     if(this.selectHandler){
35304         this.on('select', this.selectHandler, this.scope);
35305     }
35306 };
35307 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);
35308 /*
35309  * Based on:
35310  * Ext JS Library 1.1.1
35311  * Copyright(c) 2006-2007, Ext JS, LLC.
35312  *
35313  * Originally Released Under LGPL - original licence link has changed is not relivant.
35314  *
35315  * Fork - LGPL
35316  * <script type="text/javascript">
35317  */
35318  
35319
35320 /**
35321  * @class Roo.menu.DateMenu
35322  * @extends Roo.menu.Menu
35323  * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35324  * @constructor
35325  * Creates a new DateMenu
35326  * @param {Object} config Configuration options
35327  */
35328 Roo.menu.DateMenu = function(A){
35329     Roo.menu.DateMenu.superclass.constructor.call(this, A);
35330     this.plain = true;
35331     var  di = new  Roo.menu.DateItem(A);
35332     this.add(di);
35333     /**
35334      * The {@link Roo.DatePicker} instance for this DateMenu
35335      * @type DatePicker
35336      */
35337     this.picker = di.picker;
35338     /**
35339      * @event select
35340      * @param {DatePicker} picker
35341      * @param {Date} date
35342      */
35343     this.relayEvents(di, ["select"]);
35344
35345     this.on('beforeshow', function(){
35346         if(this.picker){
35347             this.picker.hideMonthPicker(true);
35348         }
35349     }, this);
35350 };
35351 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35352     cls:'x-date-menu'
35353 });
35354 /*
35355  * Based on:
35356  * Ext JS Library 1.1.1
35357  * Copyright(c) 2006-2007, Ext JS, LLC.
35358  *
35359  * Originally Released Under LGPL - original licence link has changed is not relivant.
35360  *
35361  * Fork - LGPL
35362  * <script type="text/javascript">
35363  */
35364  
35365
35366 /**
35367  * @class Roo.menu.ColorMenu
35368  * @extends Roo.menu.Menu
35369  * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35370  * @constructor
35371  * Creates a new ColorMenu
35372  * @param {Object} config Configuration options
35373  */
35374 Roo.menu.ColorMenu = function(A){
35375     Roo.menu.ColorMenu.superclass.constructor.call(this, A);
35376     this.plain = true;
35377     var  ci = new  Roo.menu.ColorItem(A);
35378     this.add(ci);
35379     /**
35380      * The {@link Roo.ColorPalette} instance for this ColorMenu
35381      * @type ColorPalette
35382      */
35383     this.palette = ci.palette;
35384     /**
35385      * @event select
35386      * @param {ColorPalette} palette
35387      * @param {String} color
35388      */
35389     this.relayEvents(ci, ["select"]);
35390 };
35391 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);
35392 /*
35393  * Based on:
35394  * Ext JS Library 1.1.1
35395  * Copyright(c) 2006-2007, Ext JS, LLC.
35396  *
35397  * Originally Released Under LGPL - original licence link has changed is not relivant.
35398  *
35399  * Fork - LGPL
35400  * <script type="text/javascript">
35401  */
35402  
35403 /**
35404  * @class Roo.form.Field
35405  * @extends Roo.BoxComponent
35406  * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35407  * @constructor
35408  * Creates a new Field
35409  * @param {Object} config Configuration options
35410  */
35411 Roo.form.Field = function(A){
35412     Roo.form.Field.superclass.constructor.call(this, A);
35413 };
35414
35415 Roo.extend(Roo.form.Field, Roo.BoxComponent,  {
35416     /**
35417      * @cfg {String} fieldLabel Label to use when rendering a form.
35418      */
35419        /**
35420      * @cfg {String} qtip Mouse over tip
35421      */
35422      
35423     /**
35424      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35425      */
35426     invalidClass : "x-form-invalid",
35427     /**
35428      * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
35429      */
35430     invalidText : "The value in this field is invalid",
35431     /**
35432      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35433      */
35434     focusClass : "x-form-focus",
35435     /**
35436      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35437       automatic validation (defaults to "keyup").
35438      */
35439     validationEvent : "keyup",
35440     /**
35441      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35442      */
35443     validateOnBlur : true,
35444     /**
35445      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35446      */
35447     validationDelay : 250,
35448     /**
35449      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35450      * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35451      */
35452     defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35453     /**
35454      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35455      */
35456     fieldClass : "x-form-field",
35457     /**
35458      * @cfg {String} msgTarget The location where error text should display.  Should be one of the following values (defaults to 'qtip'):
35459      *<pre>
35460 Value         Description
35461 -----------   ----------------------------------------------------------------------
35462 qtip          Display a quick tip when the user hovers over the field
35463 title         Display a default browser title attribute popup
35464 under         Add a block div beneath the field containing the error text
35465 side          Add an error icon to the right of the field with a popup on hover
35466 [element id]  Add the error text directly to the innerHTML of the specified element
35467 </pre>
35468      */
35469     msgTarget : 'qtip',
35470     /**
35471      * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35472      */
35473     msgFx : 'normal',
35474
35475     /**
35476      * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
35477      */
35478     readOnly : false,
35479
35480     /**
35481      * @cfg {Boolean} disabled True to disable the field (defaults to false).
35482      */
35483     disabled : false,
35484
35485     /**
35486      * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35487      */
35488     inputType : undefined,
35489     
35490     /**
35491      * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
35492          */
35493         tabIndex : undefined,
35494         
35495     // private
35496     isFormField : true,
35497
35498     // private
35499     hasFocus : false,
35500     /**
35501      * @property {Roo.Element} fieldEl
35502      * Element Containing the rendered Field (with label etc.)
35503      */
35504     /**
35505      * @cfg {Mixed} value A value to initialize this field with.
35506      */
35507     value : undefined,
35508
35509     /**
35510      * @cfg {String} name The field's HTML name attribute.
35511      */
35512     /**
35513      * @cfg {String} cls A CSS class to apply to the field's underlying element.
35514      */
35515
35516         // private ??
35517         initComponent : function(){
35518         Roo.form.Field.superclass.initComponent.call(this);
35519         this.addEvents({
35520             /**
35521              * @event focus
35522              * Fires when this field receives input focus.
35523              * @param {Roo.form.Field} this
35524              */
35525             focus : true,
35526             /**
35527              * @event blur
35528              * Fires when this field loses input focus.
35529              * @param {Roo.form.Field} this
35530              */
35531             blur : true,
35532             /**
35533              * @event specialkey
35534              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
35535              * {@link Roo.EventObject#getKey} to determine which key was pressed.
35536              * @param {Roo.form.Field} this
35537              * @param {Roo.EventObject} e The event object
35538              */
35539             specialkey : true,
35540             /**
35541              * @event change
35542              * Fires just before the field blurs if the field value has changed.
35543              * @param {Roo.form.Field} this
35544              * @param {Mixed} newValue The new value
35545              * @param {Mixed} oldValue The original value
35546              */
35547             change : true,
35548             /**
35549              * @event invalid
35550              * Fires after the field has been marked as invalid.
35551              * @param {Roo.form.Field} this
35552              * @param {String} msg The validation message
35553              */
35554             invalid : true,
35555             /**
35556              * @event valid
35557              * Fires after the field has been validated with no errors.
35558              * @param {Roo.form.Field} this
35559              */
35560             valid : true
35561         });
35562     },
35563
35564     /**
35565      * Returns the name attribute of the field if available
35566      * @return {String} name The field name
35567      */
35568     getName: function(){
35569          return  this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35570     },
35571
35572     // private
35573     onRender : function(ct, B){
35574         Roo.form.Field.superclass.onRender.call(this, ct, B);
35575         if(!this.el){
35576             var  cfg = this.getAutoCreate();
35577             if(!cfg.name){
35578                 cfg.name = this.name || this.id;
35579             }
35580             if(this.inputType){
35581                 cfg.type = this.inputType;
35582             }
35583
35584             this.el = ct.createChild(cfg, B);
35585         }
35586         var  C = this.el.dom.type;
35587         if(C){
35588             if(C == 'password'){
35589                 C = 'text';
35590             }
35591
35592             this.el.addClass('x-form-'+C);
35593         }
35594         if(this.readOnly){
35595             this.el.dom.readOnly = true;
35596         }
35597         if(this.tabIndex !== undefined){
35598             this.el.dom.setAttribute('tabIndex', this.tabIndex);
35599         }
35600
35601
35602         this.el.addClass([this.fieldClass, this.cls]);
35603         this.initValue();
35604     },
35605
35606     /**
35607      * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35608      * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35609      * @return {Roo.form.Field} this
35610      */
35611     applyTo : function(D){
35612         this.allowDomMove = false;
35613         this.el = Roo.get(D);
35614         this.render(this.el.dom.parentNode);
35615         return  this;
35616     },
35617
35618     // private
35619     initValue : function(){
35620         if(this.value !== undefined){
35621             this.setValue(this.value);
35622         }else  if(this.el.dom.value.length > 0){
35623             this.setValue(this.el.dom.value);
35624         }
35625     },
35626
35627     /**
35628      * Returns true if this field has been changed since it was originally loaded and is not disabled.
35629      */
35630     isDirty : function() {
35631         if(this.disabled) {
35632             return  false;
35633         }
35634         return  String(this.getValue()) !== String(this.originalValue);
35635     },
35636
35637     // private
35638     afterRender : function(){
35639         Roo.form.Field.superclass.afterRender.call(this);
35640         this.initEvents();
35641     },
35642
35643     // private
35644     fireKey : function(e){
35645         if(e.isNavKeyPress()){
35646             this.fireEvent("specialkey", this, e);
35647         }
35648     },
35649
35650     /**
35651      * Resets the current field value to the originally loaded value and clears any validation messages
35652      */
35653     reset : function(){
35654         this.setValue(this.originalValue);
35655         this.clearInvalid();
35656     },
35657
35658     // private
35659     initEvents : function(){
35660         this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey,  this);
35661         this.el.on("focus", this.onFocus,  this);
35662         this.el.on("blur", this.onBlur,  this);
35663
35664         // reference to original value for reset
35665         this.originalValue = this.getValue();
35666     },
35667
35668     // private
35669     onFocus : function(){
35670         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35671             this.el.addClass(this.focusClass);
35672         }
35673         if(!this.hasFocus){
35674             this.hasFocus = true;
35675             this.startValue = this.getValue();
35676             this.fireEvent("focus", this);
35677         }
35678     },
35679
35680     beforeBlur : Roo.emptyFn,
35681
35682     // private
35683     onBlur : function(){
35684         this.beforeBlur();
35685         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35686             this.el.removeClass(this.focusClass);
35687         }
35688
35689         this.hasFocus = false;
35690         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35691             this.validate();
35692         }
35693         var  v = this.getValue();
35694         if(String(v) !== String(this.startValue)){
35695             this.fireEvent('change', this, v, this.startValue);
35696         }
35697
35698         this.fireEvent("blur", this);
35699     },
35700
35701     /**
35702      * Returns whether or not the field value is currently valid
35703      * @param {Boolean} preventMark True to disable marking the field invalid
35704      * @return {Boolean} True if the value is valid, else false
35705      */
35706     isValid : function(E){
35707         if(this.disabled){
35708             return  true;
35709         }
35710         var  F = this.preventMark;
35711         this.preventMark = E === true;
35712         var  v = this.validateValue(this.processValue(this.getRawValue()));
35713         this.preventMark = F;
35714         return  v;
35715     },
35716
35717     /**
35718      * Validates the field value
35719      * @return {Boolean} True if the value is valid, else false
35720      */
35721     validate : function(){
35722         if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35723             this.clearInvalid();
35724             return  true;
35725         }
35726         return  false;
35727     },
35728
35729     processValue : function(G){
35730         return  G;
35731     },
35732
35733     // private
35734     // Subclasses should provide the validation implementation by overriding this
35735     validateValue : function(H){
35736         return  true;
35737     },
35738
35739     /**
35740      * Mark this field as invalid
35741      * @param {String} msg The validation message
35742      */
35743     markInvalid : function(I){
35744         if(!this.rendered || this.preventMark){ // not rendered
35745             return;
35746         }
35747
35748         this.el.addClass(this.invalidClass);
35749         I = I || this.invalidText;
35750         switch(this.msgTarget){
35751             case  'qtip':
35752                 this.el.dom.qtip = I;
35753                 this.el.dom.qclass = 'x-form-invalid-tip';
35754                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35755                     Roo.QuickTips.enable();
35756                 }
35757                 break;
35758             case  'title':
35759                 this.el.dom.title = I;
35760                 break;
35761             case  'under':
35762                 if(!this.errorEl){
35763                     var  elp = this.el.findParent('.x-form-element', 5, true);
35764                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35765                     this.errorEl.setWidth(elp.getWidth(true)-20);
35766                 }
35767
35768                 this.errorEl.update(I);
35769                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35770                 break;
35771             case  'side':
35772                 if(!this.errorIcon){
35773                     var  elp = this.el.findParent('.x-form-element', 5, true);
35774                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35775                 }
35776
35777                 this.alignErrorIcon();
35778                 this.errorIcon.dom.qtip = I;
35779                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35780                 this.errorIcon.show();
35781                 this.on('resize', this.alignErrorIcon, this);
35782                 break;
35783             default:
35784                 var  t = Roo.getDom(this.msgTarget);
35785                 t.innerHTML = I;
35786                 t.style.display = this.msgDisplay;
35787                 break;
35788         }
35789
35790         this.fireEvent('invalid', this, I);
35791     },
35792
35793     // private
35794     alignErrorIcon : function(){
35795         this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35796     },
35797
35798     /**
35799      * Clear any invalid styles/messages for this field
35800      */
35801     clearInvalid : function(){
35802         if(!this.rendered || this.preventMark){ // not rendered
35803             return;
35804         }
35805
35806         this.el.removeClass(this.invalidClass);
35807         switch(this.msgTarget){
35808             case  'qtip':
35809                 this.el.dom.qtip = '';
35810                 break;
35811             case  'title':
35812                 this.el.dom.title = '';
35813                 break;
35814             case  'under':
35815                 if(this.errorEl){
35816                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35817                 }
35818                 break;
35819             case  'side':
35820                 if(this.errorIcon){
35821                     this.errorIcon.dom.qtip = '';
35822                     this.errorIcon.hide();
35823                     this.un('resize', this.alignErrorIcon, this);
35824                 }
35825                 break;
35826             default:
35827                 var  t = Roo.getDom(this.msgTarget);
35828                 t.innerHTML = '';
35829                 t.style.display = 'none';
35830                 break;
35831         }
35832
35833         this.fireEvent('valid', this);
35834     },
35835
35836     /**
35837      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
35838      * @return {Mixed} value The field value
35839      */
35840     getRawValue : function(){
35841         var  v = this.el.getValue();
35842         if(v === this.emptyText){
35843             v = '';
35844         }
35845         return  v;
35846     },
35847
35848     /**
35849      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
35850      * @return {Mixed} value The field value
35851      */
35852     getValue : function(){
35853         var  v = this.el.getValue();
35854         if(v === this.emptyText || v === undefined){
35855             v = '';
35856         }
35857         return  v;
35858     },
35859
35860     /**
35861      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
35862      * @param {Mixed} value The value to set
35863      */
35864     setRawValue : function(v){
35865         return  this.el.dom.value = (v === null || v === undefined ? '' : v);
35866     },
35867
35868     /**
35869      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
35870      * @param {Mixed} value The value to set
35871      */
35872     setValue : function(v){
35873         this.value = v;
35874         if(this.rendered){
35875             this.el.dom.value = (v === null || v === undefined ? '' : v);
35876             this.validate();
35877         }
35878     },
35879
35880     adjustSize : function(w, h){
35881         var  s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35882         s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35883         return  s;
35884     },
35885
35886     adjustWidth : function(J, w){
35887         J = J.toLowerCase();
35888         if(typeof  w == 'number' && Roo.isStrict && !Roo.isSafari){
35889             if(Roo.isIE && (J == 'input' || J == 'textarea')){
35890                 if(J == 'input'){
35891                     return  w + 2;
35892                 }
35893                 if(J = 'textarea'){
35894                     return  w-2;
35895                 }
35896             }else  if(Roo.isOpera){
35897                 if(J == 'input'){
35898                     return  w + 2;
35899                 }
35900                 if(J = 'textarea'){
35901                     return  w-2;
35902                 }
35903             }
35904         }
35905         return  w;
35906     }
35907 });
35908
35909
35910 // anything other than normal should be considered experimental
35911 Roo.form.Field.msgFx = {
35912     normal : {
35913         show: function(K, f){
35914             K.setDisplayed('block');
35915         },
35916
35917         hide : function(L, f){
35918             L.setDisplayed(false).update('');
35919         }
35920     },
35921
35922     slide : {
35923         show: function(M, f){
35924             M.slideIn('t', {stopFx:true});
35925         },
35926
35927         hide : function(N, f){
35928             N.slideOut('t', {stopFx:true,useDisplay:true});
35929         }
35930     },
35931
35932     slideRight : {
35933         show: function(O, f){
35934             O.fixDisplay();
35935             O.alignTo(f.el, 'tl-tr');
35936             O.slideIn('l', {stopFx:true});
35937         },
35938
35939         hide : function(P, f){
35940             P.slideOut('l', {stopFx:true,useDisplay:true});
35941         }
35942     }
35943 };
35944 /*
35945  * Based on:
35946  * Ext JS Library 1.1.1
35947  * Copyright(c) 2006-2007, Ext JS, LLC.
35948  *
35949  * Originally Released Under LGPL - original licence link has changed is not relivant.
35950  *
35951  * Fork - LGPL
35952  * <script type="text/javascript">
35953  */
35954  
35955
35956 /**
35957  * @class Roo.form.TextField
35958  * @extends Roo.form.Field
35959  * Basic text field.  Can be used as a direct replacement for traditional text inputs, or as the base
35960  * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35961  * @constructor
35962  * Creates a new TextField
35963  * @param {Object} config Configuration options
35964  */
35965 Roo.form.TextField = function(A){
35966     Roo.form.TextField.superclass.constructor.call(this, A);
35967     this.addEvents({
35968         /**
35969          * @event autosize
35970          * Fires when the autosize function is triggered.  The field may or may not have actually changed size
35971          * according to the default logic, but this event provides a hook for the developer to apply additional
35972          * logic at runtime to resize the field if needed.
35973              * @param {Roo.form.Field} this This text field
35974              * @param {Number} width The new field width
35975              */
35976         autosize : true
35977     });
35978 };
35979
35980 Roo.extend(Roo.form.TextField, Roo.form.Field,  {
35981     /**
35982      * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35983      */
35984     grow : false,
35985     /**
35986      * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35987      */
35988     growMin : 30,
35989     /**
35990      * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35991      */
35992     growMax : 800,
35993     /**
35994      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35995      */
35996     vtype : null,
35997     /**
35998      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35999      */
36000     maskRe : null,
36001     /**
36002      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36003      */
36004     disableKeyFilter : false,
36005     /**
36006      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36007      */
36008     allowBlank : true,
36009     /**
36010      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36011      */
36012     minLength : 0,
36013     /**
36014      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36015      */
36016     maxLength : Number.MAX_VALUE,
36017     /**
36018      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36019      */
36020     minLengthText : "The minimum length for this field is {0}",
36021     /**
36022      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36023      */
36024     maxLengthText : "The maximum length for this field is {0}",
36025     /**
36026      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36027      */
36028     selectOnFocus : false,
36029     /**
36030      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36031      */
36032     blankText : "This field is required",
36033     /**
36034      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36035      * If available, this function will be called only after the basic validators all return true, and will be passed the
36036      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36037      */
36038     validator : null,
36039     /**
36040      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36041      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36042      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
36043      */
36044     regex : null,
36045     /**
36046      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36047      */
36048     regexText : "",
36049     /**
36050      * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36051      */
36052     emptyText : null,
36053     /**
36054      * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36055      * 'x-form-empty-field').  This class is automatically added and removed as needed depending on the current field value.
36056      */
36057     emptyClass : 'x-form-empty-field',
36058
36059     // private
36060     initEvents : function(){
36061         Roo.form.TextField.superclass.initEvents.call(this);
36062         if(this.validationEvent == 'keyup'){
36063             this.validationTask = new  Roo.util.DelayedTask(this.validate, this);
36064             this.el.on('keyup', this.filterValidation, this);
36065         }
36066         else  if(this.validationEvent !== false){
36067             this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36068         }
36069         if(this.selectOnFocus || this.emptyText){
36070             this.on("focus", this.preFocus, this);
36071             if(this.emptyText){
36072                 this.on('blur', this.postBlur, this);
36073                 this.applyEmptyText();
36074             }
36075         }
36076         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36077             this.el.on("keypress", this.filterKeys, this);
36078         }
36079         if(this.grow){
36080             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
36081             this.el.on("click", this.autoSize,  this);
36082         }
36083     },
36084
36085     processValue : function(B){
36086         if(this.stripCharsRe){
36087             var  newValue = B.replace(this.stripCharsRe, '');
36088             if(newValue !== B){
36089                 this.setRawValue(newValue);
36090                 return  newValue;
36091             }
36092         }
36093         return  B;
36094     },
36095
36096     filterValidation : function(e){
36097         if(!e.isNavKeyPress()){
36098             this.validationTask.delay(this.validationDelay);
36099         }
36100     },
36101
36102     // private
36103     onKeyUp : function(e){
36104         if(!e.isNavKeyPress()){
36105             this.autoSize();
36106         }
36107     },
36108
36109     /**
36110      * Resets the current field value to the originally-loaded value and clears any validation messages.
36111      * Also adds emptyText and emptyClass if the original value was blank.
36112      */
36113     reset : function(){
36114         Roo.form.TextField.superclass.reset.call(this);
36115         this.applyEmptyText();
36116     },
36117
36118     applyEmptyText : function(){
36119         if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36120             this.setRawValue(this.emptyText);
36121             this.el.addClass(this.emptyClass);
36122         }
36123     },
36124
36125     // private
36126     preFocus : function(){
36127         if(this.emptyText){
36128             if(this.el.dom.value == this.emptyText){
36129                 this.setRawValue('');
36130             }
36131
36132             this.el.removeClass(this.emptyClass);
36133         }
36134         if(this.selectOnFocus){
36135             this.el.dom.select();
36136         }
36137     },
36138
36139     // private
36140     postBlur : function(){
36141         this.applyEmptyText();
36142     },
36143
36144     // private
36145     filterKeys : function(e){
36146         var  k = e.getKey();
36147         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE  && e.button == -1))){
36148             return;
36149         }
36150         var  c = e.getCharCode(), cc = String.fromCharCode(c);
36151         if(Roo.isIE && (e.isSpecialKey() || !cc)){
36152             return;
36153         }
36154         if(!this.maskRe.test(cc)){
36155             e.stopEvent();
36156         }
36157     },
36158
36159     setValue : function(v){
36160         if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36161             this.el.removeClass(this.emptyClass);
36162         }
36163
36164         Roo.form.TextField.superclass.setValue.apply(this, arguments);
36165         this.applyEmptyText();
36166         this.autoSize();
36167     },
36168
36169     /**
36170      * Validates a value according to the field's validation rules and marks the field as invalid
36171      * if the validation fails
36172      * @param {Mixed} value The value to validate
36173      * @return {Boolean} True if the value is valid, else false
36174      */
36175     validateValue : function(C){
36176         if(C.length < 1 || C === this.emptyText){ // if it's blank
36177              if(this.allowBlank){
36178                 this.clearInvalid();
36179                 return  true;
36180              }else {
36181                 this.markInvalid(this.blankText);
36182                 return  false;
36183              }
36184         }
36185         if(C.length < this.minLength){
36186             this.markInvalid(String.format(this.minLengthText, this.minLength));
36187             return  false;
36188         }
36189         if(C.length > this.maxLength){
36190             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36191             return  false;
36192         }
36193         if(this.vtype){
36194             var  vt = Roo.form.VTypes;
36195             if(!vt[this.vtype](C, this)){
36196                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36197                 return  false;
36198             }
36199         }
36200         if(typeof  this.validator == "function"){
36201             var  msg = this.validator(C);
36202             if(msg !== true){
36203                 this.markInvalid(msg);
36204                 return  false;
36205             }
36206         }
36207         if(this.regex && !this.regex.test(C)){
36208             this.markInvalid(this.regexText);
36209             return  false;
36210         }
36211         return  true;
36212     },
36213
36214     /**
36215      * Selects text in this field
36216      * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36217      * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36218      */
36219     selectText : function(D, E){
36220         var  v = this.getRawValue();
36221         if(v.length > 0){
36222             D = D === undefined ? 0 : D;
36223             E = E === undefined ? v.length : E;
36224             var  d = this.el.dom;
36225             if(d.setSelectionRange){
36226                 d.setSelectionRange(D, E);
36227             }else  if(d.createTextRange){
36228                 var  range = d.createTextRange();
36229                 range.moveStart("character", D);
36230                 range.moveEnd("character", v.length-E);
36231                 range.select();
36232             }
36233         }
36234     },
36235
36236     /**
36237      * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36238      * This only takes effect if grow = true, and fires the autosize event.
36239      */
36240     autoSize : function(){
36241         if(!this.grow || !this.rendered){
36242             return;
36243         }
36244         if(!this.metrics){
36245             this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36246         }
36247         var  el = this.el;
36248         var  v = el.dom.value;
36249         var  d = document.createElement('div');
36250         d.appendChild(document.createTextNode(v));
36251         v = d.innerHTML;
36252         d = null;
36253         v += "&#160;";
36254         var  w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36255         this.el.setWidth(w);
36256         this.fireEvent("autosize", this, w);
36257     }
36258 });
36259 /*
36260  * Based on:
36261  * Ext JS Library 1.1.1
36262  * Copyright(c) 2006-2007, Ext JS, LLC.
36263  *
36264  * Originally Released Under LGPL - original licence link has changed is not relivant.
36265  *
36266  * Fork - LGPL
36267  * <script type="text/javascript">
36268  */
36269  
36270 /**
36271  * @class Roo.form.Hidden
36272  * @extends Roo.form.TextField
36273  * Simple Hidden element used on forms 
36274  * 
36275  * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36276  * 
36277  * @constructor
36278  * Creates a new Hidden form element.
36279  * @param {Object} config Configuration options
36280  */
36281
36282
36283
36284 // easy hidden field...
36285 Roo.form.Hidden = function(A){
36286     Roo.form.Hidden.superclass.constructor.call(this, A);
36287 };
36288   
36289 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36290     fieldLabel:      '',
36291     inputType:      'hidden',
36292     width:          50,
36293     allowBlank:     true,
36294     labelSeparator: '',
36295     hidden:         true,
36296     itemCls :       'x-form-item-display-none'
36297
36298
36299 });
36300
36301
36302
36303 /*
36304  * Based on:
36305  * Ext JS Library 1.1.1
36306  * Copyright(c) 2006-2007, Ext JS, LLC.
36307  *
36308  * Originally Released Under LGPL - original licence link has changed is not relivant.
36309  *
36310  * Fork - LGPL
36311  * <script type="text/javascript">
36312  */
36313  
36314 /**
36315  * @class Roo.form.TriggerField
36316  * @extends Roo.form.TextField
36317  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36318  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36319  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36320  * for which you can provide a custom implementation.  For example:
36321  * <pre><code>
36322 var trigger = new Roo.form.TriggerField();
36323 trigger.onTriggerClick = myTriggerFn;
36324 trigger.applyTo('my-field');
36325 </code></pre>
36326  *
36327  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36328  * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36329  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
36330  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36331  * @constructor
36332  * Create a new TriggerField.
36333  * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36334  * to the base TextField)
36335  */
36336 Roo.form.TriggerField = function(A){
36337     this.mimicing = false;
36338     Roo.form.TriggerField.superclass.constructor.call(this, A);
36339 };
36340
36341 Roo.extend(Roo.form.TriggerField, Roo.form.TextField,  {
36342     /**
36343      * @cfg {String} triggerClass A CSS class to apply to the trigger
36344      */
36345     /**
36346      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36347      * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36348      */
36349     defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36350     /**
36351      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36352      */
36353     hideTrigger:false,
36354
36355     /** @cfg {Boolean} grow @hide */
36356     /** @cfg {Number} growMin @hide */
36357     /** @cfg {Number} growMax @hide */
36358
36359     /**
36360      * @hide 
36361      * @method
36362      */
36363     autoSize: Roo.emptyFn,
36364     // private
36365     monitorTab : true,
36366     // private
36367     deferHeight : true,
36368
36369     
36370     actionMode : 'wrap',
36371     // private
36372     onResize : function(w, h){
36373         Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36374         if(typeof  w == 'number'){
36375             this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
36376         }
36377     },
36378
36379     // private
36380     adjustSize : Roo.BoxComponent.prototype.adjustSize,
36381
36382     // private
36383     getResizeEl : function(){
36384         return  this.wrap;
36385     },
36386
36387     // private
36388     getPositionEl : function(){
36389         return  this.wrap;
36390     },
36391
36392     // private
36393     alignErrorIcon : function(){
36394         this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36395     },
36396
36397     // private
36398     onRender : function(ct, B){
36399         Roo.form.TriggerField.superclass.onRender.call(this, ct, B);
36400         this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36401         this.trigger = this.wrap.createChild(this.triggerConfig ||
36402                 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36403         if(this.hideTrigger){
36404             this.trigger.setDisplayed(false);
36405         }
36406
36407         this.initTrigger();
36408         if(!this.width){
36409             this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36410         }
36411     },
36412
36413     // private
36414     initTrigger : function(){
36415         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36416         this.trigger.addClassOnOver('x-form-trigger-over');
36417         this.trigger.addClassOnClick('x-form-trigger-click');
36418     },
36419
36420     // private
36421     onDestroy : function(){
36422         if(this.trigger){
36423             this.trigger.removeAllListeners();
36424             this.trigger.remove();
36425         }
36426         if(this.wrap){
36427             this.wrap.remove();
36428         }
36429
36430         Roo.form.TriggerField.superclass.onDestroy.call(this);
36431     },
36432
36433     // private
36434     onFocus : function(){
36435         Roo.form.TriggerField.superclass.onFocus.call(this);
36436         if(!this.mimicing){
36437             this.wrap.addClass('x-trigger-wrap-focus');
36438             this.mimicing = true;
36439             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36440             if(this.monitorTab){
36441                 this.el.on("keydown", this.checkTab, this);
36442             }
36443         }
36444     },
36445
36446     // private
36447     checkTab : function(e){
36448         if(e.getKey() == e.TAB){
36449             this.triggerBlur();
36450         }
36451     },
36452
36453     // private
36454     onBlur : function(){
36455         // do nothing
36456     },
36457
36458     // private
36459     mimicBlur : function(e, t){
36460         if(!this.wrap.contains(t) && this.validateBlur()){
36461             this.triggerBlur();
36462         }
36463     },
36464
36465     // private
36466     triggerBlur : function(){
36467         this.mimicing = false;
36468         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36469         if(this.monitorTab){
36470             this.el.un("keydown", this.checkTab, this);
36471         }
36472
36473         this.wrap.removeClass('x-trigger-wrap-focus');
36474         Roo.form.TriggerField.superclass.onBlur.call(this);
36475     },
36476
36477     // private
36478     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36479     validateBlur : function(e, t){
36480         return  true;
36481     },
36482
36483     // private
36484     onDisable : function(){
36485         Roo.form.TriggerField.superclass.onDisable.call(this);
36486         if(this.wrap){
36487             this.wrap.addClass('x-item-disabled');
36488         }
36489     },
36490
36491     // private
36492     onEnable : function(){
36493         Roo.form.TriggerField.superclass.onEnable.call(this);
36494         if(this.wrap){
36495             this.wrap.removeClass('x-item-disabled');
36496         }
36497     },
36498
36499     // private
36500     onShow : function(){
36501         var  ae = this.getActionEl();
36502         
36503         if(ae){
36504             ae.dom.style.display = '';
36505             ae.dom.style.visibility = 'visible';
36506         }
36507     },
36508
36509     // private
36510     
36511     onHide : function(){
36512         var  ae = this.getActionEl();
36513         ae.dom.style.display = 'none';
36514     },
36515
36516     /**
36517      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
36518      * by an implementing function.
36519      * @method
36520      * @param {EventObject} e
36521      */
36522     onTriggerClick : Roo.emptyFn
36523 });
36524
36525 // TwinTriggerField is not a public class to be used directly.  It is meant as an abstract base class
36526 // to be extended by an implementing class.  For an example of implementing this class, see the custom
36527 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36528 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36529     initComponent : function(){
36530         Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36531
36532         this.triggerConfig = {
36533             tag:'span', cls:'x-form-twin-triggers', cn:[
36534             {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36535             {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36536         ]};
36537     },
36538
36539     getTrigger : function(C){
36540         return  this.triggers[C];
36541     },
36542
36543     initTrigger : function(){
36544         var  ts = this.trigger.select('.x-form-trigger', true);
36545         this.wrap.setStyle('overflow', 'hidden');
36546         var  D = this;
36547         ts.each(function(t, E, F){
36548             t.hide = function(){
36549                 var  w = D.wrap.getWidth();
36550                 this.dom.style.display = 'none';
36551                 D.el.setWidth(w-D.trigger.getWidth());
36552             };
36553             t.show = function(){
36554                 var  w = D.wrap.getWidth();
36555                 this.dom.style.display = '';
36556                 D.el.setWidth(w-D.trigger.getWidth());
36557             };
36558             var  G = 'Trigger'+(F+1);
36559
36560             if(this['hide'+G]){
36561                 t.dom.style.display = 'none';
36562             }
36563
36564             t.on("click", this['on'+G+'Click'], this, {preventDefault:true});
36565             t.addClassOnOver('x-form-trigger-over');
36566             t.addClassOnClick('x-form-trigger-click');
36567         }, this);
36568         this.triggers = ts.elements;
36569     },
36570
36571     onTrigger1Click : Roo.emptyFn,
36572     onTrigger2Click : Roo.emptyFn
36573 });
36574 /*
36575  * Based on:
36576  * Ext JS Library 1.1.1
36577  * Copyright(c) 2006-2007, Ext JS, LLC.
36578  *
36579  * Originally Released Under LGPL - original licence link has changed is not relivant.
36580  *
36581  * Fork - LGPL
36582  * <script type="text/javascript">
36583  */
36584  
36585 /**
36586  * @class Roo.form.TextArea
36587  * @extends Roo.form.TextField
36588  * Multiline text field.  Can be used as a direct replacement for traditional textarea fields, plus adds
36589  * support for auto-sizing.
36590  * @constructor
36591  * Creates a new TextArea
36592  * @param {Object} config Configuration options
36593  */
36594 Roo.form.TextArea = function(A){
36595     Roo.form.TextArea.superclass.constructor.call(this, A);
36596     // these are provided exchanges for backwards compat
36597     // minHeight/maxHeight were replaced by growMin/growMax to be
36598     // compatible with TextField growing config values
36599     if(this.minHeight !== undefined){
36600         this.growMin = this.minHeight;
36601     }
36602     if(this.maxHeight !== undefined){
36603         this.growMax = this.maxHeight;
36604     }
36605 };
36606
36607 Roo.extend(Roo.form.TextArea, Roo.form.TextField,  {
36608     /**
36609      * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36610      */
36611     growMin : 60,
36612     /**
36613      * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36614      */
36615     growMax: 1000,
36616     /**
36617      * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36618      * in the field (equivalent to setting overflow: hidden, defaults to false)
36619      */
36620     preventScrollbars: false,
36621     /**
36622      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36623      * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36624      */
36625
36626     // private
36627     onRender : function(ct, B){
36628         if(!this.el){
36629             this.defaultAutoCreate = {
36630                 tag: "textarea",
36631                 style:"width:300px;height:60px;",
36632                 autocomplete: "off"
36633             };
36634         }
36635
36636         Roo.form.TextArea.superclass.onRender.call(this, ct, B);
36637         if(this.grow){
36638             this.textSizeEl = Roo.DomHelper.append(document.body, {
36639                 tag: "pre", cls: "x-form-grow-sizer"
36640             });
36641             if(this.preventScrollbars){
36642                 this.el.setStyle("overflow", "hidden");
36643             }
36644
36645             this.el.setHeight(this.growMin);
36646         }
36647     },
36648
36649     onDestroy : function(){
36650         if(this.textSizeEl){
36651             this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36652         }
36653
36654         Roo.form.TextArea.superclass.onDestroy.call(this);
36655     },
36656
36657     // private
36658     onKeyUp : function(e){
36659         if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36660             this.autoSize();
36661         }
36662     },
36663
36664     /**
36665      * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36666      * This only takes effect if grow = true, and fires the autosize event if the height changes.
36667      */
36668     autoSize : function(){
36669         if(!this.grow || !this.textSizeEl){
36670             return;
36671         }
36672         var  el = this.el;
36673         var  v = el.dom.value;
36674         var  ts = this.textSizeEl;
36675
36676         ts.innerHTML = '';
36677         ts.appendChild(document.createTextNode(v));
36678         v = ts.innerHTML;
36679
36680         Roo.fly(ts).setWidth(this.el.getWidth());
36681         if(v.length < 1){
36682             v = "&#160;&#160;";
36683         }else {
36684             if(Roo.isIE){
36685                 v = v.replace(/\n/g, '<p>&#160;</p>');
36686             }
36687
36688             v += "&#160;\n&#160;";
36689         }
36690
36691         ts.innerHTML = v;
36692         var  h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36693         if(h != this.lastHeight){
36694             this.lastHeight = h;
36695             this.el.setHeight(h);
36696             this.fireEvent("autosize", this, h);
36697         }
36698     }
36699 });
36700 /*
36701  * Based on:
36702  * Ext JS Library 1.1.1
36703  * Copyright(c) 2006-2007, Ext JS, LLC.
36704  *
36705  * Originally Released Under LGPL - original licence link has changed is not relivant.
36706  *
36707  * Fork - LGPL
36708  * <script type="text/javascript">
36709  */
36710  
36711
36712 /**
36713  * @class Roo.form.NumberField
36714  * @extends Roo.form.TextField
36715  * Numeric text field that provides automatic keystroke filtering and numeric validation.
36716  * @constructor
36717  * Creates a new NumberField
36718  * @param {Object} config Configuration options
36719  */
36720 Roo.form.NumberField = function(A){
36721     Roo.form.NumberField.superclass.constructor.call(this, A);
36722 };
36723
36724 Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
36725     /**
36726      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36727      */
36728     fieldClass: "x-form-field x-form-num-field",
36729     /**
36730      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36731      */
36732     allowDecimals : true,
36733     /**
36734      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36735      */
36736     decimalSeparator : ".",
36737     /**
36738      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36739      */
36740     decimalPrecision : 2,
36741     /**
36742      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36743      */
36744     allowNegative : true,
36745     /**
36746      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36747      */
36748     minValue : Number.NEGATIVE_INFINITY,
36749     /**
36750      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36751      */
36752     maxValue : Number.MAX_VALUE,
36753     /**
36754      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36755      */
36756     minText : "The minimum value for this field is {0}",
36757     /**
36758      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36759      */
36760     maxText : "The maximum value for this field is {0}",
36761     /**
36762      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
36763      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36764      */
36765     nanText : "{0} is not a valid number",
36766
36767     // private
36768     initEvents : function(){
36769         Roo.form.NumberField.superclass.initEvents.call(this);
36770         var  B = "0123456789";
36771         if(this.allowDecimals){
36772             B += this.decimalSeparator;
36773         }
36774         if(this.allowNegative){
36775             B += "-";
36776         }
36777
36778         this.stripCharsRe = new  RegExp('[^'+B+']', 'gi');
36779         var  C = function(e){
36780             var  k = e.getKey();
36781             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE )){
36782                 return;
36783             }
36784             var  c = e.getCharCode();
36785             if(B.indexOf(String.fromCharCode(c)) === -1){
36786                 e.stopEvent();
36787             }
36788         };
36789         this.el.on("keypress", C, this);
36790     },
36791
36792     // private
36793     validateValue : function(D){
36794         if(!Roo.form.NumberField.superclass.validateValue.call(this, D)){
36795             return  false;
36796         }
36797         if(D.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36798              return  true;
36799         }
36800         var  E = this.parseValue(D);
36801         if(isNaN(E)){
36802             this.markInvalid(String.format(this.nanText, D));
36803             return  false;
36804         }
36805         if(E < this.minValue){
36806             this.markInvalid(String.format(this.minText, this.minValue));
36807             return  false;
36808         }
36809         if(E > this.maxValue){
36810             this.markInvalid(String.format(this.maxText, this.maxValue));
36811             return  false;
36812         }
36813         return  true;
36814     },
36815
36816     getValue : function(){
36817         return  this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36818     },
36819
36820     // private
36821     parseValue : function(F){
36822         F = parseFloat(String(F).replace(this.decimalSeparator, "."));
36823         return  isNaN(F) ? '' : F;
36824     },
36825
36826     // private
36827     fixPrecision : function(G){
36828         var  H = isNaN(G);
36829         if(!this.allowDecimals || this.decimalPrecision == -1 || H || !G){
36830             return  H ? '' : G;
36831         }
36832         return  parseFloat(G).toFixed(this.decimalPrecision);
36833     },
36834
36835     setValue : function(v){
36836         Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36837     },
36838
36839     // private
36840     decimalPrecisionFcn : function(v){
36841         return  Math.floor(v);
36842     },
36843
36844     beforeBlur : function(){
36845         var  v = this.parseValue(this.getRawValue());
36846         if(v){
36847             this.setValue(this.fixPrecision(v));
36848         }
36849     }
36850 });
36851 /*
36852  * Based on:
36853  * Ext JS Library 1.1.1
36854  * Copyright(c) 2006-2007, Ext JS, LLC.
36855  *
36856  * Originally Released Under LGPL - original licence link has changed is not relivant.
36857  *
36858  * Fork - LGPL
36859  * <script type="text/javascript">
36860  */
36861  
36862 /**
36863  * @class Roo.form.DateField
36864  * @extends Roo.form.TriggerField
36865  * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36866 * @constructor
36867 * Create a new DateField
36868 * @param {Object} config
36869  */
36870 Roo.form.DateField = function(A){
36871     Roo.form.DateField.superclass.constructor.call(this, A);
36872     
36873       this.addEvents({
36874          
36875         /**
36876          * @event select
36877          * Fires when a date is selected
36878              * @param {Roo.form.DateField} combo This combo box
36879              * @param {Date} date The date selected
36880              */
36881         'select' : true
36882          
36883     });
36884     
36885     
36886     if(typeof  this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36887     if(typeof  this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36888     this.ddMatch = null;
36889     if(this.disabledDates){
36890         var  dd = this.disabledDates;
36891         var  re = "(?:";
36892         for(var  i = 0; i < dd.length; i++){
36893             re += dd[i];
36894             if(i != dd.length-1) re += "|";
36895         }
36896
36897         this.ddMatch = new  RegExp(re + ")");
36898     }
36899 };
36900
36901 Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
36902     /**
36903      * @cfg {String} format
36904      * The default date format string which can be overriden for localization support.  The format must be
36905      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36906      */
36907     format : "m/d/y",
36908     /**
36909      * @cfg {String} altFormats
36910      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36911      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36912      */
36913     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36914     /**
36915      * @cfg {Array} disabledDays
36916      * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36917      */
36918     disabledDays : null,
36919     /**
36920      * @cfg {String} disabledDaysText
36921      * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36922      */
36923     disabledDaysText : "Disabled",
36924     /**
36925      * @cfg {Array} disabledDates
36926      * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36927      * expression so they are very powerful. Some examples:
36928      * <ul>
36929      * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36930      * <li>["03/08", "09/16"] would disable those days for every year</li>
36931      * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36932      * <li>["03/../2006"] would disable every day in March 2006</li>
36933      * <li>["^03"] would disable every day in every March</li>
36934      * </ul>
36935      * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36936      * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36937      */
36938     disabledDates : null,
36939     /**
36940      * @cfg {String} disabledDatesText
36941      * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36942      */
36943     disabledDatesText : "Disabled",
36944     /**
36945      * @cfg {Date/String} minValue
36946      * The minimum allowed date. Can be either a Javascript date object or a string date in a
36947      * valid format (defaults to null).
36948      */
36949     minValue : null,
36950     /**
36951      * @cfg {Date/String} maxValue
36952      * The maximum allowed date. Can be either a Javascript date object or a string date in a
36953      * valid format (defaults to null).
36954      */
36955     maxValue : null,
36956     /**
36957      * @cfg {String} minText
36958      * The error text to display when the date in the cell is before minValue (defaults to
36959      * 'The date in this field must be after {minValue}').
36960      */
36961     minText : "The date in this field must be equal to or after {0}",
36962     /**
36963      * @cfg {String} maxText
36964      * The error text to display when the date in the cell is after maxValue (defaults to
36965      * 'The date in this field must be before {maxValue}').
36966      */
36967     maxText : "The date in this field must be equal to or before {0}",
36968     /**
36969      * @cfg {String} invalidText
36970      * The error text to display when the date in the field is invalid (defaults to
36971      * '{value} is not a valid date - it must be in the format {format}').
36972      */
36973     invalidText : "{0} is not a valid date - it must be in the format {1}",
36974     /**
36975      * @cfg {String} triggerClass
36976      * An additional CSS class used to style the trigger button.  The trigger will always get the
36977      * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36978      * which displays a calendar icon).
36979      */
36980     triggerClass : 'x-form-date-trigger',
36981     
36982
36983     /**
36984      * @cfg {bool} useIso
36985      * if enabled, then the date field will use a hidden field to store the 
36986      * real value as iso formated date. default (false)
36987      */ 
36988     useIso : false,
36989     /**
36990      * @cfg {String/Object} autoCreate
36991      * A DomHelper element spec, or true for a default element spec (defaults to
36992      * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36993      */ 
36994     // private
36995     defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36996     
36997     // private
36998     hiddenField: false,
36999     
37000     onRender : function(ct, B)
37001     {
37002         Roo.form.DateField.superclass.onRender.call(this, ct, B);
37003         if (this.useIso) {
37004             this.el.dom.removeAttribute('name'); 
37005             this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37006                     'before', true);
37007             this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37008             // prevent input submission
37009             this.hiddenName = this.name;
37010         }
37011             
37012             
37013     },
37014     
37015     // private
37016     validateValue : function(C)
37017     {
37018         C = this.formatDate(C);
37019         if(!Roo.form.DateField.superclass.validateValue.call(this, C)){
37020             return  false;
37021         }
37022         if(C.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37023              return  true;
37024         }
37025         var  D = C;
37026         C = this.parseDate(C);
37027         if(!C){
37028             this.markInvalid(String.format(this.invalidText, D, this.format));
37029             return  false;
37030         }
37031         var  E = C.getTime();
37032         if(this.minValue && E < this.minValue.getTime()){
37033             this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37034             return  false;
37035         }
37036         if(this.maxValue && E > this.maxValue.getTime()){
37037             this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37038             return  false;
37039         }
37040         if(this.disabledDays){
37041             var  day = C.getDay();
37042             for(var  i = 0; i < this.disabledDays.length; i++) {
37043                 if(day === this.disabledDays[i]){
37044                     this.markInvalid(this.disabledDaysText);
37045                     return  false;
37046                 }
37047             }
37048         }
37049         var  F = this.formatDate(C);
37050         if(this.ddMatch && this.ddMatch.test(F)){
37051             this.markInvalid(String.format(this.disabledDatesText, F));
37052             return  false;
37053         }
37054         return  true;
37055     },
37056
37057     // private
37058     // Provides logic to override the default TriggerField.validateBlur which just returns true
37059     validateBlur : function(){
37060         return  !this.menu || !this.menu.isVisible();
37061     },
37062
37063     /**
37064      * Returns the current date value of the date field.
37065      * @return {Date} The date value
37066      */
37067     getValue : function(){
37068         
37069         return   this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37070     },
37071
37072     /**
37073      * Sets the value of the date field.  You can pass a date object or any string that can be parsed into a valid
37074      * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37075      * (the default format used is "m/d/y").
37076      * <br />Usage:
37077      * <pre><code>
37078 //All of these calls set the same date value (May 4, 2006)
37079
37080 //Pass a date object:
37081 var dt = new Date('5/4/06');
37082 dateField.setValue(dt);
37083
37084 //Pass a date string (default format):
37085 dateField.setValue('5/4/06');
37086
37087 //Pass a date string (custom format):
37088 dateField.format = 'Y-m-d';
37089 dateField.setValue('2006-5-4');
37090 </code></pre>
37091      * @param {String/Date} date The date or valid date string
37092      */
37093     setValue : function(G){
37094         if (this.hiddenField) {
37095             this.hiddenField.value = this.formatDate(this.parseDate(G), 'Y-m-d');
37096         }
37097
37098         Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(G)));
37099     },
37100
37101     // private
37102     parseDate : function(H){
37103         if(!H || H  instanceof  Date){
37104             return  H;
37105         }
37106         var  v = Date.parseDate(H, this.format);
37107         if(!v && this.altFormats){
37108             if(!this.altFormatsArray){
37109                 this.altFormatsArray = this.altFormats.split("|");
37110             }
37111             for(var  i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37112                 v = Date.parseDate(H, this.altFormatsArray[i]);
37113             }
37114         }
37115         return  v;
37116     },
37117
37118     // private
37119     formatDate : function(I, J){
37120         return  (!I || !(I  instanceof  Date)) ?
37121                I : I.dateFormat(J || this.format);
37122     },
37123
37124     // private
37125     menuListeners : {
37126         select: function(m, d){
37127             this.setValue(d);
37128             this.fireEvent('select', this, d);
37129         },
37130         show : function(){ // retain focus styling
37131             this.onFocus();
37132         },
37133         hide : function(){
37134             this.focus.defer(10, this);
37135             var  ml = this.menuListeners;
37136             this.menu.un("select", ml.select,  this);
37137             this.menu.un("show", ml.show,  this);
37138             this.menu.un("hide", ml.hide,  this);
37139         }
37140     },
37141
37142     // private
37143     // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37144     onTriggerClick : function(){
37145         if(this.disabled){
37146             return;
37147         }
37148         if(this.menu == null){
37149             this.menu = new  Roo.menu.DateMenu();
37150         }
37151
37152         Roo.apply(this.menu.picker,  {
37153             showClear: this.allowBlank,
37154             minDate : this.minValue,
37155             maxDate : this.maxValue,
37156             disabledDatesRE : this.ddMatch,
37157             disabledDatesText : this.disabledDatesText,
37158             disabledDays : this.disabledDays,
37159             disabledDaysText : this.disabledDaysText,
37160             format : this.format,
37161             minText : String.format(this.minText, this.formatDate(this.minValue)),
37162             maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37163         });
37164         this.menu.on(Roo.apply({}, this.menuListeners, {
37165             scope:this
37166         }));
37167         this.menu.picker.setValue(this.getValue() || new  Date());
37168         this.menu.show(this.el, "tl-bl?");
37169     },
37170
37171     beforeBlur : function(){
37172         var  v = this.parseDate(this.getRawValue());
37173         if(v){
37174             this.setValue(v);
37175         }
37176     }
37177
37178     /** @cfg {Boolean} grow @hide */
37179     /** @cfg {Number} growMin @hide */
37180     /** @cfg {Number} growMax @hide */
37181     /**
37182      * @hide
37183      * @method autoSize
37184      */
37185 });
37186 /*
37187  * Based on:
37188  * Ext JS Library 1.1.1
37189  * Copyright(c) 2006-2007, Ext JS, LLC.
37190  *
37191  * Originally Released Under LGPL - original licence link has changed is not relivant.
37192  *
37193  * Fork - LGPL
37194  * <script type="text/javascript">
37195  */
37196  
37197
37198 /**
37199  * @class Roo.form.ComboBox
37200  * @extends Roo.form.TriggerField
37201  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37202  * @constructor
37203  * Create a new ComboBox.
37204  * @param {Object} config Configuration options
37205  */
37206 Roo.form.ComboBox = function(A){
37207     Roo.form.ComboBox.superclass.constructor.call(this, A);
37208     this.addEvents({
37209         /**
37210          * @event expand
37211          * Fires when the dropdown list is expanded
37212              * @param {Roo.form.ComboBox} combo This combo box
37213              */
37214         'expand' : true,
37215         /**
37216          * @event collapse
37217          * Fires when the dropdown list is collapsed
37218              * @param {Roo.form.ComboBox} combo This combo box
37219              */
37220         'collapse' : true,
37221         /**
37222          * @event beforeselect
37223          * Fires before a list item is selected. Return false to cancel the selection.
37224              * @param {Roo.form.ComboBox} combo This combo box
37225              * @param {Roo.data.Record} record The data record returned from the underlying store
37226              * @param {Number} index The index of the selected item in the dropdown list
37227              */
37228         'beforeselect' : true,
37229         /**
37230          * @event select
37231          * Fires when a list item is selected
37232              * @param {Roo.form.ComboBox} combo This combo box
37233              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37234              * @param {Number} index The index of the selected item in the dropdown list
37235              */
37236         'select' : true,
37237         /**
37238          * @event beforequery
37239          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37240          * The event object passed has these properties:
37241              * @param {Roo.form.ComboBox} combo This combo box
37242              * @param {String} query The query
37243              * @param {Boolean} forceAll true to force "all" query
37244              * @param {Boolean} cancel true to cancel the query
37245              * @param {Object} e The query event object
37246              */
37247         'beforequery': true
37248     });
37249     if(this.transform){
37250         this.allowDomMove = false;
37251         var  s = Roo.getDom(this.transform);
37252         if(!this.hiddenName){
37253             this.hiddenName = s.name;
37254         }
37255         if(!this.store){
37256             this.mode = 'local';
37257             var  d = [], opts = s.options;
37258             for(var  i = 0, len = opts.length;i < len; i++){
37259                 var  o = opts[i];
37260                 var  value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37261                 if(o.selected) {
37262                     this.value = value;
37263                 }
37264
37265                 d.push([value, o.text]);
37266             }
37267
37268             this.store = new  Roo.data.SimpleStore({
37269                 'id': 0,
37270                 fields: ['value', 'text'],
37271                 data : d
37272             });
37273             this.valueField = 'value';
37274             this.displayField = 'text';
37275         }
37276
37277         s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37278         if(!this.lazyRender){
37279             this.target = true;
37280             this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37281             s.parentNode.removeChild(s); // remove it
37282             this.render(this.el.parentNode);
37283         }else {
37284             s.parentNode.removeChild(s); // remove it
37285         }
37286
37287     }
37288     if (this.store) {
37289         this.store = Roo.factory(this.store, Roo.data);
37290     }
37291
37292     
37293     this.selectedIndex = -1;
37294     if(this.mode == 'local'){
37295         if(A.queryDelay === undefined){
37296             this.queryDelay = 10;
37297         }
37298         if(A.minChars === undefined){
37299             this.minChars = 0;
37300         }
37301     }
37302 };
37303
37304 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37305     /**
37306      * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37307      */
37308     /**
37309      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37310      * rendering into an Roo.Editor, defaults to false)
37311      */
37312     /**
37313      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37314      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37315      */
37316     /**
37317      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37318      */
37319     /**
37320      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37321      * the dropdown list (defaults to undefined, with no header element)
37322      */
37323
37324      /**
37325      * @cfg {String/Roo.Template} tpl The template to use to render the output
37326      */
37327      
37328     // private
37329     defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37330     /**
37331      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37332      */
37333     listWidth: undefined,
37334     /**
37335      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37336      * mode = 'remote' or 'text' if mode = 'local')
37337      */
37338     displayField: undefined,
37339     /**
37340      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37341      * mode = 'remote' or 'value' if mode = 'local'). 
37342      * Note: use of a valueField requires the user make a selection
37343      * in order for a value to be mapped.
37344      */
37345     valueField: undefined,
37346     /**
37347      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37348      * field's data value (defaults to the underlying DOM element's name)
37349      */
37350     hiddenName: undefined,
37351     /**
37352      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37353      */
37354     listClass: '',
37355     /**
37356      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37357      */
37358     selectedClass: 'x-combo-selected',
37359     /**
37360      * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
37361      * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37362      * which displays a downward arrow icon).
37363      */
37364     triggerClass : 'x-form-arrow-trigger',
37365     /**
37366      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37367      */
37368     shadow:'sides',
37369     /**
37370      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37371      * anchor positions (defaults to 'tl-bl')
37372      */
37373     listAlign: 'tl-bl?',
37374     /**
37375      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37376      */
37377     maxHeight: 300,
37378     /**
37379      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
37380      * query specified by the allQuery config option (defaults to 'query')
37381      */
37382     triggerAction: 'query',
37383     /**
37384      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37385      * (defaults to 4, does not apply if editable = false)
37386      */
37387     minChars : 4,
37388     /**
37389      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37390      * delay (typeAheadDelay) if it matches a known value (defaults to false)
37391      */
37392     typeAhead: false,
37393     /**
37394      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37395      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37396      */
37397     queryDelay: 500,
37398     /**
37399      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37400      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
37401      */
37402     pageSize: 0,
37403     /**
37404      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
37405      * when editable = true (defaults to false)
37406      */
37407     selectOnFocus:false,
37408     /**
37409      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37410      */
37411     queryParam: 'query',
37412     /**
37413      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
37414      * when mode = 'remote' (defaults to 'Loading...')
37415      */
37416     loadingText: 'Loading...',
37417     /**
37418      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37419      */
37420     resizable: false,
37421     /**
37422      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37423      */
37424     handleHeight : 8,
37425     /**
37426      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37427      * traditional select (defaults to true)
37428      */
37429     editable: true,
37430     /**
37431      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37432      */
37433     allQuery: '',
37434     /**
37435      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37436      */
37437     mode: 'remote',
37438     /**
37439      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37440      * listWidth has a higher value)
37441      */
37442     minListWidth : 70,
37443     /**
37444      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37445      * allow the user to set arbitrary text into the field (defaults to false)
37446      */
37447     forceSelection:false,
37448     /**
37449      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37450      * if typeAhead = true (defaults to 250)
37451      */
37452     typeAheadDelay : 250,
37453     /**
37454      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37455      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37456      */
37457     valueNotFoundText : undefined,
37458     /**
37459      * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37460      */
37461     blockFocus : false,
37462     
37463     /**
37464      * @cfg {bool} disableClear Disable showing of clear button.
37465      */
37466     disableClear : false,
37467     
37468     // private
37469     onRender : function(ct, B){
37470         Roo.form.ComboBox.superclass.onRender.call(this, ct, B);
37471         if(this.hiddenName){
37472             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
37473                     'before', true);
37474             this.hiddenField.value =
37475                 this.hiddenValue !== undefined ? this.hiddenValue :
37476                 this.value !== undefined ? this.value : '';
37477
37478             // prevent input submission
37479             this.el.dom.removeAttribute('name');
37480         }
37481         if(Roo.isGecko){
37482             this.el.dom.setAttribute('autocomplete', 'off');
37483         }
37484
37485         var  C = 'x-combo-list';
37486
37487         this.list = new  Roo.Layer({
37488             shadow: this.shadow, cls: [C, this.listClass].join(' '), constrain:false
37489         });
37490
37491         var  lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37492         this.list.setWidth(lw);
37493         this.list.swallowEvent('mousewheel');
37494         this.assetHeight = 0;
37495
37496         if(this.title){
37497             this.header = this.list.createChild({cls:C+'-hd', html: this.title});
37498             this.assetHeight += this.header.getHeight();
37499         }
37500
37501
37502         this.innerList = this.list.createChild({cls:C+'-inner'});
37503         this.innerList.on('mouseover', this.onViewOver, this);
37504         this.innerList.on('mousemove', this.onViewMove, this);
37505         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37506         
37507         if(this.allowBlank && !this.pageSize && !this.disableClear){
37508             this.footer = this.list.createChild({cls:C+'-ft'});
37509             this.pageTb = new  Roo.Toolbar(this.footer);
37510            
37511         }
37512         if(this.pageSize){
37513             this.footer = this.list.createChild({cls:C+'-ft'});
37514             this.pageTb = new  Roo.PagingToolbar(this.footer, this.store,
37515                     {pageSize: this.pageSize});
37516             
37517         }
37518         
37519         if (this.pageTb && this.allowBlank && !this.disableClear) {
37520             var  _this = this;
37521             this.pageTb.add(new  Roo.Toolbar.Fill(), {
37522                 cls: 'x-btn-icon x-btn-clear',
37523                 text: '&#160;',
37524                 handler: function()
37525                 {
37526                     _this.collapse();
37527                     _this.clearValue();
37528                     _this.onSelect(false, -1);
37529                 }
37530             });
37531         }
37532         if (this.footer) {
37533             this.assetHeight += this.footer.getHeight();
37534         }
37535         
37536
37537         if(!this.tpl){
37538             this.tpl = '<div class="'+C+'-item">{' + this.displayField + '}</div>';
37539         }
37540
37541
37542         this.view = new  Roo.View(this.innerList, this.tpl, {
37543             singleSelect:true, store: this.store, selectedClass: this.selectedClass
37544         });
37545
37546         this.view.on('click', this.onViewClick, this);
37547
37548         this.store.on('beforeload', this.onBeforeLoad, this);
37549         this.store.on('load', this.onLoad, this);
37550         this.store.on('loadexception', this.collapse, this);
37551
37552         if(this.resizable){
37553             this.resizer = new  Roo.Resizable(this.list,  {
37554                pinned:true, handles:'se'
37555             });
37556             this.resizer.on('resize', function(r, w, h){
37557                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37558                 this.listWidth = w;
37559                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37560                 this.restrictHeight();
37561             }, this);
37562             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37563         }
37564         if(!this.editable){
37565             this.editable = true;
37566             this.setEditable(false);
37567         }
37568     },
37569
37570     // private
37571     initEvents : function(){
37572         Roo.form.ComboBox.superclass.initEvents.call(this);
37573
37574         this.keyNav = new  Roo.KeyNav(this.el, {
37575             "up" : function(e){
37576                 this.inKeyMode = true;
37577                 this.selectPrev();
37578             },
37579
37580             "down" : function(e){
37581                 if(!this.isExpanded()){
37582                     this.onTriggerClick();
37583                 }else {
37584                     this.inKeyMode = true;
37585                     this.selectNext();
37586                 }
37587             },
37588
37589             "enter" : function(e){
37590                 this.onViewClick();
37591                 //return true;
37592             },
37593
37594             "esc" : function(e){
37595                 this.collapse();
37596             },
37597
37598             "tab" : function(e){
37599                 this.onViewClick(false);
37600                 return  true;
37601             },
37602
37603             scope : this,
37604
37605             doRelay : function(D, E, F){
37606                 if(F == 'down' || this.scope.isExpanded()){
37607                    return  Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37608                 }
37609                 return  true;
37610             },
37611
37612             forceKeyDown: true
37613         });
37614         this.queryDelay = Math.max(this.queryDelay || 10,
37615                 this.mode == 'local' ? 10 : 250);
37616         this.dqTask = new  Roo.util.DelayedTask(this.initQuery, this);
37617         if(this.typeAhead){
37618             this.taTask = new  Roo.util.DelayedTask(this.onTypeAhead, this);
37619         }
37620         if(this.editable !== false){
37621             this.el.on("keyup", this.onKeyUp, this);
37622         }
37623         if(this.forceSelection){
37624             this.on('blur', this.doForce, this);
37625         }
37626     },
37627
37628     onDestroy : function(){
37629         if(this.view){
37630             this.view.setStore(null);
37631             this.view.el.removeAllListeners();
37632             this.view.el.remove();
37633             this.view.purgeListeners();
37634         }
37635         if(this.list){
37636             this.list.destroy();
37637         }
37638         if(this.store){
37639             this.store.un('beforeload', this.onBeforeLoad, this);
37640             this.store.un('load', this.onLoad, this);
37641             this.store.un('loadexception', this.collapse, this);
37642         }
37643
37644         Roo.form.ComboBox.superclass.onDestroy.call(this);
37645     },
37646
37647     // private
37648     fireKey : function(e){
37649         if(e.isNavKeyPress() && !this.list.isVisible()){
37650             this.fireEvent("specialkey", this, e);
37651         }
37652     },
37653
37654     // private
37655     onResize: function(w, h){
37656         Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37657         if(this.list && this.listWidth === undefined){
37658             var  lw = Math.max(w, this.minListWidth);
37659             this.list.setWidth(lw);
37660             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37661         }
37662     },
37663
37664     /**
37665      * Allow or prevent the user from directly editing the field text.  If false is passed,
37666      * the user will only be able to select from the items defined in the dropdown list.  This method
37667      * is the runtime equivalent of setting the 'editable' config option at config time.
37668      * @param {Boolean} value True to allow the user to directly edit the field text
37669      */
37670     setEditable : function(D){
37671         if(D == this.editable){
37672             return;
37673         }
37674
37675         this.editable = D;
37676         if(!D){
37677             this.el.dom.setAttribute('readOnly', true);
37678             this.el.on('mousedown', this.onTriggerClick,  this);
37679             this.el.addClass('x-combo-noedit');
37680         }else {
37681             this.el.dom.setAttribute('readOnly', false);
37682             this.el.un('mousedown', this.onTriggerClick,  this);
37683             this.el.removeClass('x-combo-noedit');
37684         }
37685     },
37686
37687     // private
37688     onBeforeLoad : function(){
37689         if(!this.hasFocus){
37690             return;
37691         }
37692
37693         this.innerList.update(this.loadingText ?
37694                '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37695         this.restrictHeight();
37696         this.selectedIndex = -1;
37697     },
37698
37699     // private
37700     onLoad : function(){
37701         if(!this.hasFocus){
37702             return;
37703         }
37704         if(this.store.getCount() > 0){
37705             this.expand();
37706             this.restrictHeight();
37707             if(this.lastQuery == this.allQuery){
37708                 if(this.editable){
37709                     this.el.dom.select();
37710                 }
37711                 if(!this.selectByValue(this.value, true)){
37712                     this.select(0, true);
37713                 }
37714             }else {
37715                 this.selectNext();
37716                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE ){
37717                     this.taTask.delay(this.typeAheadDelay);
37718                 }
37719             }
37720         }else {
37721             this.onEmptyResults();
37722         }
37723         //this.el.focus();
37724     },
37725
37726     // private
37727     onTypeAhead : function(){
37728         if(this.store.getCount() > 0){
37729             var  r = this.store.getAt(0);
37730             var  newValue = r.data[this.displayField];
37731             var  len = newValue.length;
37732             var  selStart = this.getRawValue().length;
37733             if(selStart != len){
37734                 this.setRawValue(newValue);
37735                 this.selectText(selStart, newValue.length);
37736             }
37737         }
37738     },
37739
37740     // private
37741     onSelect : function(E, F){
37742         if(this.fireEvent('beforeselect', this, E, F) !== false){
37743             this.setFromData(F > -1 ? E.data : false);
37744             this.collapse();
37745             this.fireEvent('select', this, E, F);
37746         }
37747     },
37748
37749     /**
37750      * Returns the currently selected field value or empty string if no value is set.
37751      * @return {String} value The selected value
37752      */
37753     getValue : function(){
37754         if(this.valueField){
37755             return  typeof  this.value != 'undefined' ? this.value : '';
37756         }else {
37757             return  Roo.form.ComboBox.superclass.getValue.call(this);
37758         }
37759     },
37760
37761     /**
37762      * Clears any text/value currently set in the field
37763      */
37764     clearValue : function(){
37765         if(this.hiddenField){
37766             this.hiddenField.value = '';
37767         }
37768
37769         this.value = '';
37770         this.setRawValue('');
37771         this.lastSelectionText = '';
37772         this.applyEmptyText();
37773     },
37774
37775     /**
37776      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
37777      * will be displayed in the field.  If the value does not match the data value of an existing item,
37778      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37779      * Otherwise the field will be blank (although the value will still be set).
37780      * @param {String} value The value to match
37781      */
37782     setValue : function(v){
37783         var  G = v;
37784         if(this.valueField){
37785             var  r = this.findRecord(this.valueField, v);
37786             if(r){
37787                 G = r.data[this.displayField];
37788             }else  if(this.valueNotFoundText !== undefined){
37789                 G = this.valueNotFoundText;
37790             }
37791         }
37792
37793         this.lastSelectionText = G;
37794         if(this.hiddenField){
37795             this.hiddenField.value = v;
37796         }
37797
37798         Roo.form.ComboBox.superclass.setValue.call(this, G);
37799         this.value = v;
37800     },
37801     /**
37802      * @property {Object} the last set data for the element
37803      */
37804     
37805     lastData : false,
37806     /**
37807      * Sets the value of the field based on a object which is related to the record format for the store.
37808      * @param {Object} value the value to set as. or false on reset?
37809      */
37810     setFromData : function(o){
37811         var  dv = ''; // display value
37812         var  vv = ''; // value value..
37813         this.lastData = o;
37814         if (this.displayField) {
37815             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37816         } else  {
37817             // this is an error condition!!!
37818             console.log('no value field set for '+ this.name);
37819         }
37820         
37821         if(this.valueField){
37822             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37823         }
37824         if(this.hiddenField){
37825             this.hiddenField.value = vv;
37826             
37827             this.lastSelectionText = dv;
37828             Roo.form.ComboBox.superclass.setValue.call(this, dv);
37829             this.value = vv;
37830             return;
37831         }
37832
37833         // no hidden field.. - we store the value in 'value', but still display
37834         // display field!!!!
37835         this.lastSelectionText = dv;
37836         Roo.form.ComboBox.superclass.setValue.call(this, dv);
37837         this.value = vv;
37838         
37839         
37840     },
37841     // private
37842     findRecord : function(H, I){
37843         var  J;
37844         if(this.store.getCount() > 0){
37845             this.store.each(function(r){
37846                 if(r.data[H] == I){
37847                     J = r;
37848                     return  false;
37849                 }
37850             });
37851         }
37852         return  J;
37853     },
37854
37855     // private
37856     onViewMove : function(e, t){
37857         this.inKeyMode = false;
37858     },
37859
37860     // private
37861     onViewOver : function(e, t){
37862         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37863             return;
37864         }
37865         var  K = this.view.findItemFromChild(t);
37866         if(K){
37867             var  F = this.view.indexOf(K);
37868             this.select(F, false);
37869         }
37870     },
37871
37872     // private
37873     onViewClick : function(L){
37874         var  M = this.view.getSelectedIndexes()[0];
37875         var  r = this.store.getAt(M);
37876         if(r){
37877             this.onSelect(r, M);
37878         }
37879         if(L !== false && !this.blockFocus){
37880             this.el.focus();
37881         }
37882     },
37883
37884     // private
37885     restrictHeight : function(){
37886         this.innerList.dom.style.height = '';
37887         var  N = this.innerList.dom;
37888         var  h = Math.max(N.clientHeight, N.offsetHeight, N.scrollHeight);
37889         this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37890         this.list.beginUpdate();
37891         this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37892         this.list.alignTo(this.el, this.listAlign);
37893         this.list.endUpdate();
37894     },
37895
37896     // private
37897     onEmptyResults : function(){
37898         this.collapse();
37899     },
37900
37901     /**
37902      * Returns true if the dropdown list is expanded, else false.
37903      */
37904     isExpanded : function(){
37905         return  this.list.isVisible();
37906     },
37907
37908     /**
37909      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37910      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37911      * @param {String} value The data value of the item to select
37912      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37913      * selected item if it is not currently in view (defaults to true)
37914      * @return {Boolean} True if the value matched an item in the list, else false
37915      */
37916     selectByValue : function(v, O){
37917         if(v !== undefined && v !== null){
37918             var  r = this.findRecord(this.valueField || this.displayField, v);
37919             if(r){
37920                 this.select(this.store.indexOf(r), O);
37921                 return  true;
37922             }
37923         }
37924         return  false;
37925     },
37926
37927     /**
37928      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37929      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37930      * @param {Number} index The zero-based index of the list item to select
37931      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37932      * selected item if it is not currently in view (defaults to true)
37933      */
37934     select : function(P, Q){
37935         this.selectedIndex = P;
37936         this.view.select(P);
37937         if(Q !== false){
37938             var  el = this.view.getNode(P);
37939             if(el){
37940                 this.innerList.scrollChildIntoView(el, false);
37941             }
37942         }
37943     },
37944
37945     // private
37946     selectNext : function(){
37947         var  ct = this.store.getCount();
37948         if(ct > 0){
37949             if(this.selectedIndex == -1){
37950                 this.select(0);
37951             }else  if(this.selectedIndex < ct-1){
37952                 this.select(this.selectedIndex+1);
37953             }
37954         }
37955     },
37956
37957     // private
37958     selectPrev : function(){
37959         var  ct = this.store.getCount();
37960         if(ct > 0){
37961             if(this.selectedIndex == -1){
37962                 this.select(0);
37963             }else  if(this.selectedIndex != 0){
37964                 this.select(this.selectedIndex-1);
37965             }
37966         }
37967     },
37968
37969     // private
37970     onKeyUp : function(e){
37971         if(this.editable !== false && !e.isSpecialKey()){
37972             this.lastKey = e.getKey();
37973             this.dqTask.delay(this.queryDelay);
37974         }
37975     },
37976
37977     // private
37978     validateBlur : function(){
37979         return  !this.list || !this.list.isVisible();   
37980     },
37981
37982     // private
37983     initQuery : function(){
37984         this.doQuery(this.getRawValue());
37985     },
37986
37987     // private
37988     doForce : function(){
37989         if(this.el.dom.value.length > 0){
37990             this.el.dom.value =
37991                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37992             this.applyEmptyText();
37993         }
37994     },
37995
37996     /**
37997      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
37998      * query allowing the query action to be canceled if needed.
37999      * @param {String} query The SQL query to execute
38000      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38001      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
38002      * saved in the current store (defaults to false)
38003      */
38004     doQuery : function(q, R){
38005         if(q === undefined || q === null){
38006             q = '';
38007         }
38008         var  qe = {
38009             query: q,
38010             forceAll: R,
38011             combo: this,
38012             cancel:false
38013         };
38014         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38015             return  false;
38016         }
38017
38018         q = qe.query;
38019         R = qe.forceAll;
38020         if(R === true || (q.length >= this.minChars)){
38021             if(this.lastQuery != q){
38022                 this.lastQuery = q;
38023                 if(this.mode == 'local'){
38024                     this.selectedIndex = -1;
38025                     if(R){
38026                         this.store.clearFilter();
38027                     }else {
38028                         this.store.filter(this.displayField, q);
38029                     }
38030
38031                     this.onLoad();
38032                 }else {
38033                     this.store.baseParams[this.queryParam] = q;
38034                     this.store.load({
38035                         params: this.getParams(q)
38036                     });
38037                     this.expand();
38038                 }
38039             }else {
38040                 this.selectedIndex = -1;
38041                 this.onLoad();   
38042             }
38043         }
38044     },
38045
38046     // private
38047     getParams : function(q){
38048         var  p = {};
38049         //p[this.queryParam] = q;
38050         if(this.pageSize){
38051             p.start = 0;
38052             p.limit = this.pageSize;
38053         }
38054         return  p;
38055     },
38056
38057     /**
38058      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38059      */
38060     collapse : function(){
38061         if(!this.isExpanded()){
38062             return;
38063         }
38064
38065         this.list.hide();
38066         Roo.get(document).un('mousedown', this.collapseIf, this);
38067         Roo.get(document).un('mousewheel', this.collapseIf, this);
38068         this.fireEvent('collapse', this);
38069     },
38070
38071     // private
38072     collapseIf : function(e){
38073         if(!e.within(this.wrap) && !e.within(this.list)){
38074             this.collapse();
38075         }
38076     },
38077
38078     /**
38079      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38080      */
38081     expand : function(){
38082         if(this.isExpanded() || !this.hasFocus){
38083             return;
38084         }
38085
38086         this.list.alignTo(this.el, this.listAlign);
38087         this.list.show();
38088         Roo.get(document).on('mousedown', this.collapseIf, this);
38089         Roo.get(document).on('mousewheel', this.collapseIf, this);
38090         this.fireEvent('expand', this);
38091     },
38092
38093     // private
38094     // Implements the default empty TriggerField.onTriggerClick function
38095     onTriggerClick : function(){
38096         if(this.disabled){
38097             return;
38098         }
38099         if(this.isExpanded()){
38100             this.collapse();
38101             if (!this.blockFocus) {
38102                 this.el.focus();
38103             }
38104             
38105         }else  {
38106             this.hasFocus = true;
38107             if(this.triggerAction == 'all') {
38108                 this.doQuery(this.allQuery, true);
38109             } else  {
38110                 this.doQuery(this.getRawValue());
38111             }
38112             if (!this.blockFocus) {
38113                 this.el.focus();
38114             }
38115         }
38116     }
38117
38118     /** 
38119     * @cfg {Boolean} grow 
38120     * @hide 
38121     */
38122     /** 
38123     * @cfg {Number} growMin 
38124     * @hide 
38125     */
38126     /** 
38127     * @cfg {Number} growMax 
38128     * @hide 
38129     */
38130     /**
38131      * @hide
38132      * @method autoSize
38133      */
38134 });
38135 /*
38136  * Based on:
38137  * Ext JS Library 1.1.1
38138  * Copyright(c) 2006-2007, Ext JS, LLC.
38139  *
38140  * Originally Released Under LGPL - original licence link has changed is not relivant.
38141  *
38142  * Fork - LGPL
38143  * <script type="text/javascript">
38144  */
38145 /**
38146  * @class Roo.form.Checkbox
38147  * @extends Roo.form.Field
38148  * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.
38149  * @constructor
38150  * Creates a new Checkbox
38151  * @param {Object} config Configuration options
38152  */
38153 Roo.form.Checkbox = function(A){
38154     Roo.form.Checkbox.superclass.constructor.call(this, A);
38155     this.addEvents({
38156         /**
38157          * @event check
38158          * Fires when the checkbox is checked or unchecked.
38159              * @param {Roo.form.Checkbox} this This checkbox
38160              * @param {Boolean} checked The new checked value
38161              */
38162         check : true
38163     });
38164 };
38165
38166 Roo.extend(Roo.form.Checkbox, Roo.form.Field,  {
38167     /**
38168      * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38169      */
38170     focusClass : undefined,
38171     /**
38172      * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38173      */
38174     fieldClass: "x-form-field",
38175     /**
38176      * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38177      */
38178     checked: false,
38179     /**
38180      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38181      * {tag: "input", type: "checkbox", autocomplete: "off"})
38182      */
38183     defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38184     /**
38185      * @cfg {String} boxLabel The text that appears beside the checkbox
38186      */
38187     boxLabel : "",
38188     /**
38189      * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38190      */  
38191     inputValue : '1',
38192     /**
38193      * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38194      */
38195      valueOff: '0', // value when not checked..
38196
38197     actionMode : 'viewEl', 
38198     //
38199     // private
38200     itemCls : 'x-menu-check-item x-form-item',
38201     groupClass : 'x-menu-group-item',
38202     inputType : 'hidden',
38203     
38204     
38205     inSetChecked: false, // check that we are not calling self...
38206     
38207     inputElement: false, // real input element?
38208     basedOn: false, // ????
38209     
38210     isFormField: true, // not sure where this is needed!!!!
38211
38212     onResize : function(){
38213         Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38214         if(!this.boxLabel){
38215             this.el.alignTo(this.wrap, 'c-c');
38216         }
38217     },
38218
38219     initEvents : function(){
38220         Roo.form.Checkbox.superclass.initEvents.call(this);
38221         this.el.on("click", this.onClick,  this);
38222         this.el.on("change", this.onClick,  this);
38223     },
38224
38225
38226     getResizeEl : function(){
38227         return  this.wrap;
38228     },
38229
38230     getPositionEl : function(){
38231         return  this.wrap;
38232     },
38233
38234     // private
38235     onRender : function(ct, B){
38236         Roo.form.Checkbox.superclass.onRender.call(this, ct, B);
38237         /*
38238         if(this.inputValue !== undefined){
38239             this.el.dom.value = this.inputValue;
38240         }
38241         */
38242         //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38243         this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38244         var  C = this.wrap.createChild({ 
38245             tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38246         this.viewEl = C;   
38247         this.wrap.on('click', this.onClick,  this); 
38248         
38249         this.el.on('DOMAttrModified', this.setFromHidden,  this); //ff
38250         this.el.on('propertychange', this.setFromHidden,  this);  //ie
38251         
38252         
38253         
38254         if(this.boxLabel){
38255             this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38256         //    viewEl.on('click', this.onClick,  this); 
38257         }
38258
38259         //if(this.checked){
38260             this.setChecked(this.checked);
38261         //}else{
38262             //this.checked = this.el.dom;
38263         //}
38264
38265     },
38266
38267     // private
38268     initValue : Roo.emptyFn,
38269
38270     /**
38271      * Returns the checked state of the checkbox.
38272      * @return {Boolean} True if checked, else false
38273      */
38274     getValue : function(){
38275         if(this.el){
38276             return  String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38277         }
38278         return  this.valueOff;
38279         
38280     },
38281
38282         // private
38283     onClick : function(){ 
38284         this.setChecked(!this.checked);
38285
38286         //if(this.el.dom.checked != this.checked){
38287         //    this.setValue(this.el.dom.checked);
38288        // }
38289     },
38290
38291     /**
38292      * Sets the checked state of the checkbox.
38293      * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
38294      */
38295     setValue : function(v,D){
38296         //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38297         //if(this.el && this.el.dom){
38298         //    this.el.dom.checked = this.checked;
38299         //    this.el.dom.defaultChecked = this.checked;
38300         //}
38301         this.setChecked(v === this.inputValue);
38302         //this.fireEvent("check", this, this.checked);
38303     },
38304     // private..
38305     setChecked : function(E,F)
38306     {
38307         if (this.inSetChecked) {
38308             this.checked = E;
38309             return;
38310         }
38311         
38312     
38313         if(this.wrap){
38314             this.wrap[E ? 'addClass' : 'removeClass']('x-menu-item-checked');
38315         }
38316
38317         this.checked = E;
38318         if(F !== true){
38319             this.fireEvent('checkchange', this, E);
38320         }
38321
38322         this.inSetChecked = true;
38323         this.el.dom.value = E ? this.inputValue : this.valueOff;
38324         this.inSetChecked = false;
38325         
38326     },
38327     // handle setting of hidden value by some other method!!?!?
38328     setFromHidden: function()
38329     {
38330         if(!this.el){
38331             return;
38332         }
38333
38334         //console.log("SET FROM HIDDEN");
38335         //alert('setFrom hidden');
38336         this.setValue(this.el.dom.value);
38337     },
38338     
38339     onDestroy : function()
38340     {
38341         if(this.viewEl){
38342             Roo.get(this.viewEl).remove();
38343         }
38344
38345          
38346         Roo.form.Checkbox.superclass.onDestroy.call(this);
38347     }
38348
38349 });
38350 /*
38351  * Based on:
38352  * Ext JS Library 1.1.1
38353  * Copyright(c) 2006-2007, Ext JS, LLC.
38354  *
38355  * Originally Released Under LGPL - original licence link has changed is not relivant.
38356  *
38357  * Fork - LGPL
38358  * <script type="text/javascript">
38359  */
38360  
38361 /**
38362  * @class Roo.form.Radio
38363  * @extends Roo.form.Checkbox
38364  * Single radio field.  Same as Checkbox, but provided as a convenience for automatically setting the input type.
38365  * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38366  * @constructor
38367  * Creates a new Radio
38368  * @param {Object} config Configuration options
38369  */
38370 Roo.form.Radio = function(){
38371     Roo.form.Radio.superclass.constructor.apply(this, arguments);
38372 };
38373 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38374     inputType: 'radio',
38375
38376     /**
38377      * If this radio is part of a group, it will return the selected value
38378      * @return {String}
38379      */
38380     getGroupValue : function(){
38381         return  this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38382     }
38383 });
38384 //<script type="text/javascript">
38385
38386 /*
38387  * Ext JS Library 1.1.1
38388  * Copyright(c) 2006-2007, Ext JS, LLC.
38389  * licensing@extjs.com
38390  * 
38391  * http://www.extjs.com/license
38392  */
38393  
38394  /*
38395   * 
38396   * Known bugs:
38397   * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38398   * - IE ? - no idea how much works there.
38399   * 
38400   * 
38401   * 
38402   */
38403  
38404
38405 /**
38406  * @class Ext.form.HtmlEditor
38407  * @extends Ext.form.Field
38408  * Provides a lightweight HTML Editor component.
38409  * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38410  * 
38411  * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38412  * supported by this editor.</b><br/><br/>
38413  * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38414  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38415  */
38416 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38417       /**
38418      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38419      */
38420     toolbars : false,
38421     /**
38422      * @cfg {String} createLinkText The default text for the create link prompt
38423      */
38424     createLinkText : 'Please enter the URL for the link:',
38425     /**
38426      * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38427      */
38428     defaultLinkValue : 'http:/'+'/',
38429    
38430     
38431     // id of frame..
38432     frameId: false,
38433     
38434     // private properties
38435     validationEvent : false,
38436     deferHeight: true,
38437     initialized : false,
38438     activated : false,
38439     sourceEditMode : false,
38440     onFocus : Roo.emptyFn,
38441     iframePad:3,
38442     hideMode:'offsets',
38443     defaultAutoCreate : {
38444         tag: "textarea",
38445         style:"width:500px;height:300px;",
38446         autocomplete: "off"
38447     },
38448
38449     // private
38450     initComponent : function(){
38451         this.addEvents({
38452             /**
38453              * @event initialize
38454              * Fires when the editor is fully initialized (including the iframe)
38455              * @param {HtmlEditor} this
38456              */
38457             initialize: true,
38458             /**
38459              * @event activate
38460              * Fires when the editor is first receives the focus. Any insertion must wait
38461              * until after this event.
38462              * @param {HtmlEditor} this
38463              */
38464             activate: true,
38465              /**
38466              * @event beforesync
38467              * Fires before the textarea is updated with content from the editor iframe. Return false
38468              * to cancel the sync.
38469              * @param {HtmlEditor} this
38470              * @param {String} html
38471              */
38472             beforesync: true,
38473              /**
38474              * @event beforepush
38475              * Fires before the iframe editor is updated with content from the textarea. Return false
38476              * to cancel the push.
38477              * @param {HtmlEditor} this
38478              * @param {String} html
38479              */
38480             beforepush: true,
38481              /**
38482              * @event sync
38483              * Fires when the textarea is updated with content from the editor iframe.
38484              * @param {HtmlEditor} this
38485              * @param {String} html
38486              */
38487             sync: true,
38488              /**
38489              * @event push
38490              * Fires when the iframe editor is updated with content from the textarea.
38491              * @param {HtmlEditor} this
38492              * @param {String} html
38493              */
38494             push: true,
38495              /**
38496              * @event editmodechange
38497              * Fires when the editor switches edit modes
38498              * @param {HtmlEditor} this
38499              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38500              */
38501             editmodechange: true,
38502             /**
38503              * @event editorevent
38504              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38505              * @param {HtmlEditor} this
38506              */
38507             editorevent: true
38508         })
38509     },
38510
38511     /**
38512      * Protected method that will not generally be called directly. It
38513      * is called when the editor creates its toolbar. Override this method if you need to
38514      * add custom toolbar buttons.
38515      * @param {HtmlEditor} editor
38516      */
38517     createToolbar : function(A){
38518         if (!A.toolbars || !A.toolbars.length) {
38519             A.toolbars = [ new  Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38520         }
38521         
38522         for (var  i =0 ; i < A.toolbars.length;i++) {
38523             A.toolbars[i].init(A);
38524         }
38525          
38526         
38527     },
38528
38529     /**
38530      * Protected method that will not generally be called directly. It
38531      * is called when the editor initializes the iframe with HTML contents. Override this method if you
38532      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38533      */
38534     getDocMarkup : function(){
38535         return  '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38536     },
38537
38538     // private
38539     onRender : function(ct, B){
38540         Roo.form.HtmlEditor.superclass.onRender.call(this, ct, B);
38541         this.el.dom.style.border = '0 none';
38542         this.el.dom.setAttribute('tabIndex', -1);
38543         this.el.addClass('x-hidden');
38544         if(Roo.isIE){ // fix IE 1px bogus margin
38545             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38546         }
38547
38548         this.wrap = this.el.wrap({
38549             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38550         });
38551
38552         this.frameId = Roo.id();
38553         this.createToolbar(this);
38554         
38555         
38556         
38557         
38558       
38559         
38560         var  C = this.wrap.createChild({
38561             tag: 'iframe',
38562             id: this.frameId,
38563             name: this.frameId,
38564             frameBorder : 'no',
38565             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
38566         });
38567         
38568        // console.log(iframe);
38569         //this.wrap.dom.appendChild(iframe);
38570
38571         this.iframe = C.dom;
38572
38573          this.assignDocWin();
38574         
38575         this.doc.designMode = 'on';
38576        
38577         this.doc.open();
38578         this.doc.write(this.getDocMarkup());
38579         this.doc.close();
38580
38581         
38582         var  D = { // must defer to wait for browser to be ready
38583             run : function(){
38584                 //console.log("run task?" + this.doc.readyState);
38585                 this.assignDocWin();
38586                 if(this.doc.body || this.doc.readyState == 'complete'){
38587                     try {
38588                         
38589                        
38590                         this.doc.designMode="on";
38591                     } catch (e) {
38592                         return;
38593                     }
38594
38595                     Roo.TaskMgr.stop(D);
38596                     this.initEditor.defer(10, this);
38597                 }
38598             },
38599             interval : 10,
38600             duration:10000,
38601             scope: this
38602         };
38603         Roo.TaskMgr.start(D);
38604
38605         if(!this.width){
38606             this.setSize(this.el.getSize());
38607         }
38608     },
38609
38610     // private
38611     onResize : function(w, h){
38612         Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38613         if(this.el && this.iframe){
38614             if(typeof  w == 'number'){
38615                 var  aw = w - this.wrap.getFrameWidth('lr');
38616                 this.el.setWidth(this.adjustWidth('textarea', aw));
38617                 this.iframe.style.width = aw + 'px';
38618             }
38619             if(typeof  h == 'number'){
38620                 var  tbh = 0;
38621                 for (var  i =0; i < this.toolbars.length;i++) {
38622                     // fixme - ask toolbars for heights?
38623                     tbh += this.toolbars[i].tb.el.getHeight();
38624                 }
38625                 
38626                 
38627                 
38628                 
38629                 var  ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38630                 this.el.setHeight(this.adjustWidth('textarea', ah));
38631                 this.iframe.style.height = ah + 'px';
38632                 if(this.doc){
38633                     (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38634                 }
38635             }
38636         }
38637     },
38638
38639     /**
38640      * Toggles the editor between standard and source edit mode.
38641      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38642      */
38643     toggleSourceEdit : function(E){
38644         
38645         this.sourceEditMode = E === true;
38646         
38647         if(this.sourceEditMode){
38648           
38649             this.syncValue();
38650             this.iframe.className = 'x-hidden';
38651             this.el.removeClass('x-hidden');
38652             this.el.dom.removeAttribute('tabIndex');
38653             this.el.focus();
38654         }else {
38655              
38656             this.pushValue();
38657             this.iframe.className = '';
38658             this.el.addClass('x-hidden');
38659             this.el.dom.setAttribute('tabIndex', -1);
38660             this.deferFocus();
38661         }
38662
38663         this.setSize(this.wrap.getSize());
38664         this.fireEvent('editmodechange', this, this.sourceEditMode);
38665     },
38666
38667     // private used internally
38668     createLink : function(){
38669         var  F = prompt(this.createLinkText, this.defaultLinkValue);
38670         if(F && F != 'http:/'+'/'){
38671             this.relayCmd('createlink', F);
38672         }
38673     },
38674
38675     // private (for BoxComponent)
38676     adjustSize : Roo.BoxComponent.prototype.adjustSize,
38677
38678     // private (for BoxComponent)
38679     getResizeEl : function(){
38680         return  this.wrap;
38681     },
38682
38683     // private (for BoxComponent)
38684     getPositionEl : function(){
38685         return  this.wrap;
38686     },
38687
38688     // private
38689     initEvents : function(){
38690         this.originalValue = this.getValue();
38691     },
38692
38693     /**
38694      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38695      * @method
38696      */
38697     markInvalid : Roo.emptyFn,
38698     /**
38699      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38700      * @method
38701      */
38702     clearInvalid : Roo.emptyFn,
38703
38704     setValue : function(v){
38705         Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38706         this.pushValue();
38707     },
38708
38709     /**
38710      * Protected method that will not generally be called directly. If you need/want
38711      * custom HTML cleanup, this is the method you should override.
38712      * @param {String} html The HTML to be cleaned
38713      * return {String} The cleaned HTML
38714      */
38715     cleanHtml : function(G){
38716         G = String(G);
38717         if(G.length > 5){
38718             if(Roo.isSafari){ // strip safari nonsense
38719                 G = G.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38720             }
38721         }
38722         if(G == '&nbsp;'){
38723             G = '';
38724         }
38725         return  G;
38726     },
38727
38728     /**
38729      * Protected method that will not generally be called directly. Syncs the contents
38730      * of the editor iframe with the textarea.
38731      */
38732     syncValue : function(){
38733         if(this.initialized){
38734             var  bd = (this.doc.body || this.doc.documentElement);
38735             var  G = bd.innerHTML;
38736             if(Roo.isSafari){
38737                 var  bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38738                 var  m = bs.match(/text-align:(.*?);/i);
38739                 if(m && m[1]){
38740                     G = '<div style="'+m[0]+'">' + G + '</div>';
38741                 }
38742             }
38743
38744             G = this.cleanHtml(G);
38745             if(this.fireEvent('beforesync', this, G) !== false){
38746                 this.el.dom.value = G;
38747                 this.fireEvent('sync', this, G);
38748             }
38749         }
38750     },
38751
38752     /**
38753      * Protected method that will not generally be called directly. Pushes the value of the textarea
38754      * into the iframe editor.
38755      */
38756     pushValue : function(){
38757         if(this.initialized){
38758             var  v = this.el.dom.value;
38759             if(v.length < 1){
38760                 v = '&#160;';
38761             }
38762             if(this.fireEvent('beforepush', this, v) !== false){
38763                 (this.doc.body || this.doc.documentElement).innerHTML = v;
38764                 this.fireEvent('push', this, v);
38765             }
38766         }
38767     },
38768
38769     // private
38770     deferFocus : function(){
38771         this.focus.defer(10, this);
38772     },
38773
38774     // doc'ed in Field
38775     focus : function(){
38776         if(this.win && !this.sourceEditMode){
38777             this.win.focus();
38778         }else {
38779             this.el.focus();
38780         }
38781     },
38782     
38783     assignDocWin: function()
38784     {
38785         var  H = this.iframe;
38786         
38787          if(Roo.isIE){
38788             this.doc = H.contentWindow.document;
38789             this.win = H.contentWindow;
38790         } else  {
38791             this.doc = (H.contentDocument || Roo.get(this.frameId).dom.document);
38792             this.win = Roo.get(this.frameId).dom.contentWindow;
38793         }
38794     },
38795     
38796     // private
38797     initEditor : function(){
38798         //console.log("INIT EDITOR");
38799         this.assignDocWin();
38800         
38801         
38802         
38803         this.doc.designMode="on";
38804         this.doc.open();
38805         this.doc.write(this.getDocMarkup());
38806         this.doc.close();
38807         
38808         var  I = (this.doc.body || this.doc.documentElement);
38809         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38810         // this copies styles from the containing element into thsi one..
38811         // not sure why we need all of this..
38812         var  ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38813         ss['background-attachment'] = 'fixed'; // w3c
38814         I.bgProperties = 'fixed'; // ie
38815         Roo.DomHelper.applyStyles(I, ss);
38816         Roo.EventManager.on(this.doc, {
38817             'mousedown': this.onEditorEvent,
38818             'dblclick': this.onEditorEvent,
38819             'click': this.onEditorEvent,
38820             'keyup': this.onEditorEvent,
38821             buffer:100,
38822             scope: this
38823         });
38824         if(Roo.isGecko){
38825             Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38826         }
38827         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38828             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38829         }
38830
38831         this.initialized = true;
38832
38833         this.fireEvent('initialize', this);
38834         this.pushValue();
38835     },
38836
38837     // private
38838     onDestroy : function(){
38839         
38840         
38841         
38842         if(this.rendered){
38843             
38844             for (var  i =0; i < this.toolbars.length;i++) {
38845                 // fixme - ask toolbars for heights?
38846                 this.toolbars[i].onDestroy();
38847             }
38848
38849             
38850             this.wrap.dom.innerHTML = '';
38851             this.wrap.remove();
38852         }
38853     },
38854
38855     // private
38856     onFirstFocus : function(){
38857         
38858         this.assignDocWin();
38859         
38860         
38861         this.activated = true;
38862         for (var  i =0; i < this.toolbars.length;i++) {
38863             this.toolbars[i].onFirstFocus();
38864         }
38865        
38866         if(Roo.isGecko){ // prevent silly gecko errors
38867             this.win.focus();
38868             var  s = this.win.getSelection();
38869             if(!s.focusNode || s.focusNode.nodeType != 3){
38870                 var  r = s.getRangeAt(0);
38871                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38872                 r.collapse(true);
38873                 this.deferFocus();
38874             }
38875             try{
38876                 this.execCmd('useCSS', true);
38877                 this.execCmd('styleWithCSS', false);
38878             }catch(e){}
38879         }
38880
38881         this.fireEvent('activate', this);
38882     },
38883
38884     // private
38885     adjustFont: function(J){
38886         var  K = J.cmd == 'increasefontsize' ? 1 : -1;
38887         //if(Roo.isSafari){ // safari
38888         //    adjust *= 2;
38889        // }
38890         var  v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38891         if(Roo.isSafari){ // safari
38892             var  sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38893             v =  (v < 10) ? 10 : v;
38894             v =  (v > 48) ? 48 : v;
38895             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38896             
38897         }
38898
38899         
38900         
38901         v = Math.max(1, v+K);
38902         
38903         this.execCmd('FontSize', v  );
38904     },
38905
38906     onEditorEvent : function(e){
38907         this.fireEvent('editorevent', this, e);
38908       //  this.updateToolbar();
38909         this.syncValue();
38910     },
38911
38912     insertTag : function(tg)
38913     {
38914         // could be a bit smarter... -> wrap the current selected tRoo..
38915         
38916         this.execCmd("formatblock",   tg);
38917         
38918     },
38919     
38920     insertText : function(L)
38921     {
38922         
38923         
38924         range = this.createRange();
38925         range.deleteContents();
38926                //alert(Sender.getAttribute('label'));
38927                
38928         range.insertNode(this.doc.createTextNode(L));
38929     } ,
38930     
38931     // private
38932     relayBtnCmd : function(M){
38933         this.relayCmd(M.cmd);
38934     },
38935
38936     /**
38937      * Executes a Midas editor command on the editor document and performs necessary focus and
38938      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38939      * @param {String} cmd The Midas command
38940      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38941      */
38942     relayCmd : function(N, O){
38943         this.win.focus();
38944         this.execCmd(N, O);
38945         this.fireEvent('editorevent', this);
38946         //this.updateToolbar();
38947         this.deferFocus();
38948     },
38949
38950     /**
38951      * Executes a Midas editor command directly on the editor document.
38952      * For visual commands, you should use {@link #relayCmd} instead.
38953      * <b>This should only be called after the editor is initialized.</b>
38954      * @param {String} cmd The Midas command
38955      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38956      */
38957     execCmd : function(P, Q){
38958         this.doc.execCommand(P, false, Q === undefined ? null : Q);
38959         this.syncValue();
38960     },
38961
38962     // private
38963     applyCommand : function(e){
38964         if(e.ctrlKey){
38965             var  c = e.getCharCode(), P;
38966             if(c > 0){
38967                 c = String.fromCharCode(c);
38968                 switch(c){
38969                     case  'b':
38970                         P = 'bold';
38971                     break;
38972                     case  'i':
38973                         P = 'italic';
38974                     break;
38975                     case  'u':
38976                         P = 'underline';
38977                     break;
38978                 }
38979                 if(P){
38980                     this.win.focus();
38981                     this.execCmd(P);
38982                     this.deferFocus();
38983                     e.preventDefault();
38984                 }
38985             }
38986         }
38987     },
38988
38989     /**
38990      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38991      * to insert tRoo.
38992      * @param {String} text
38993      */
38994     insertAtCursor : function(R){
38995         if(!this.activated){
38996             return;
38997         }
38998         if(Roo.isIE){
38999             this.win.focus();
39000             var  r = this.doc.selection.createRange();
39001             if(r){
39002                 r.collapse(true);
39003                 r.pasteHTML(R);
39004                 this.syncValue();
39005                 this.deferFocus();
39006             }
39007         }else  if(Roo.isGecko || Roo.isOpera){
39008             this.win.focus();
39009             this.execCmd('InsertHTML', R);
39010             this.deferFocus();
39011         }else  if(Roo.isSafari){
39012             this.execCmd('InsertText', R);
39013             this.deferFocus();
39014         }
39015     },
39016
39017     // private
39018     fixKeys : function(){ // load time branching for fastest keydown performance
39019         if(Roo.isIE){
39020             return  function(e){
39021                 var  k = e.getKey(), r;
39022                 if(k == e.TAB){
39023                     e.stopEvent();
39024                     r = this.doc.selection.createRange();
39025                     if(r){
39026                         r.collapse(true);
39027                         r.pasteHTML('&#160;&#160;&#160;&#160;');
39028                         this.deferFocus();
39029                     }
39030                 }else  if(k == e.ENTER){
39031                     r = this.doc.selection.createRange();
39032                     if(r){
39033                         var  target = r.parentElement();
39034                         if(!target || target.tagName.toLowerCase() != 'li'){
39035                             e.stopEvent();
39036                             r.pasteHTML('<br />');
39037                             r.collapse(false);
39038                             r.select();
39039                         }
39040                     }
39041                 }
39042             };
39043         }else  if(Roo.isOpera){
39044             return  function(e){
39045                 var  k = e.getKey();
39046                 if(k == e.TAB){
39047                     e.stopEvent();
39048                     this.win.focus();
39049                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
39050                     this.deferFocus();
39051                 }
39052             };
39053         }else  if(Roo.isSafari){
39054             return  function(e){
39055                 var  k = e.getKey();
39056                 if(k == e.TAB){
39057                     e.stopEvent();
39058                     this.execCmd('InsertText','\t');
39059                     this.deferFocus();
39060                 }
39061              };
39062         }
39063     }(),
39064     
39065     getAllAncestors: function()
39066     {
39067         var  p = this.getSelectedNode();
39068         var  a = [];
39069         if (!p) {
39070             a.push(p); // push blank onto stack..
39071             p = this.getParentElement();
39072         }
39073         
39074         
39075         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39076             a.push(p);
39077             p = p.parentNode;
39078         }
39079
39080         a.push(this.doc.body);
39081         return  a;
39082     },
39083     lastSel : false,
39084     lastSelNode : false,
39085     
39086     
39087     getSelection : function() 
39088     {
39089         this.assignDocWin();
39090         return  Roo.isIE ? this.doc.selection : this.win.getSelection();
39091     },
39092     
39093     getSelectedNode: function() 
39094     {
39095         // this may only work on Gecko!!!
39096         
39097         // should we cache this!!!!
39098         
39099         
39100         
39101          
39102         var  S = this.createRange(this.getSelection());
39103         
39104         if (Roo.isIE) {
39105             var  parent = S.parentElement();
39106             while (true) {
39107                 var  testRange = S.duplicate();
39108                 testRange.moveToElementText(parent);
39109                 if (testRange.inRange(S)) {
39110                     break;
39111                 }
39112                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39113                     break;
39114                 }
39115
39116                 parent = parent.parentElement;
39117             }
39118             return  parent;
39119         }
39120         
39121         
39122         var  ar = S.endContainer.childNodes;
39123         if (!ar.length) {
39124             ar = S.commonAncestorContainer.childNodes;
39125             //alert(ar.length);
39126         }
39127         var  T = [];
39128         var  U = [];
39129         var  V = false;
39130         for (var  i=0;i<ar.length;i++) {
39131             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
39132                 continue;
39133             }
39134             // fullly contained node.
39135             
39136             if (this.rangeIntersectsNode(S,ar[i]) && this.rangeCompareNode(S,ar[i]) == 3) {
39137                 T.push(ar[i]);
39138                 continue;
39139             }
39140             
39141             // probably selected..
39142             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(S,ar[i]) && (this.rangeCompareNode(S,ar[i]) > 0)) {
39143                 U.push(ar[i]);
39144                 continue;
39145             }
39146             if (!this.rangeIntersectsNode(S,ar[i])|| (this.rangeCompareNode(S,ar[i]) == 0))  {
39147                 continue;
39148             }
39149
39150             
39151             
39152             V = true;
39153         }
39154         if (!T.length && U.length) {
39155             T= U;
39156         }
39157         if (V || !T.length || (T.length > 1)) {
39158             return  false;
39159         }
39160         
39161         return  T[0];
39162     },
39163     createRange: function(W)
39164     {
39165         // this has strange effects when using with 
39166         // top toolbar - not sure if it's a great idea.
39167         //this.editor.contentWindow.focus();
39168         if (typeof  W != "undefined") {
39169             try {
39170                 return  W.getRangeAt ? W.getRangeAt(0) : W.createRange();
39171             } catch(e) {
39172                 return  this.doc.createRange();
39173             }
39174         } else  {
39175             return  this.doc.createRange();
39176         }
39177     },
39178     getParentElement: function()
39179     {
39180         
39181         this.assignDocWin();
39182         var  X = Roo.isIE ? this.doc.selection : this.win.getSelection();
39183         
39184         var  Y = this.createRange(X);
39185          
39186         try {
39187             var  p = Y.commonAncestorContainer;
39188             while (p.nodeType == 3) { // text node
39189                 p = p.parentNode;
39190             }
39191             return  p;
39192         } catch (e) {
39193             return  null;
39194         }
39195     
39196     },
39197     
39198     
39199     
39200     // BC Hacks - cause I cant work out what i was trying to do..
39201     rangeIntersectsNode : function(Z, b)
39202     {
39203         var  d = b.ownerDocument.createRange();
39204         try {
39205             d.selectNode(b);
39206         }
39207         catch (e) {
39208             nodeRange.selectNodeContents(node);
39209         }
39210
39211         return  Z.compareBoundaryPoints(Range.END_TO_START, d) == -1 &&
39212                  Z.compareBoundaryPoints(Range.START_TO_END, d) == 1;
39213     },
39214     rangeCompareNode : function(f, g) {
39215         var  j = g.ownerDocument.createRange();
39216         try {
39217             j.selectNode(g);
39218         } catch (e) {
39219             nodeRange.selectNodeContents(node);
39220         }
39221         var  k = f.compareBoundaryPoints(Range.START_TO_START, j) == 1;
39222         var  l = f.compareBoundaryPoints(Range.END_TO_END, j) == -1;
39223
39224         if (k && !l)
39225             return  0;
39226         if (!k && l)
39227             return  1;
39228         if (k && l)
39229             return  2;
39230
39231         return  3;
39232     }
39233
39234     
39235     
39236     // hide stuff that is not compatible
39237     /**
39238      * @event blur
39239      * @hide
39240      */
39241     /**
39242      * @event change
39243      * @hide
39244      */
39245     /**
39246      * @event focus
39247      * @hide
39248      */
39249     /**
39250      * @event specialkey
39251      * @hide
39252      */
39253     /**
39254      * @cfg {String} fieldClass @hide
39255      */
39256     /**
39257      * @cfg {String} focusClass @hide
39258      */
39259     /**
39260      * @cfg {String} autoCreate @hide
39261      */
39262     /**
39263      * @cfg {String} inputType @hide
39264      */
39265     /**
39266      * @cfg {String} invalidClass @hide
39267      */
39268     /**
39269      * @cfg {String} invalidText @hide
39270      */
39271     /**
39272      * @cfg {String} msgFx @hide
39273      */
39274     /**
39275      * @cfg {String} validateOnBlur @hide
39276      */
39277 });
39278 // <script type="text/javascript">
39279 /*
39280  * Based on
39281  * Ext JS Library 1.1.1
39282  * Copyright(c) 2006-2007, Ext JS, LLC.
39283  *  
39284  
39285  */
39286
39287 /**
39288  * @class Roo.form.HtmlEditorToolbar1
39289  * Basic Toolbar
39290  * 
39291  * Usage:
39292  *
39293  new Roo.form.HtmlEditor({
39294     ....
39295     toolbars : [
39296         new Roo.form.HtmlEditorToolbar1({
39297             disable : { fonts: 1 , format: 1, ..., ... , ...],
39298             btns : [ .... ]
39299         })
39300     }
39301      
39302  * 
39303  * @cfg {Object} disable List of elements to disable..
39304  * @cfg {Array} btns List of additional buttons.
39305  * 
39306  * 
39307  * NEEDS Extra CSS? 
39308  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39309  */
39310  
39311 Roo.form.HtmlEditor.ToolbarStandard = function(A)
39312 {
39313     
39314     Roo.apply(this, A);
39315     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39316     // dont call parent... till later.
39317 }
39318
39319
39320 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
39321     
39322     tb: false,
39323     
39324     rendered: false,
39325     
39326     editor : false,
39327     /**
39328      * @cfg {Object} disable  List of toolbar elements to disable
39329          
39330      */
39331     disable : false,
39332       /**
39333      * @cfg {Array} fontFamilies An array of available font families
39334      */
39335     fontFamilies : [
39336         'Arial',
39337         'Courier New',
39338         'Tahoma',
39339         'Times New Roman',
39340         'Verdana'
39341     ],
39342     
39343     specialChars : [
39344            "&#169;",
39345           "&#174;",     
39346           "&#8482;",    
39347           "&#163;" ,    
39348          // "&#8212;",    
39349           "&#8230;",    
39350           "&#247;" ,    
39351         //  "&#225;" ,     ?? a acute?
39352            "&#8364;"    , //Euro
39353        //   "&#8220;"    ,
39354         //  "&#8221;"    ,
39355         //  "&#8226;"    ,
39356           "&#176;"  //   , // degrees
39357
39358          // "&#233;"     , // e ecute
39359          // "&#250;"     , // u ecute?
39360     ],
39361     inputElements : [ 
39362             "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password", 
39363             "input:submit", "input:button", "select", "textarea", "label" ],
39364     formats : [
39365         ["p"] ,  
39366         ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
39367         ["pre"],[ "code"], 
39368         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39369     ],
39370      /**
39371      * @cfg {String} defaultFont default font to use.
39372      */
39373     defaultFont: 'tahoma',
39374    
39375     fontSelect : false,
39376     
39377     
39378     formatCombo : false,
39379     
39380     init : function(B)
39381     {
39382         this.editor = B;
39383         
39384         
39385         var  C = B.frameId;
39386         var  D = this;
39387         function  E(id, G, H){
39388             var  I = C + '-'+ id ;
39389             return  {
39390                 id : I,
39391                 cmd : id,
39392                 cls : 'x-btn-icon x-edit-'+id,
39393                 enableToggle:G !== false,
39394                 scope: B, // was editor...
39395                 handler:H||B.relayBtnCmd,
39396                 clickEvent:'mousedown',
39397                 tooltip: D.buttonTips[id] || undefined, ///tips ???
39398                 tabIndex:-1
39399             };
39400         }
39401         
39402         
39403         
39404         var  tb = new  Roo.Toolbar(B.wrap.dom.firstChild);
39405         this.tb = tb;
39406          // stop form submits
39407         tb.el.on('click', function(e){
39408             e.preventDefault(); // what does this do?
39409         });
39410
39411         if(!this.disable.font && !Roo.isSafari){
39412             /* why no safari for fonts
39413             editor.fontSelect = tb.el.createChild({
39414                 tag:'select',
39415                 tabIndex: -1,
39416                 cls:'x-font-select',
39417                 html: editor.createFontOptions()
39418             });
39419             editor.fontSelect.on('change', function(){
39420                 var font = editor.fontSelect.dom.value;
39421                 editor.relayCmd('fontname', font);
39422                 editor.deferFocus();
39423             }, editor);
39424             tb.add(
39425                 editor.fontSelect.dom,
39426                 '-'
39427             );
39428             */
39429         };
39430         if(!this.disable.formats){
39431             this.formatCombo = new  Roo.form.ComboBox({
39432                 store: new  Roo.data.SimpleStore({
39433                     id : 'tag',
39434                     fields: ['tag'],
39435                     data : this.formats // from states.js
39436                 }),
39437                 blockFocus : true,
39438                 //autoCreate : {tag: "div",  size: "20"},
39439                 displayField:'tag',
39440                 typeAhead: false,
39441                 mode: 'local',
39442                 editable : false,
39443                 triggerAction: 'all',
39444                 emptyText:'Add tag',
39445                 selectOnFocus:true,
39446                 width:135,
39447                 listeners : {
39448                     'select': function(c, r, i) {
39449                         B.insertTag(r.get('tag'));
39450                         B.focus();
39451                     }
39452                 }
39453
39454             });
39455             tb.addField(this.formatCombo);
39456             
39457         }
39458         
39459         if(!this.disable.format){
39460             tb.add(
39461                 E('bold'),
39462                 E('italic'),
39463                 E('underline')
39464             );
39465         };
39466         if(!this.disable.fontSize){
39467             tb.add(
39468                 '-',
39469                 
39470                 
39471                 E('increasefontsize', false, B.adjustFont),
39472                 E('decreasefontsize', false, B.adjustFont)
39473             );
39474         };
39475         
39476         
39477         if(this.disable.colors){
39478             tb.add(
39479                 '-', {
39480                     id:B.frameId +'-forecolor',
39481                     cls:'x-btn-icon x-edit-forecolor',
39482                     clickEvent:'mousedown',
39483                     tooltip: this.buttonTips['forecolor'] || undefined,
39484                     tabIndex:-1,
39485                     menu : new  Roo.menu.ColorMenu({
39486                         allowReselect: true,
39487                         focus: Roo.emptyFn,
39488                         value:'000000',
39489                         plain:true,
39490                         selectHandler: function(cp, G){
39491                             B.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+G : G);
39492                             B.deferFocus();
39493                         },
39494                         scope: B,
39495                         clickEvent:'mousedown'
39496                     })
39497                 }, {
39498                     id:B.frameId +'backcolor',
39499                     cls:'x-btn-icon x-edit-backcolor',
39500                     clickEvent:'mousedown',
39501                     tooltip: this.buttonTips['backcolor'] || undefined,
39502                     tabIndex:-1,
39503                     menu : new  Roo.menu.ColorMenu({
39504                         focus: Roo.emptyFn,
39505                         value:'FFFFFF',
39506                         plain:true,
39507                         allowReselect: true,
39508                         selectHandler: function(cp, H){
39509                             if(Roo.isGecko){
39510                                 B.execCmd('useCSS', false);
39511                                 B.execCmd('hilitecolor', H);
39512                                 B.execCmd('useCSS', true);
39513                                 B.deferFocus();
39514                             }else {
39515                                 B.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
39516                                     Roo.isSafari || Roo.isIE ? '#'+H : H);
39517                                 B.deferFocus();
39518                             }
39519                         },
39520                         scope:B,
39521                         clickEvent:'mousedown'
39522                     })
39523                 }
39524             );
39525         };
39526         // now add all the items...
39527         
39528
39529         if(!this.disable.alignments){
39530             tb.add(
39531                 '-',
39532                 E('justifyleft'),
39533                 E('justifycenter'),
39534                 E('justifyright')
39535             );
39536         };
39537
39538         //if(!Roo.isSafari){
39539             if(!this.disable.links){
39540                 tb.add(
39541                     '-',
39542                     E('createlink', false, B.createLink)    /// MOVE TO HERE?!!?!?!?!
39543                 );
39544             };
39545
39546             if(!this.disable.lists){
39547                 tb.add(
39548                     '-',
39549                     E('insertorderedlist'),
39550                     E('insertunorderedlist')
39551                 );
39552             }
39553             if(!this.disable.sourceEdit){
39554                 tb.add(
39555                     '-',
39556                     E('sourceedit', true, function(G){
39557                         this.toggleSourceEdit(G.pressed);
39558                     })
39559                 );
39560             }
39561         //}
39562         
39563         var  F = { };
39564         // special menu.. - needs to be tidied up..
39565         if (!this.disable.special) {
39566             F = {
39567                 text: "&#169;",
39568                 cls: 'x-edit-none',
39569                 menu : {
39570                     items : []
39571                    }
39572             };
39573             for (var  i =0; i < this.specialChars.length; i++) {
39574                 F.menu.items.push({
39575                     
39576                     text: this.specialChars[i],
39577                     handler: function(a,b) {
39578                         B.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
39579                     },
39580                     tabIndex:-1
39581                 });
39582             }
39583
39584             
39585             
39586             tb.add(F);
39587             
39588             
39589         }
39590         if (this.btns) {
39591             for(var  i =0; i< this.btns.length;i++) {
39592                 var  b = this.btns[i];
39593                 b.cls =  'x-edit-none';
39594                 b.scope = B;
39595                 tb.add(b);
39596             }
39597         
39598         }
39599
39600         
39601         
39602         
39603         // disable everything...
39604         
39605         this.tb.items.each(function(G){
39606            if(G.id != B.frameId+ '-sourceedit'){
39607                 G.disable();
39608             }
39609         });
39610         this.rendered = true;
39611         
39612         // the all the btns;
39613         B.on('editorevent', this.updateToolbar, this);
39614         // other toolbars need to implement this..
39615         //editor.on('editmodechange', this.updateToolbar, this);
39616     },
39617     
39618     
39619     
39620     /**
39621      * Protected method that will not generally be called directly. It triggers
39622      * a toolbar update by reading the markup state of the current selection in the editor.
39623      */
39624     updateToolbar: function(){
39625
39626         if(!this.editor.activated){
39627             this.editor.onFirstFocus();
39628             return;
39629         }
39630
39631         var  G = this.tb.items.map, 
39632             H = this.editor.doc,
39633             I = this.editor.frameId;
39634
39635         if(!this.disable.font && !Roo.isSafari){
39636             /*
39637             var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39638             if(name != this.fontSelect.dom.value){
39639                 this.fontSelect.dom.value = name;
39640             }
39641             */
39642         }
39643         if(!this.disable.format){
39644             G[I + '-bold'].toggle(H.queryCommandState('bold'));
39645             G[I + '-italic'].toggle(H.queryCommandState('italic'));
39646             G[I + '-underline'].toggle(H.queryCommandState('underline'));
39647         }
39648         if(!this.disable.alignments){
39649             G[I + '-justifyleft'].toggle(H.queryCommandState('justifyleft'));
39650             G[I + '-justifycenter'].toggle(H.queryCommandState('justifycenter'));
39651             G[I + '-justifyright'].toggle(H.queryCommandState('justifyright'));
39652         }
39653         if(!Roo.isSafari && !this.disable.lists){
39654             G[I + '-insertorderedlist'].toggle(H.queryCommandState('insertorderedlist'));
39655             G[I + '-insertunorderedlist'].toggle(H.queryCommandState('insertunorderedlist'));
39656         }
39657         
39658         var  J = this.editor.getAllAncestors();
39659         if (this.formatCombo) {
39660             
39661             
39662             var  store = this.formatCombo.store;
39663             this.formatCombo.setValue("");
39664             for (var  i =0; i < J.length;i++) {
39665                 if (J[i] && store.query('tag',J[i].tagName.toLowerCase(), true).length) {
39666                     // select it..
39667                     this.formatCombo.setValue(J[i].tagName.toLowerCase());
39668                     break;
39669                 }
39670             }
39671         }
39672
39673         
39674         
39675         
39676         // hides menus... - so this cant be on a menu...
39677         Roo.menu.MenuMgr.hideAll();
39678
39679         //this.editorsyncValue();
39680     },
39681    
39682     
39683     createFontOptions : function(){
39684         var  K = [], fs = this.fontFamilies, ff, lc;
39685         for(var  i = 0, len = fs.length; i< len; i++){
39686             ff = fs[i];
39687             lc = ff.toLowerCase();
39688             K.push(
39689                 '<option value="',lc,'" style="font-family:',ff,';"',
39690                     (this.defaultFont == lc ? ' selected="true">' : '>'),
39691                     ff,
39692                 '</option>'
39693             );
39694         }
39695         return  K.join('');
39696     },
39697     
39698     toggleSourceEdit : function(L){
39699         if(L === undefined){
39700             L = !this.sourceEditMode;
39701         }
39702
39703         this.sourceEditMode = L === true;
39704         var  M = this.tb.items.get(this.editor.frameId +'-sourceedit');
39705         // just toggle the button?
39706         if(M.pressed !== this.editor.sourceEditMode){
39707             M.toggle(this.editor.sourceEditMode);
39708             return;
39709         }
39710         
39711         if(this.sourceEditMode){
39712             this.tb.items.each(function(N){
39713                 if(N.cmd != 'sourceedit'){
39714                     N.disable();
39715                 }
39716             });
39717           
39718         }else {
39719             if(this.initialized){
39720                 this.tb.items.each(function(O){
39721                     O.enable();
39722                 });
39723             }
39724             
39725         }
39726
39727         // tell the editor that it's been pressed..
39728         this.editor.toggleSourceEdit(L);
39729        
39730     },
39731      /**
39732      * Object collection of toolbar tooltips for the buttons in the editor. The key
39733      * is the command id associated with that button and the value is a valid QuickTips object.
39734      * For example:
39735 <pre><code>
39736 {
39737     bold : {
39738         title: 'Bold (Ctrl+B)',
39739         text: 'Make the selected text bold.',
39740         cls: 'x-html-editor-tip'
39741     },
39742     italic : {
39743         title: 'Italic (Ctrl+I)',
39744         text: 'Make the selected text italic.',
39745         cls: 'x-html-editor-tip'
39746     },
39747     ...
39748 </code></pre>
39749     * @type Object
39750      */
39751     buttonTips : {
39752         bold : {
39753             title: 'Bold (Ctrl+B)',
39754             text: 'Make the selected text bold.',
39755             cls: 'x-html-editor-tip'
39756         },
39757         italic : {
39758             title: 'Italic (Ctrl+I)',
39759             text: 'Make the selected text italic.',
39760             cls: 'x-html-editor-tip'
39761         },
39762         underline : {
39763             title: 'Underline (Ctrl+U)',
39764             text: 'Underline the selected text.',
39765             cls: 'x-html-editor-tip'
39766         },
39767         increasefontsize : {
39768             title: 'Grow Text',
39769             text: 'Increase the font size.',
39770             cls: 'x-html-editor-tip'
39771         },
39772         decreasefontsize : {
39773             title: 'Shrink Text',
39774             text: 'Decrease the font size.',
39775             cls: 'x-html-editor-tip'
39776         },
39777         backcolor : {
39778             title: 'Text Highlight Color',
39779             text: 'Change the background color of the selected text.',
39780             cls: 'x-html-editor-tip'
39781         },
39782         forecolor : {
39783             title: 'Font Color',
39784             text: 'Change the color of the selected text.',
39785             cls: 'x-html-editor-tip'
39786         },
39787         justifyleft : {
39788             title: 'Align Text Left',
39789             text: 'Align text to the left.',
39790             cls: 'x-html-editor-tip'
39791         },
39792         justifycenter : {
39793             title: 'Center Text',
39794             text: 'Center text in the editor.',
39795             cls: 'x-html-editor-tip'
39796         },
39797         justifyright : {
39798             title: 'Align Text Right',
39799             text: 'Align text to the right.',
39800             cls: 'x-html-editor-tip'
39801         },
39802         insertunorderedlist : {
39803             title: 'Bullet List',
39804             text: 'Start a bulleted list.',
39805             cls: 'x-html-editor-tip'
39806         },
39807         insertorderedlist : {
39808             title: 'Numbered List',
39809             text: 'Start a numbered list.',
39810             cls: 'x-html-editor-tip'
39811         },
39812         createlink : {
39813             title: 'Hyperlink',
39814             text: 'Make the selected text a hyperlink.',
39815             cls: 'x-html-editor-tip'
39816         },
39817         sourceedit : {
39818             title: 'Source Edit',
39819             text: 'Switch to source editing mode.',
39820             cls: 'x-html-editor-tip'
39821         }
39822     },
39823     // private
39824     onDestroy : function(){
39825         if(this.rendered){
39826             
39827             this.tb.items.each(function(N){
39828                 if(N.menu){
39829                     N.menu.removeAll();
39830                     if(N.menu.el){
39831                         N.menu.el.destroy();
39832                     }
39833                 }
39834
39835                 N.destroy();
39836             });
39837              
39838         }
39839     },
39840     onFirstFocus: function() {
39841         this.tb.items.each(function(N){
39842            N.enable();
39843         });
39844     }
39845 });
39846
39847
39848
39849
39850
39851 // <script type="text/javascript">
39852 /*
39853  * Based on
39854  * Ext JS Library 1.1.1
39855  * Copyright(c) 2006-2007, Ext JS, LLC.
39856  *  
39857  
39858  */
39859
39860  
39861 /**
39862  * @class Roo.form.HtmlEditor.ToolbarContext
39863  * Context Toolbar
39864  * 
39865  * Usage:
39866  *
39867  new Roo.form.HtmlEditor({
39868     ....
39869     toolbars : [
39870         new Roo.form.HtmlEditor.ToolbarStandard(),
39871         new Roo.form.HtmlEditor.ToolbarContext()
39872         })
39873     }
39874      
39875  * 
39876  * @config : {Object} disable List of elements to disable.. (not done yet.)
39877  * 
39878  * 
39879  */
39880
39881 Roo.form.HtmlEditor.ToolbarContext = function(A)
39882 {
39883     
39884     Roo.apply(this, A);
39885     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39886     // dont call parent... till later.
39887 }
39888
39889 Roo.form.HtmlEditor.ToolbarContext.types = {
39890     'IMG' : {
39891         width : {
39892             title: "Width",
39893             width: 40
39894         },
39895         height:  {
39896             title: "Height",
39897             width: 40
39898         },
39899         align: {
39900             title: "Align",
39901             opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39902             width : 80
39903             
39904         },
39905         border: {
39906             title: "Border",
39907             width: 40
39908         },
39909         alt: {
39910             title: "Alt",
39911             width: 120
39912         },
39913         src : {
39914             title: "Src",
39915             width: 220
39916         }
39917         
39918     },
39919     'A' : {
39920         name : {
39921             title: "Name",
39922             width: 50
39923         },
39924         href:  {
39925             title: "Href",
39926             width: 220
39927         } // border?
39928         
39929     },
39930     'TABLE' : {
39931         rows : {
39932             title: "Rows",
39933             width: 20
39934         },
39935         cols : {
39936             title: "Cols",
39937             width: 20
39938         },
39939         width : {
39940             title: "Width",
39941             width: 40
39942         },
39943         height : {
39944             title: "Height",
39945             width: 40
39946         },
39947         border : {
39948             title: "Border",
39949             width: 20
39950         }
39951     },
39952     'TD' : {
39953         width : {
39954             title: "Width",
39955             width: 40
39956         },
39957         height : {
39958             title: "Height",
39959             width: 40
39960         },   
39961         align: {
39962             title: "Align",
39963             opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39964             width: 40
39965         },
39966         valign: {
39967             title: "Valign",
39968             opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39969             width: 40
39970         },
39971         colspan: {
39972             title: "Colspan",
39973             width: 20
39974             
39975         }
39976     },
39977     'INPUT' : {
39978         name : {
39979             title: "name",
39980             width: 120
39981         },
39982         value : {
39983             title: "Value",
39984             width: 120
39985         },
39986         width : {
39987             title: "Width",
39988             width: 40
39989         }
39990     },
39991     'LABEL' : {
39992         'for' : {
39993             title: "For",
39994             width: 120
39995         }
39996     },
39997     'TEXTAREA' : {
39998           name : {
39999             title: "name",
40000             width: 120
40001         },
40002         rows : {
40003             title: "Rows",
40004             width: 20
40005         },
40006         cols : {
40007             title: "Cols",
40008             width: 20
40009         }
40010     },
40011     'SELECT' : {
40012         name : {
40013             title: "name",
40014             width: 120
40015         },
40016         selectoptions : {
40017             title: "Options",
40018             width: 200
40019         }
40020     },
40021     'BODY' : {
40022         title : {
40023             title: "title",
40024             width: 120,
40025             disabled : true
40026         }
40027     }
40028 };
40029
40030
40031
40032 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
40033     
40034     tb: false,
40035     
40036     rendered: false,
40037     
40038     editor : false,
40039     /**
40040      * @cfg {Object} disable  List of toolbar elements to disable
40041          
40042      */
40043     disable : false,
40044     
40045     
40046     
40047     toolbars : false,
40048     
40049     init : function(B)
40050     {
40051         this.editor = B;
40052         
40053         
40054         var  C = B.frameId;
40055         var  D = this;
40056         function  E(id, G, H){
40057             var  I = C + '-'+ id ;
40058             return  {
40059                 id : I,
40060                 cmd : id,
40061                 cls : 'x-btn-icon x-edit-'+id,
40062                 enableToggle:G !== false,
40063                 scope: B, // was editor...
40064                 handler:H||B.relayBtnCmd,
40065                 clickEvent:'mousedown',
40066                 tooltip: D.buttonTips[id] || undefined, ///tips ???
40067                 tabIndex:-1
40068             };
40069         }
40070         // create a new element.
40071         var  F = B.wrap.createChild({
40072                 tag: 'div'
40073             }, B.wrap.dom.firstChild.nextSibling, true);
40074         
40075         // can we do this more than once??
40076         
40077          // stop form submits
40078       
40079  
40080         // disable everything...
40081         var  ty= Roo.form.HtmlEditor.ToolbarContext.types;
40082         this.toolbars = {};
40083            
40084         for (var  i  in   ty) {
40085             this.toolbars[i] = this.buildToolbar(ty[i],i);
40086         }
40087
40088         this.tb = this.toolbars.BODY;
40089         this.tb.el.show();
40090         
40091          
40092         this.rendered = true;
40093         
40094         // the all the btns;
40095         B.on('editorevent', this.updateToolbar, this);
40096         // other toolbars need to implement this..
40097         //editor.on('editmodechange', this.updateToolbar, this);
40098     },
40099     
40100     
40101     
40102     /**
40103      * Protected method that will not generally be called directly. It triggers
40104      * a toolbar update by reading the markup state of the current selection in the editor.
40105      */
40106     updateToolbar: function(){
40107
40108         if(!this.editor.activated){
40109             this.editor.onFirstFocus();
40110             return;
40111         }
40112
40113         
40114         var  G = this.editor.getAllAncestors();
40115         
40116         // pick
40117         var  ty= Roo.form.HtmlEditor.ToolbarContext.types;
40118         var  H = G.length ? (G[0] ?  G[0]  : G[1]) : this.editor.doc.body;
40119         H = H ? H : this.editor.doc.body;
40120         H = H.tagName.length ? H : this.editor.doc.body;
40121         var  tn = H.tagName.toUpperCase();
40122         H = typeof(ty[tn]) != 'undefined' ? H : this.editor.doc.body;
40123         tn = H.tagName.toUpperCase();
40124         if (this.tb.name  == tn) {
40125             return; // no change
40126         }
40127
40128         this.tb.el.hide();
40129         ///console.log("show: " + tn);
40130         this.tb =  this.toolbars[tn];
40131         this.tb.el.show();
40132         this.tb.fields.each(function(e) {
40133             e.setValue(H.getAttribute(e.name));
40134         });
40135         this.tb.selectedNode = H;
40136         
40137         
40138         Roo.menu.MenuMgr.hideAll();
40139
40140         //this.editorsyncValue();
40141     },
40142    
40143        
40144     // private
40145     onDestroy : function(){
40146         if(this.rendered){
40147             
40148             this.tb.items.each(function(I){
40149                 if(I.menu){
40150                     I.menu.removeAll();
40151                     if(I.menu.el){
40152                         I.menu.el.destroy();
40153                     }
40154                 }
40155
40156                 I.destroy();
40157             });
40158              
40159         }
40160     },
40161     onFirstFocus: function() {
40162         // need to do this for all the toolbars..
40163         this.tb.items.each(function(I){
40164            I.enable();
40165         });
40166     },
40167     buildToolbar: function(I, nm)
40168     {
40169         var  J = this.editor;
40170          // create a new element.
40171         var  K = J.wrap.createChild({
40172                 tag: 'div'
40173             }, J.wrap.dom.firstChild.nextSibling, true);
40174         
40175        
40176         var  tb = new  Roo.Toolbar(K);
40177         tb.add(nm+ ":&nbsp;");
40178         for (var  i  in  I) {
40179             var  item = I[i];
40180             tb.add(item.title + ":&nbsp;");
40181             if (item.opts) {
40182                 // fixme
40183                 
40184               
40185                 tb.addField( new  Roo.form.ComboBox({
40186                     store: new  Roo.data.SimpleStore({
40187                         id : 'val',
40188                         fields: ['val'],
40189                         data : item.opts // from states.js
40190                     }),
40191                     name : i,
40192                     displayField:'val',
40193                     typeAhead: false,
40194                     mode: 'local',
40195                     editable : false,
40196                     triggerAction: 'all',
40197                     emptyText:'Select',
40198                     selectOnFocus:true,
40199                     width: item.width ? item.width  : 130,
40200                     listeners : {
40201                         'select': function(c, r, i) {
40202                             tb.selectedNode.setAttribute(c.name, r.get('val'));
40203                         }
40204                     }
40205
40206                 }));
40207                 continue;
40208                     
40209                 
40210                 
40211                 
40212                 
40213                 tb.addField( new  Roo.form.TextField({
40214                     name: i,
40215                     width: 100,
40216                     //allowBlank:false,
40217                     value: ''
40218                 }));
40219                 continue;
40220             }
40221
40222             tb.addField( new  Roo.form.TextField({
40223                 name: i,
40224                 width: item.width,
40225                 //allowBlank:true,
40226                 value: '',
40227                 listeners: {
40228                     'change' : function(f, nv, ov) {
40229                         tb.selectedNode.setAttribute(f.name, nv);
40230                     }
40231                 }
40232             }));
40233              
40234         }
40235
40236         tb.el.on('click', function(e){
40237             e.preventDefault(); // what does this do?
40238         });
40239         tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40240         tb.el.hide();
40241         tb.name = nm;
40242         // dont need to disable them... as they will get hidden
40243         return  tb;
40244          
40245         
40246     }
40247     
40248     
40249     
40250     
40251 });
40252
40253
40254
40255
40256
40257
40258 /*
40259  * Based on:
40260  * Ext JS Library 1.1.1
40261  * Copyright(c) 2006-2007, Ext JS, LLC.
40262  *
40263  * Originally Released Under LGPL - original licence link has changed is not relivant.
40264  *
40265  * Fork - LGPL
40266  * <script type="text/javascript">
40267  */
40268  
40269 /**
40270  * @class Roo.form.BasicForm
40271  * @extends Roo.util.Observable
40272  * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40273  * @constructor
40274  * @param {String/HTMLElement/Roo.Element} el The form element or its id
40275  * @param {Object} config Configuration options
40276  */
40277 Roo.form.BasicForm = function(el, A){
40278     Roo.apply(this, A);
40279     /*
40280      * The Roo.form.Field items in this form.
40281      * @type MixedCollection
40282      */
40283     this.items = new  Roo.util.MixedCollection(false, function(o){
40284         return  o.id || (o.id = Roo.id());
40285     });
40286     this.addEvents({
40287         /**
40288          * @event beforeaction
40289          * Fires before any action is performed. Return false to cancel the action.
40290          * @param {Form} this
40291          * @param {Action} action The action to be performed
40292          */
40293         beforeaction: true,
40294         /**
40295          * @event actionfailed
40296          * Fires when an action fails.
40297          * @param {Form} this
40298          * @param {Action} action The action that failed
40299          */
40300         actionfailed : true,
40301         /**
40302          * @event actioncomplete
40303          * Fires when an action is completed.
40304          * @param {Form} this
40305          * @param {Action} action The action that completed
40306          */
40307         actioncomplete : true
40308     });
40309     if(el){
40310         this.initEl(el);
40311     }
40312
40313     Roo.form.BasicForm.superclass.constructor.call(this);
40314 };
40315
40316 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40317     /**
40318      * @cfg {String} method
40319      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40320      */
40321     /**
40322      * @cfg {DataReader} reader
40323      * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40324      * This is optional as there is built-in support for processing JSON.
40325      */
40326     /**
40327      * @cfg {DataReader} errorReader
40328      * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40329      * This is completely optional as there is built-in support for processing JSON.
40330      */
40331     /**
40332      * @cfg {String} url
40333      * The URL to use for form actions if one isn't supplied in the action options.
40334      */
40335     /**
40336      * @cfg {Boolean} fileUpload
40337      * Set to true if this form is a file upload.
40338      */
40339     /**
40340      * @cfg {Object} baseParams
40341      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40342      */
40343     /**
40344      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40345      */
40346     timeout: 30,
40347
40348     // private
40349     activeAction : null,
40350
40351     /**
40352      * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40353      * or setValues() data instead of when the form was first created.
40354      */
40355     trackResetOnLoad : false,
40356
40357     /**
40358      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40359      * element by passing it or its id or mask the form itself by passing in true.
40360      * @type Mixed
40361      */
40362     waitMsgTarget : undefined,
40363
40364     // private
40365     initEl : function(el){
40366         this.el = Roo.get(el);
40367         this.id = this.el.id || Roo.id();
40368         this.el.on('submit', this.onSubmit, this);
40369         this.el.addClass('x-form');
40370     },
40371
40372     // private
40373     onSubmit : function(e){
40374         e.stopEvent();
40375     },
40376
40377     /**
40378      * Returns true if client-side validation on the form is successful.
40379      * @return Boolean
40380      */
40381     isValid : function(){
40382         var  B = true;
40383         this.items.each(function(f){
40384            if(!f.validate()){
40385                B = false;
40386            }
40387         });
40388         return  B;
40389     },
40390
40391     /**
40392      * Returns true if any fields in this form have changed since their original load.
40393      * @return Boolean
40394      */
40395     isDirty : function(){
40396         var  C = false;
40397         this.items.each(function(f){
40398            if(f.isDirty()){
40399                C = true;
40400                return  false;
40401            }
40402         });
40403         return  C;
40404     },
40405
40406     /**
40407      * Performs a predefined action (submit or load) or custom actions you define on this form.
40408      * @param {String} actionName The name of the action type
40409      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
40410      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40411      * accept other config options):
40412      * <pre>
40413 Property          Type             Description
40414 ----------------  ---------------  ----------------------------------------------------------------------------------
40415 url               String           The url for the action (defaults to the form's url)
40416 method            String           The form method to use (defaults to the form's method, or POST if not defined)
40417 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
40418 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
40419                                    validate the form on the client (defaults to false)
40420      * </pre>
40421      * @return {BasicForm} this
40422      */
40423     doAction : function(D, E){
40424         if(typeof  D == 'string'){
40425             D = new  Roo.form.Action.ACTION_TYPES[D](this, E);
40426         }
40427         if(this.fireEvent('beforeaction', this, D) !== false){
40428             this.beforeAction(D);
40429             D.run.defer(100, D);
40430         }
40431         return  this;
40432     },
40433
40434     /**
40435      * Shortcut to do a submit action.
40436      * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40437      * @return {BasicForm} this
40438      */
40439     submit : function(F){
40440         this.doAction('submit', F);
40441         return  this;
40442     },
40443
40444     /**
40445      * Shortcut to do a load action.
40446      * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40447      * @return {BasicForm} this
40448      */
40449     load : function(G){
40450         this.doAction('load', G);
40451         return  this;
40452     },
40453
40454     /**
40455      * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40456      * @param {Record} record The record to edit
40457      * @return {BasicForm} this
40458      */
40459     updateRecord : function(H){
40460         H.beginEdit();
40461         var  fs = H.fields;
40462         fs.each(function(f){
40463             var  I = this.findField(f.name);
40464             if(I){
40465                 H.set(f.name, I.getValue());
40466             }
40467         }, this);
40468         H.endEdit();
40469         return  this;
40470     },
40471
40472     /**
40473      * Loads an Roo.data.Record into this form.
40474      * @param {Record} record The record to load
40475      * @return {BasicForm} this
40476      */
40477     loadRecord : function(I){
40478         this.setValues(I.data);
40479         return  this;
40480     },
40481
40482     // private
40483     beforeAction : function(J){
40484         var  o = J.options;
40485         if(o.waitMsg){
40486             if(this.waitMsgTarget === true){
40487                 this.el.mask(o.waitMsg, 'x-mask-loading');
40488             }else  if(this.waitMsgTarget){
40489                 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40490                 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40491             }else {
40492                 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40493             }
40494         }
40495     },
40496
40497     // private
40498     afterAction : function(K, L){
40499         this.activeAction = null;
40500         var  o = K.options;
40501         if(o.waitMsg){
40502             if(this.waitMsgTarget === true){
40503                 this.el.unmask();
40504             }else  if(this.waitMsgTarget){
40505                 this.waitMsgTarget.unmask();
40506             }else {
40507                 Roo.MessageBox.updateProgress(1);
40508                 Roo.MessageBox.hide();
40509             }
40510         }
40511         if(L){
40512             if(o.reset){
40513                 this.reset();
40514             }
40515
40516             Roo.callback(o.success, o.scope, [this, K]);
40517             this.fireEvent('actioncomplete', this, K);
40518         }else {
40519             Roo.callback(o.failure, o.scope, [this, K]);
40520             this.fireEvent('actionfailed', this, K);
40521         }
40522     },
40523
40524     /**
40525      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40526      * @param {String} id The value to search for
40527      * @return Field
40528      */
40529     findField : function(id){
40530         var  M = this.items.get(id);
40531         if(!M){
40532             this.items.each(function(f){
40533                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40534                     M = f;
40535                     return  false;
40536                 }
40537             });
40538         }
40539         return  M || null;
40540     },
40541
40542
40543     /**
40544      * Mark fields in this form invalid in bulk.
40545      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40546      * @return {BasicForm} this
40547      */
40548     markInvalid : function(N){
40549         if(N  instanceof  Array){
40550             for(var  i = 0, len = N.length; i < len; i++){
40551                 var  fieldError = N[i];
40552                 var  f = this.findField(fieldError.id);
40553                 if(f){
40554                     f.markInvalid(fieldError.msg);
40555                 }
40556             }
40557         }else {
40558             var  M, id;
40559             for(id  in  N){
40560                 if(typeof  N[id] != 'function' && (M = this.findField(id))){
40561                     M.markInvalid(N[id]);
40562                 }
40563             }
40564         }
40565         return  this;
40566     },
40567
40568     /**
40569      * Set values for fields in this form in bulk.
40570      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40571      * @return {BasicForm} this
40572      */
40573     setValues : function(O){
40574         if(O  instanceof  Array){ // array of objects
40575             for(var  i = 0, len = O.length; i < len; i++){
40576                 var  v = O[i];
40577                 var  f = this.findField(v.id);
40578                 if(f){
40579                     f.setValue(v.value);
40580                     if(this.trackResetOnLoad){
40581                         f.originalValue = f.getValue();
40582                     }
40583                 }
40584             }
40585         }else { // object hash
40586             var  M, id;
40587             for(id  in  O){
40588                 if(typeof  O[id] != 'function' && (M = this.findField(id))){
40589                     
40590                     if (M.setFromData && 
40591                         M.valueField && 
40592                         M.displayField &&
40593                         // combos' with local stores can 
40594                         // be queried via setValue()
40595                         // to set their value..
40596                         (M.store && !M.store.isLocal)
40597                         ) {
40598                         // it's a combo
40599                         var  sd = { };
40600                         sd[M.valueField] = typeof(O[M.hiddenName]) == 'undefined' ? '' : O[M.hiddenName];
40601                         sd[M.displayField] = typeof(O[M.name]) == 'undefined' ? '' : O[M.name];
40602                         M.setFromData(sd);
40603                         
40604                     } else  {
40605                         M.setValue(O[id]);
40606                     }
40607                     
40608                     
40609                     if(this.trackResetOnLoad){
40610                         M.originalValue = M.getValue();
40611                     }
40612                 }
40613             }
40614         }
40615         return  this;
40616     },
40617
40618     /**
40619      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40620      * they are returned as an array.
40621      * @param {Boolean} asString
40622      * @return {Object}
40623      */
40624     getValues : function(P){
40625         var  fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40626         if(P === true){
40627             return  fs;
40628         }
40629         return  Roo.urlDecode(fs);
40630     },
40631
40632     /**
40633      * Clears all invalid messages in this form.
40634      * @return {BasicForm} this
40635      */
40636     clearInvalid : function(){
40637         this.items.each(function(f){
40638            f.clearInvalid();
40639         });
40640         return  this;
40641     },
40642
40643     /**
40644      * Resets this form.
40645      * @return {BasicForm} this
40646      */
40647     reset : function(){
40648         this.items.each(function(f){
40649             f.reset();
40650         });
40651         return  this;
40652     },
40653
40654     /**
40655      * Add Roo.form components to this form.
40656      * @param {Field} field1
40657      * @param {Field} field2 (optional)
40658      * @param {Field} etc (optional)
40659      * @return {BasicForm} this
40660      */
40661     add : function(){
40662         this.items.addAll(Array.prototype.slice.call(arguments, 0));
40663         return  this;
40664     },
40665
40666
40667     /**
40668      * Removes a field from the items collection (does NOT remove its markup).
40669      * @param {Field} field
40670      * @return {BasicForm} this
40671      */
40672     remove : function(Q){
40673         this.items.remove(Q);
40674         return  this;
40675     },
40676
40677     /**
40678      * Looks at the fields in this form, checks them for an id attribute,
40679      * and calls applyTo on the existing dom element with that id.
40680      * @return {BasicForm} this
40681      */
40682     render : function(){
40683         this.items.each(function(f){
40684             if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40685                 f.applyTo(f.id);
40686             }
40687         });
40688         return  this;
40689     },
40690
40691     /**
40692      * Calls {@link Ext#apply} for all fields in this form with the passed object.
40693      * @param {Object} values
40694      * @return {BasicForm} this
40695      */
40696     applyToFields : function(o){
40697         this.items.each(function(f){
40698            Roo.apply(f, o);
40699         });
40700         return  this;
40701     },
40702
40703     /**
40704      * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40705      * @param {Object} values
40706      * @return {BasicForm} this
40707      */
40708     applyIfToFields : function(o){
40709         this.items.each(function(f){
40710            Roo.applyIf(f, o);
40711         });
40712         return  this;
40713     }
40714 });
40715
40716 // back compat
40717 Roo.BasicForm = Roo.form.BasicForm;
40718 /*
40719  * Based on:
40720  * Ext JS Library 1.1.1
40721  * Copyright(c) 2006-2007, Ext JS, LLC.
40722  *
40723  * Originally Released Under LGPL - original licence link has changed is not relivant.
40724  *
40725  * Fork - LGPL
40726  * <script type="text/javascript">
40727  */
40728
40729 /**
40730  * @class Roo.form.Form
40731  * @extends Roo.form.BasicForm
40732  * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40733  * @constructor
40734  * @param {Object} config Configuration options
40735  */
40736 Roo.form.Form = function(A){
40737     var  B =  [];
40738     if (A.items) {
40739         B = A.items;
40740         delete  A.items;
40741     }
40742
40743     
40744     
40745     Roo.form.Form.superclass.constructor.call(this, null, A);
40746     this.url = this.url || this.action;
40747     if(!this.root){
40748         this.root = new  Roo.form.Layout(Roo.applyIf({
40749             id: Roo.id()
40750         }, A));
40751     }
40752
40753     this.active = this.root;
40754     /**
40755      * Array of all the buttons that have been added to this form via {@link addButton}
40756      * @type Array
40757      */
40758     this.buttons = [];
40759     this.allItems = [];
40760     this.addEvents({
40761         /**
40762          * @event clientvalidation
40763          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40764          * @param {Form} this
40765          * @param {Boolean} valid true if the form has passed client-side validation
40766          */
40767         clientvalidation: true,
40768         /**
40769          * @event rendered
40770          * Fires when the form is rendered
40771          * @param {Roo.form.Form} form
40772          */
40773         rendered : true
40774     });
40775     
40776     Roo.each(B, this.addxtype, this);
40777     
40778     
40779     
40780 };
40781
40782 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40783     /**
40784      * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40785      */
40786     /**
40787      * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40788      */
40789     /**
40790      * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40791      */
40792     buttonAlign:'center',
40793
40794     /**
40795      * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40796      */
40797     minButtonWidth:75,
40798
40799     /**
40800      * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40801      * This property cascades to child containers if not set.
40802      */
40803     labelAlign:'left',
40804
40805     /**
40806      * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40807      * fires a looping event with that state. This is required to bind buttons to the valid
40808      * state using the config value formBind:true on the button.
40809      */
40810     monitorValid : false,
40811
40812     /**
40813      * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40814      */
40815     monitorPoll : 200,
40816
40817     /**
40818      * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40819      * fields are added and the column is closed. If no fields are passed the column remains open
40820      * until end() is called.
40821      * @param {Object} config The config to pass to the column
40822      * @param {Field} field1 (optional)
40823      * @param {Field} field2 (optional)
40824      * @param {Field} etc (optional)
40825      * @return Column The column container object
40826      */
40827     column : function(c){
40828         var  C = new  Roo.form.Column(c);
40829         this.start(C);
40830         if(arguments.length > 1){ // duplicate code required because of Opera
40831             this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40832             this.end();
40833         }
40834         return  C;
40835     },
40836
40837     /**
40838      * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40839      * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40840      * until end() is called.
40841      * @param {Object} config The config to pass to the fieldset
40842      * @param {Field} field1 (optional)
40843      * @param {Field} field2 (optional)
40844      * @param {Field} etc (optional)
40845      * @return FieldSet The fieldset container object
40846      */
40847     fieldset : function(c){
40848         var  fs = new  Roo.form.FieldSet(c);
40849         this.start(fs);
40850         if(arguments.length > 1){ // duplicate code required because of Opera
40851             this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40852             this.end();
40853         }
40854         return  fs;
40855     },
40856
40857     /**
40858      * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40859      * fields are added and the container is closed. If no fields are passed the container remains open
40860      * until end() is called.
40861      * @param {Object} config The config to pass to the Layout
40862      * @param {Field} field1 (optional)
40863      * @param {Field} field2 (optional)
40864      * @param {Field} etc (optional)
40865      * @return Layout The container object
40866      */
40867     container : function(c){
40868         var  l = new  Roo.form.Layout(c);
40869         this.start(l);
40870         if(arguments.length > 1){ // duplicate code required because of Opera
40871             this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40872             this.end();
40873         }
40874         return  l;
40875     },
40876
40877     /**
40878      * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40879      * @param {Object} container A Roo.form.Layout or subclass of Layout
40880      * @return {Form} this
40881      */
40882     start : function(c){
40883         // cascade label info
40884         Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40885         this.active.stack.push(c);
40886         c.ownerCt = this.active;
40887         this.active = c;
40888         return  this;
40889     },
40890
40891     /**
40892      * Closes the current open container
40893      * @return {Form} this
40894      */
40895     end : function(){
40896         if(this.active == this.root){
40897             return  this;
40898         }
40899
40900         this.active = this.active.ownerCt;
40901         return  this;
40902     },
40903
40904     /**
40905      * Add Roo.form components to the current open container (e.g. column, fieldset, etc.).  Fields added via this method
40906      * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40907      * as the label of the field.
40908      * @param {Field} field1
40909      * @param {Field} field2 (optional)
40910      * @param {Field} etc. (optional)
40911      * @return {Form} this
40912      */
40913     add : function(){
40914         this.active.stack.push.apply(this.active.stack, arguments);
40915         this.allItems.push.apply(this.allItems,arguments);
40916         var  r = [];
40917         for(var  i = 0, a = arguments, len = a.length; i < len; i++) {
40918             if(a[i].isFormField){
40919                 r.push(a[i]);
40920             }
40921         }
40922         if(r.length > 0){
40923             Roo.form.Form.superclass.add.apply(this, r);
40924         }
40925         return  this;
40926     },
40927      /**
40928      * Find any element that has been added to a form, using it's ID or name
40929      * This can include framesets, columns etc. along with regular fields..
40930      * @param {String} id - id or name to find.
40931      
40932      * @return {Element} e - or false if nothing found.
40933      */
40934     findbyId : function(id)
40935     {
40936         var  D = false;
40937         if (!id) {
40938             return  D;
40939         }
40940
40941         Ext.each(this.allItems, function(f){
40942             if (f.id == id || f.name == id ){
40943                 D = f;
40944                 return  false;
40945             }
40946         });
40947         return  D;
40948     },
40949
40950     
40951     
40952     /**
40953      * Render this form into the passed container. This should only be called once!
40954      * @param {String/HTMLElement/Element} container The element this component should be rendered into
40955      * @return {Form} this
40956      */
40957     render : function(ct){
40958         ct = Roo.get(ct);
40959         var  o = this.autoCreate || {
40960             tag: 'form',
40961             method : this.method || 'POST',
40962             id : this.id || Roo.id()
40963         };
40964         this.initEl(ct.createChild(o));
40965
40966         this.root.render(this.el);
40967
40968         this.items.each(function(f){
40969             f.render('x-form-el-'+f.id);
40970         });
40971
40972         if(this.buttons.length > 0){
40973             // tables are required to maintain order and for correct IE layout
40974             var  tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40975                 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40976                 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40977             }}, null, true);
40978             var  tr = tb.getElementsByTagName('tr')[0];
40979             for(var  i = 0, len = this.buttons.length; i < len; i++) {
40980                 var  b = this.buttons[i];
40981                 var  td = document.createElement('td');
40982                 td.className = 'x-form-btn-td';
40983                 b.render(tr.appendChild(td));
40984             }
40985         }
40986         if(this.monitorValid){ // initialize after render
40987             this.startMonitoring();
40988         }
40989
40990         this.fireEvent('rendered', this);
40991         return  this;
40992     },
40993
40994     /**
40995      * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40996      * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40997      * object or a valid Roo.DomHelper element config
40998      * @param {Function} handler The function called when the button is clicked
40999      * @param {Object} scope (optional) The scope of the handler function
41000      * @return {Roo.Button}
41001      */
41002     addButton : function(E, F, G){
41003         var  bc = {
41004             handler: F,
41005             scope: G,
41006             minWidth: this.minButtonWidth,
41007             hideParent:true
41008         };
41009         if(typeof  E == "string"){
41010             bc.text = E;
41011         }else {
41012             Roo.apply(bc, E);
41013         }
41014         var  H = new  Roo.Button(null, bc);
41015         this.buttons.push(H);
41016         return  H;
41017     },
41018
41019      /**
41020      * Adds a series of form elements (using the xtype property as the factory method.
41021      * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41022      * @param {Object} config 
41023      */
41024     
41025     addxtype : function()
41026     {
41027         var  ar = Array.prototype.slice.call(arguments, 0);
41028         var  I = false;
41029         for(var  i = 0; i < ar.length; i++) {
41030             if (!ar[i]) {
41031                 continue; // skip -- if this happends something invalid got sent, we 
41032                 // should ignore it, as basically that interface element will not show up
41033                 // and that should be pretty obvious!!
41034             }
41035             
41036             if (Roo.form[ar[i].xtype]) {
41037                 ar[i].form = this;
41038                 var  fe = Roo.factory(ar[i], Roo.form);
41039                 if (!I) {
41040                     I = fe;
41041                 }
41042
41043                 fe.form = this;
41044                 if (fe.store) {
41045                     fe.store.form = this;
41046                 }
41047                 if (fe.isLayout) {  
41048                          
41049                     this.start(fe);
41050                     this.allItems.push(fe);
41051                     if (fe.items && fe.addxtype) {
41052                         fe.addxtype.apply(fe, fe.items);
41053                         delete  fe.items;
41054                     }
41055
41056                      this.end();
41057                     continue;
41058                 }
41059
41060                 
41061                 
41062                  
41063                 this.add(fe);
41064               //  console.log('adding ' + ar[i].xtype);
41065             }
41066             if (ar[i].xtype == 'Button') {  
41067                 //console.log('adding button');
41068                 //console.log(ar[i]);
41069                 this.addButton(ar[i]);
41070                 this.allItems.push(fe);
41071                 continue;
41072             }
41073             
41074             if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41075                 alert('end is not supported on xtype any more, use items');
41076             //    this.end();
41077             //    //console.log('adding end');
41078             }
41079             
41080         }
41081         return  I;
41082     },
41083     
41084     /**
41085      * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41086      * option "monitorValid"
41087      */
41088     startMonitoring : function(){
41089         if(!this.bound){
41090             this.bound = true;
41091             Roo.TaskMgr.start({
41092                 run : this.bindHandler,
41093                 interval : this.monitorPoll || 200,
41094                 scope: this
41095             });
41096         }
41097     },
41098
41099     /**
41100      * Stops monitoring of the valid state of this form
41101      */
41102     stopMonitoring : function(){
41103         this.bound = false;
41104     },
41105
41106     // private
41107     bindHandler : function(){
41108         if(!this.bound){
41109             return  false; // stops binding
41110         }
41111         var  J = true;
41112         this.items.each(function(f){
41113             if(!f.isValid(true)){
41114                 J = false;
41115                 return  false;
41116             }
41117         });
41118         for(var  i = 0, len = this.buttons.length; i < len; i++){
41119             var  H = this.buttons[i];
41120             if(H.formBind === true && H.disabled === J){
41121                 H.setDisabled(!J);
41122             }
41123         }
41124
41125         this.fireEvent('clientvalidation', this, J);
41126     }
41127     
41128     
41129     
41130     
41131     
41132     
41133     
41134     
41135 });
41136
41137
41138 // back compat
41139 Roo.Form = Roo.form.Form;
41140
41141 /*
41142  * Based on:
41143  * Ext JS Library 1.1.1
41144  * Copyright(c) 2006-2007, Ext JS, LLC.
41145  *
41146  * Originally Released Under LGPL - original licence link has changed is not relivant.
41147  *
41148  * Fork - LGPL
41149  * <script type="text/javascript">
41150  */
41151  
41152  /**
41153  * @class Roo.form.Action
41154  * Internal Class used to handle form actions
41155  * @constructor
41156  * @param {Roo.form.BasicForm} el The form element or its id
41157  * @param {Object} config Configuration options
41158  */
41159  
41160  
41161 // define the action interface
41162 Roo.form.Action = function(A, B){
41163     this.form = A;
41164     this.options = B || {};
41165 };
41166 /**
41167  * Client Validation Failed
41168  * @const 
41169  */
41170 Roo.form.Action.CLIENT_INVALID = 'client';
41171 /**
41172  * Server Validation Failed
41173  * @const 
41174  */
41175  Roo.form.Action.SERVER_INVALID = 'server';
41176  /**
41177  * Connect to Server Failed
41178  * @const 
41179  */
41180 Roo.form.Action.CONNECT_FAILURE = 'connect';
41181 /**
41182  * Reading Data from Server Failed
41183  * @const 
41184  */
41185 Roo.form.Action.LOAD_FAILURE = 'load';
41186
41187 Roo.form.Action.prototype = {
41188     type : 'default',
41189     failureType : undefined,
41190     response : undefined,
41191     result : undefined,
41192
41193     // interface method
41194     run : function(C){
41195
41196     },
41197
41198     // interface method
41199     success : function(D){
41200
41201     },
41202
41203     // interface method
41204     handleResponse : function(E){
41205
41206     },
41207
41208     // default connection failure
41209     failure : function(F){
41210         this.response = F;
41211         this.failureType = Roo.form.Action.CONNECT_FAILURE;
41212         this.form.afterAction(this, false);
41213     },
41214
41215     processResponse : function(G){
41216         this.response = G;
41217         if(!G.responseText){
41218             return  true;
41219         }
41220
41221         this.result = this.handleResponse(G);
41222         return  this.result;
41223     },
41224
41225     // utility functions used internally
41226     getUrl : function(H){
41227         var  I = this.options.url || this.form.url || this.form.el.dom.action;
41228         if(H){
41229             var  p = this.getParams();
41230             if(p){
41231                 I += (I.indexOf('?') != -1 ? '&' : '?') + p;
41232             }
41233         }
41234         return  I;
41235     },
41236
41237     getMethod : function(){
41238         return  (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41239     },
41240
41241     getParams : function(){
41242         var  bp = this.form.baseParams;
41243         var  p = this.options.params;
41244         if(p){
41245             if(typeof  p == "object"){
41246                 p = Roo.urlEncode(Roo.applyIf(p, bp));
41247             }else  if(typeof  p == 'string' && bp){
41248                 p += '&' + Roo.urlEncode(bp);
41249             }
41250         }else  if(bp){
41251             p = Roo.urlEncode(bp);
41252         }
41253         return  p;
41254     },
41255
41256     createCallback : function(){
41257         return  {
41258             success: this.success,
41259             failure: this.failure,
41260             scope: this,
41261             timeout: (this.form.timeout*1000),
41262             upload: this.form.fileUpload ? this.success : undefined
41263         };
41264     }
41265 };
41266
41267 Roo.form.Action.Submit = function(J, K){
41268     Roo.form.Action.Submit.superclass.constructor.call(this, J, K);
41269 };
41270
41271 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41272     type : 'submit',
41273
41274     run : function(){
41275         var  o = this.options;
41276         var  L = this.getMethod();
41277         var  M = L == 'POST';
41278         if(o.clientValidation === false || this.form.isValid()){
41279             Roo.Ajax.request(Roo.apply(this.createCallback(), {
41280                 form:this.form.el.dom,
41281                 url:this.getUrl(!M),
41282                 method: L,
41283                 params:M ? this.getParams() : null,
41284                 isUpload: this.form.fileUpload
41285             }));
41286
41287         }else  if (o.clientValidation !== false){ // client validation failed
41288             this.failureType = Roo.form.Action.CLIENT_INVALID;
41289             this.form.afterAction(this, false);
41290         }
41291     },
41292
41293     success : function(N){
41294         var  O = this.processResponse(N);
41295         if(O === true || O.success){
41296             this.form.afterAction(this, true);
41297             return;
41298         }
41299         if(O.errors){
41300             this.form.markInvalid(O.errors);
41301             this.failureType = Roo.form.Action.SERVER_INVALID;
41302         }
41303
41304         this.form.afterAction(this, false);
41305     },
41306
41307     handleResponse : function(P){
41308         if(this.form.errorReader){
41309             var  rs = this.form.errorReader.read(P);
41310             var  errors = [];
41311             if(rs.records){
41312                 for(var  i = 0, len = rs.records.length; i < len; i++) {
41313                     var  r = rs.records[i];
41314                     errors[i] = r.data;
41315                 }
41316             }
41317             if(errors.length < 1){
41318                 errors = null;
41319             }
41320             return  {
41321                 success : rs.success,
41322                 errors : errors
41323             };
41324         }
41325         var  Q = false;
41326         try {
41327             Q = Roo.decode(P.responseText);
41328         } catch (e) {
41329             ret = {
41330                 success: false,
41331                 errorMsg: "Failed to read server message: " + response.responseText,
41332                 errors : []
41333             };
41334         }
41335         return  Q;
41336         
41337     }
41338 });
41339
41340
41341 Roo.form.Action.Load = function(R, S){
41342     Roo.form.Action.Load.superclass.constructor.call(this, R, S);
41343     this.reader = this.form.reader;
41344 };
41345
41346 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41347     type : 'load',
41348
41349     run : function(){
41350         Roo.Ajax.request(Roo.apply(
41351                 this.createCallback(), {
41352                     method:this.getMethod(),
41353                     url:this.getUrl(false),
41354                     params:this.getParams()
41355         }));
41356     },
41357
41358     success : function(T){
41359         var  U = this.processResponse(T);
41360         if(U === true || !U.success || !U.data){
41361             this.failureType = Roo.form.Action.LOAD_FAILURE;
41362             this.form.afterAction(this, false);
41363             return;
41364         }
41365
41366         this.form.clearInvalid();
41367         this.form.setValues(U.data);
41368         this.form.afterAction(this, true);
41369     },
41370
41371     handleResponse : function(V){
41372         if(this.form.reader){
41373             var  rs = this.form.reader.read(V);
41374             var  data = rs.records && rs.records[0] ? rs.records[0].data : null;
41375             return  {
41376                 success : rs.success,
41377                 data : data
41378             };
41379         }
41380         return  Roo.decode(V.responseText);
41381     }
41382 });
41383
41384 Roo.form.Action.ACTION_TYPES = {
41385     'load' : Roo.form.Action.Load,
41386     'submit' : Roo.form.Action.Submit
41387 };
41388 /*
41389  * Based on:
41390  * Ext JS Library 1.1.1
41391  * Copyright(c) 2006-2007, Ext JS, LLC.
41392  *
41393  * Originally Released Under LGPL - original licence link has changed is not relivant.
41394  *
41395  * Fork - LGPL
41396  * <script type="text/javascript">
41397  */
41398  
41399 /**
41400  * @class Roo.form.Layout
41401  * @extends Roo.Component
41402  * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41403  * @constructor
41404  * @param {Object} config Configuration options
41405  */
41406 Roo.form.Layout = function(A){
41407     var  B = [];
41408     if (A.items) {
41409         B = A.items;
41410         delete  A.items;
41411     }
41412
41413     Roo.form.Layout.superclass.constructor.call(this, A);
41414     this.stack = [];
41415     Roo.each(B, this.addxtype, this);
41416      
41417 };
41418
41419 Roo.extend(Roo.form.Layout, Roo.Component, {
41420     /**
41421      * @cfg {String/Object} autoCreate
41422      * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41423      */
41424     /**
41425      * @cfg {String/Object/Function} style
41426      * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41427      * a function which returns such a specification.
41428      */
41429     /**
41430      * @cfg {String} labelAlign
41431      * Valid values are "left," "top" and "right" (defaults to "left")
41432      */
41433     /**
41434      * @cfg {Number} labelWidth
41435      * Fixed width in pixels of all field labels (defaults to undefined)
41436      */
41437     /**
41438      * @cfg {Boolean} clear
41439      * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41440      */
41441     clear : true,
41442     /**
41443      * @cfg {String} labelSeparator
41444      * The separator to use after field labels (defaults to ':')
41445      */
41446     labelSeparator : ':',
41447     /**
41448      * @cfg {Boolean} hideLabels
41449      * True to suppress the display of field labels in this layout (defaults to false)
41450      */
41451     hideLabels : false,
41452
41453     // private
41454     defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41455     
41456     isLayout : true,
41457     
41458     // private
41459     onRender : function(ct, C){
41460         if(this.el){ // from markup
41461             this.el = Roo.get(this.el);
41462         }else  {  // generate
41463             var  cfg = this.getAutoCreate();
41464             this.el = ct.createChild(cfg, C);
41465         }
41466         if(this.style){
41467             this.el.applyStyles(this.style);
41468         }
41469         if(this.labelAlign){
41470             this.el.addClass('x-form-label-'+this.labelAlign);
41471         }
41472         if(this.hideLabels){
41473             this.labelStyle = "display:none";
41474             this.elementStyle = "padding-left:0;";
41475         }else {
41476             if(typeof  this.labelWidth == 'number'){
41477                 this.labelStyle = "width:"+this.labelWidth+"px;";
41478                 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof  this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41479             }
41480             if(this.labelAlign == 'top'){
41481                 this.labelStyle = "width:auto;";
41482                 this.elementStyle = "padding-left:0;";
41483             }
41484         }
41485         var  D = this.stack;
41486         var  E = D.length;
41487         if(E > 0){
41488             if(!this.fieldTpl){
41489                 var  t = new  Roo.Template(
41490                     '<div class="x-form-item {5}">',
41491                         '<label for="{0}" style="{2}">{1}{4}</label>',
41492                         '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41493                         '</div>',
41494                     '</div><div class="x-form-clear-left"></div>'
41495                 );
41496                 t.disableFormats = true;
41497                 t.compile();
41498                 Roo.form.Layout.prototype.fieldTpl = t;
41499             }
41500             for(var  i = 0; i < E; i++) {
41501                 if(D[i].isFormField){
41502                     this.renderField(D[i]);
41503                 }else {
41504                     this.renderComponent(D[i]);
41505                 }
41506             }
41507         }
41508         if(this.clear){
41509             this.el.createChild({cls:'x-form-clear'});
41510         }
41511     },
41512
41513     // private
41514     renderField : function(f){
41515         f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41516                f.id, //0
41517                f.fieldLabel, //1
41518                f.labelStyle||this.labelStyle||'', //2
41519                this.elementStyle||'', //3
41520                typeof  f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41521                f.itemCls||this.itemCls||''  //5
41522        ], true).getPrevSibling());
41523     },
41524
41525     // private
41526     renderComponent : function(c){
41527         c.render(c.isLayout ? this.el : this.el.createChild());    
41528     },
41529     /**
41530      * Adds a object form elements (using the xtype property as the factory method.)
41531      * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column
41532      * @param {Object} config 
41533      */
41534     addxtype : function(o)
41535     {
41536         // create the lement.
41537         o.form = this.form;
41538         var  fe = Roo.factory(o, Roo.form);
41539         this.form.allItems.push(fe);
41540         this.stack.push(fe);
41541         
41542         if (fe.isFormField) {
41543             this.form.items.add(fe);
41544         }
41545          
41546         return  fe;
41547     }
41548 });
41549
41550 /**
41551  * @class Roo.form.Column
41552  * @extends Roo.form.Layout
41553  * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41554  * @constructor
41555  * @param {Object} config Configuration options
41556  */
41557 Roo.form.Column = function(F){
41558     Roo.form.Column.superclass.constructor.call(this, F);
41559 };
41560
41561 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41562     /**
41563      * @cfg {Number/String} width
41564      * The fixed width of the column in pixels or CSS value (defaults to "auto")
41565      */
41566     /**
41567      * @cfg {String/Object} autoCreate
41568      * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41569      */
41570
41571     // private
41572     defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41573
41574     // private
41575     onRender : function(ct, G){
41576         Roo.form.Column.superclass.onRender.call(this, ct, G);
41577         if(this.width){
41578             this.el.setWidth(this.width);
41579         }
41580     }
41581 });
41582
41583
41584 /**
41585  * @class Roo.form.Row
41586  * @extends Roo.form.Layout
41587  * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41588  * @constructor
41589  * @param {Object} config Configuration options
41590  */
41591
41592  
41593 Roo.form.Row = function(H){
41594     Roo.form.Row.superclass.constructor.call(this, H);
41595 };
41596  
41597 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41598       /**
41599      * @cfg {Number/String} width
41600      * The fixed width of the column in pixels or CSS value (defaults to "auto")
41601      */
41602     /**
41603      * @cfg {Number/String} height
41604      * The fixed height of the column in pixels or CSS value (defaults to "auto")
41605      */
41606     defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41607     
41608     padWidth : 20,
41609     // private
41610     onRender : function(ct, I){
41611         //console.log('row render');
41612         if(!this.rowTpl){
41613             var  t = new  Roo.Template(
41614                 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41615                     '<label for="{0}" style="{2}">{1}{4}</label>',
41616                     '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41617                     '</div>',
41618                 '</div>'
41619             );
41620             t.disableFormats = true;
41621             t.compile();
41622             Roo.form.Layout.prototype.rowTpl = t;
41623         }
41624
41625         this.fieldTpl = this.rowTpl;
41626         
41627         //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41628         var  J = 100;
41629         
41630         if ((this.labelAlign != 'top')) {
41631             if (typeof  this.labelWidth == 'number') {
41632                 J = this.labelWidth
41633             }
41634
41635             this.padWidth =  20 + J;
41636             
41637         }
41638
41639         
41640         Roo.form.Column.superclass.onRender.call(this, ct, I);
41641         if(this.width){
41642             this.el.setWidth(this.width);
41643         }
41644         if(this.height){
41645             this.el.setHeight(this.height);
41646         }
41647     },
41648     
41649     // private
41650     renderField : function(f){
41651         f.fieldEl = this.fieldTpl.append(this.el, [
41652                f.id, f.fieldLabel,
41653                f.labelStyle||this.labelStyle||'',
41654                this.elementStyle||'',
41655                typeof  f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41656                f.itemCls||this.itemCls||'',
41657                f.width ? f.width + this.padWidth : 160 + this.padWidth
41658        ],true);
41659     }
41660 });
41661  
41662
41663 /**
41664  * @class Roo.form.FieldSet
41665  * @extends Roo.form.Layout
41666  * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41667  * @constructor
41668  * @param {Object} config Configuration options
41669  */
41670 Roo.form.FieldSet = function(K){
41671     Roo.form.FieldSet.superclass.constructor.call(this, K);
41672 };
41673
41674 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41675     /**
41676      * @cfg {String} legend
41677      * The text to display as the legend for the FieldSet (defaults to '')
41678      */
41679     /**
41680      * @cfg {String/Object} autoCreate
41681      * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41682      */
41683
41684     // private
41685     defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41686
41687     // private
41688     onRender : function(ct, L){
41689         Roo.form.FieldSet.superclass.onRender.call(this, ct, L);
41690         if(this.legend){
41691             this.setLegend(this.legend);
41692         }
41693     },
41694
41695     // private
41696     setLegend : function(M){
41697         if(this.rendered){
41698             this.el.child('legend').update(M);
41699         }
41700     }
41701 });
41702 /*
41703  * Based on:
41704  * Ext JS Library 1.1.1
41705  * Copyright(c) 2006-2007, Ext JS, LLC.
41706  *
41707  * Originally Released Under LGPL - original licence link has changed is not relivant.
41708  *
41709  * Fork - LGPL
41710  * <script type="text/javascript">
41711  */
41712 /**
41713  * @class Roo.form.VTypes
41714  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41715  * @singleton
41716  */
41717 Roo.form.VTypes = function(){
41718     // closure these in so they are only created once.
41719     var  A = /^[a-zA-Z_]+$/;
41720     var  B = /^[a-zA-Z0-9_]+$/;
41721     var  C = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41722     var  D = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41723
41724     // All these messages and functions are configurable
41725     return  {
41726         /**
41727          * The function used to validate email addresses
41728          * @param {String} value The email address
41729          */
41730         'email' : function(v){
41731             return  C.test(v);
41732         },
41733         /**
41734          * The error text to display when the email validation function returns false
41735          * @type String
41736          */
41737         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41738         /**
41739          * The keystroke filter mask to be applied on email input
41740          * @type RegExp
41741          */
41742         'emailMask' : /[a-z0-9_\.\-@]/i,
41743
41744         /**
41745          * The function used to validate URLs
41746          * @param {String} value The URL
41747          */
41748         'url' : function(v){
41749             return  D.test(v);
41750         },
41751         /**
41752          * The error text to display when the url validation function returns false
41753          * @type String
41754          */
41755         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41756         
41757         /**
41758          * The function used to validate alpha values
41759          * @param {String} value The value
41760          */
41761         'alpha' : function(v){
41762             return  A.test(v);
41763         },
41764         /**
41765          * The error text to display when the alpha validation function returns false
41766          * @type String
41767          */
41768         'alphaText' : 'This field should only contain letters and _',
41769         /**
41770          * The keystroke filter mask to be applied on alpha input
41771          * @type RegExp
41772          */
41773         'alphaMask' : /[a-z_]/i,
41774
41775         /**
41776          * The function used to validate alphanumeric values
41777          * @param {String} value The value
41778          */
41779         'alphanum' : function(v){
41780             return  B.test(v);
41781         },
41782         /**
41783          * The error text to display when the alphanumeric validation function returns false
41784          * @type String
41785          */
41786         'alphanumText' : 'This field should only contain letters, numbers and _',
41787         /**
41788          * The keystroke filter mask to be applied on alphanumeric input
41789          * @type RegExp
41790          */
41791         'alphanumMask' : /[a-z0-9_]/i
41792     };
41793 }();
41794 //<script type="text/javascript">
41795
41796 /**
41797  * @class Roo.form.FCKeditor
41798  * @extends Roo.form.TextArea
41799  * Wrapper around the FCKEditor http://www.fckeditor.net
41800  * @constructor
41801  * Creates a new FCKeditor
41802  * @param {Object} config Configuration options
41803  */
41804 Roo.form.FCKeditor = function(A){
41805     Roo.form.FCKeditor.superclass.constructor.call(this, A);
41806     this.addEvents({
41807          /**
41808          * @event editorinit
41809          * Fired when the editor is initialized - you can add extra handlers here..
41810          * @param {FCKeditor} this
41811          * @param {Object} the FCK object.
41812          */
41813         editorinit : true
41814     });
41815     
41816     
41817 };
41818 Roo.form.FCKeditor.editors = { };
41819 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41820 {
41821     //defaultAutoCreate : {
41822     //    tag : "textarea",style   : "width:100px;height:60px;" ,autocomplete    : "off"
41823     //},
41824     // private
41825     /**
41826      * @cfg {Object} fck options - see fck manual for details.
41827      */
41828     fckconfig : false,
41829     
41830     /**
41831      * @cfg {Object} fck toolbar set (Basic or Default)
41832      */
41833     toolbarSet : 'Basic',
41834     /**
41835      * @cfg {Object} fck BasePath
41836      */ 
41837     basePath : '/fckeditor/',
41838     
41839     
41840     frame : false,
41841     
41842     value : '',
41843     
41844    
41845     onRender : function(ct, B)
41846     {
41847         if(!this.el){
41848             this.defaultAutoCreate = {
41849                 tag: "textarea",
41850                 style:"width:300px;height:60px;",
41851                 autocomplete: "off"
41852             };
41853         }
41854
41855         Roo.form.FCKeditor.superclass.onRender.call(this, ct, B);
41856         /*
41857         if(this.grow){
41858             this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41859             if(this.preventScrollbars){
41860                 this.el.setStyle("overflow", "hidden");
41861             }
41862             this.el.setHeight(this.growMin);
41863         }
41864         */
41865         //console.log('onrender' + this.getId() );
41866         Roo.form.FCKeditor.editors[this.getId()] = this;
41867          
41868
41869         this.replaceTextarea() ;
41870         
41871     },
41872     
41873     getEditor : function() {
41874         return  this.fckEditor;
41875     },
41876     /**
41877      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
41878      * @param {Mixed} value The value to set
41879      */
41880     
41881     
41882     setValue : function(C)
41883     {
41884         //console.log('setValue: ' + value);
41885         
41886         if(typeof(C) == 'undefined') { // not sure why this is happending...
41887             return;
41888         }
41889
41890         Roo.form.FCKeditor.superclass.setValue.apply(this,[C]);
41891         
41892         //if(!this.el || !this.getEditor()) {
41893         //    this.value = value;
41894             //this.setValue.defer(100,this,[value]);    
41895         //    return;
41896         //} 
41897         
41898         if(!this.getEditor()) {
41899             return;
41900         }
41901
41902         
41903         this.getEditor().SetData(C);
41904         
41905         //
41906
41907     },
41908
41909     /**
41910      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
41911      * @return {Mixed} value The field value
41912      */
41913     getValue : function()
41914     {
41915         
41916         if (this.frame && this.frame.dom.style.display == 'none') {
41917             return  Roo.form.FCKeditor.superclass.getValue.call(this);
41918         }
41919         
41920         if(!this.el || !this.getEditor()) {
41921            
41922            // this.getValue.defer(100,this); 
41923             return  this.value;
41924         }
41925        
41926         
41927         var  D=this.getEditor().GetData();
41928         Roo.form.FCKeditor.superclass.setValue.apply(this,[D]);
41929         return  Roo.form.FCKeditor.superclass.getValue.call(this);
41930         
41931
41932     },
41933
41934     /**
41935      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
41936      * @return {Mixed} value The field value
41937      */
41938     getRawValue : function()
41939     {
41940         if (this.frame && this.frame.dom.style.display == 'none') {
41941             return  Roo.form.FCKeditor.superclass.getRawValue.call(this);
41942         }
41943         
41944         if(!this.el || !this.getEditor()) {
41945             //this.getRawValue.defer(100,this); 
41946             return  this.value;
41947             return;
41948         }
41949         
41950         
41951         
41952         var  E=this.getEditor().GetData();
41953         Roo.form.FCKeditor.superclass.setRawValue.apply(this,[E]);
41954         return  Roo.form.FCKeditor.superclass.getRawValue.call(this);
41955          
41956     },
41957     
41958     setSize : function(w,h) {
41959         
41960         
41961         
41962         //if (this.frame && this.frame.dom.style.display == 'none') {
41963         //    Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41964         //    return;
41965         //}
41966         //if(!this.el || !this.getEditor()) {
41967         //    this.setSize.defer(100,this, [w,h]); 
41968         //    return;
41969         //}
41970         
41971         
41972         
41973         Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41974         
41975         this.frame.dom.setAttribute('width', w);
41976         this.frame.dom.setAttribute('height', h);
41977         this.frame.setSize(w,h);
41978         
41979     },
41980     
41981     toggleSourceEdit : function(F) {
41982         
41983       
41984          
41985         this.el.dom.style.display = F ? '' : 'none';
41986         this.frame.dom.style.display = F ?  'none' : '';
41987         
41988     },
41989     
41990     
41991     focus: function(G)
41992     {
41993         if (this.frame.dom.style.display == 'none') {
41994             return  Roo.form.FCKeditor.superclass.focus.call(this);
41995         }
41996         if(!this.el || !this.getEditor()) {
41997             this.focus.defer(100,this, [G]); 
41998             return;
41999         }
42000         
42001         
42002         
42003         
42004         var  H = this.getEditor().EditorDocument.getElementsByTagName(G);
42005         this.getEditor().Focus();
42006         if (H.length) {
42007             if (!this.getEditor().Selection.GetSelection()) {
42008                 this.focus.defer(100,this, [G]); 
42009                 return;
42010             }
42011             
42012             
42013             var  r = this.getEditor().EditorDocument.createRange();
42014             r.setStart(H[0],0);
42015             r.setEnd(H[0],0);
42016             this.getEditor().Selection.GetSelection().removeAllRanges();
42017             this.getEditor().Selection.GetSelection().addRange(r);
42018             this.getEditor().Focus();
42019         }
42020         
42021     },
42022     
42023     
42024     
42025     replaceTextarea : function()
42026     {
42027         if ( document.getElementById( this.getId() + '___Frame' ) )
42028             return ;
42029         //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42030         //{
42031             // We must check the elements firstly using the Id and then the name.
42032         var  I = document.getElementById( this.getId() );
42033         
42034         var  J = document.getElementsByName( this.getId() ) ;
42035          
42036         I.style.display = 'none' ;
42037
42038         if ( I.tabIndex ) {            
42039             this.TabIndex = I.tabIndex ;
42040         }
42041
42042         
42043         this._insertHtmlBefore( this._getConfigHtml(), I ) ;
42044         this._insertHtmlBefore( this._getIFrameHtml(), I ) ;
42045         this.frame = Roo.get(this.getId() + '___Frame')
42046     },
42047     
42048     _getConfigHtml : function()
42049     {
42050         var  K = '' ;
42051
42052         for ( var  o  in  this.fckconfig ) {
42053             K += K.length > 0  ? '&amp;' : '';
42054             K += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42055         }
42056
42057         return  '<input type="hidden" id="' + this.getId() + '___Config" value="' + K + '" style="display:none" />' ;
42058     },
42059     
42060     
42061     _getIFrameHtml : function()
42062     {
42063         var  L = 'fckeditor.html' ;
42064         /* no idea what this is about..
42065         try
42066         {
42067             if ( (/fcksource=true/i).test( window.top.location.search ) )
42068                 sFile = 'fckeditor.original.html' ;
42069         }
42070         catch (e) { 
42071         */
42072
42073         var  M = this.basePath + 'editor/' + L + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42074         M += this.toolbarSet ? ( '&amp;Toolbar=' + this.toolbarSet)  : '';
42075         
42076         
42077         var  N = '<iframe id="' + this.getId() +
42078             '___Frame" src="' + M +
42079             '" width="' + this.width +
42080             '" height="' + this.height + '"' +
42081             (this.tabIndex ?  ' tabindex="' + this.tabIndex + '"' :'' ) +
42082             ' frameborder="0" scrolling="no"></iframe>' ;
42083
42084         return  N ;
42085     },
42086     
42087     _insertHtmlBefore : function( O, P )
42088     {
42089         if ( P.insertAdjacentHTML )     {
42090             // IE
42091             P.insertAdjacentHTML( 'beforeBegin', O ) ;
42092         } else  { // Gecko
42093             var  oRange = document.createRange() ;
42094             oRange.setStartBefore( P ) ;
42095             var  oFragment = oRange.createContextualFragment( O );
42096             P.parentNode.insertBefore( oFragment, P ) ;
42097         }
42098     }
42099     
42100     
42101   
42102     
42103     
42104     
42105     
42106
42107 });
42108
42109 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42110
42111 function  Q(R){
42112     var  f = Roo.form.FCKeditor.editors[R.Name];
42113     f.fckEditor = R;
42114     //console.log("loaded");
42115     f.fireEvent('editorinit', f, R);
42116
42117   
42118
42119  
42120
42121
42122
42123
42124
42125
42126
42127
42128
42129
42130
42131
42132
42133
42134
42135
42136 //<script type="text/javascript">
42137 /**
42138  * @class Roo.form.GridField
42139  * @extends Roo.form.Field
42140  * Embed a grid (or editable grid into a form)
42141  * STATUS ALPHA
42142  * @constructor
42143  * Creates a new GridField
42144  * @param {Object} config Configuration options
42145  */
42146 Roo.form.GridField = function(A){
42147     Roo.form.GridField.superclass.constructor.call(this, A);
42148      
42149 };
42150
42151 Roo.extend(Roo.form.GridField, Roo.form.Field,  {
42152     /**
42153      * @cfg {Number} width  - used to restrict width of grid..
42154      */
42155     width : 100,
42156     /**
42157      * @cfg {Number} height - used to restrict height of grid..
42158      */
42159     height : 50,
42160      /**
42161      * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
42162      */
42163     xgrid : false, 
42164     /**
42165      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42166      * {tag: "input", type: "checkbox", autocomplete: "off"})
42167      */
42168    // defaultAutoCreate : { tag: 'div' },
42169     defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42170     /**
42171      * @cfg {String} addTitle Text to include for adding a title.
42172      */
42173     addTitle : false,
42174     //
42175     onResize : function(){
42176         Roo.form.Field.superclass.onResize.apply(this, arguments);
42177     },
42178
42179     initEvents : function(){
42180         // Roo.form.Checkbox.superclass.initEvents.call(this);
42181         // has no events...
42182        
42183     },
42184
42185
42186     getResizeEl : function(){
42187         return  this.wrap;
42188     },
42189
42190     getPositionEl : function(){
42191         return  this.wrap;
42192     },
42193
42194     // private
42195     onRender : function(ct, B){
42196         
42197         this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42198         var  C = this.style;
42199         delete  this.style;
42200         
42201         Roo.form.DisplayImage.superclass.onRender.call(this, ct, B);
42202         this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42203         this.viewEl = this.wrap.createChild({ tag: 'div' });
42204         if (C) {
42205             this.viewEl.applyStyles(C);
42206         }
42207         if (this.width) {
42208             this.viewEl.setWidth(this.width);
42209         }
42210         if (this.height) {
42211             this.viewEl.setHeight(this.height);
42212         }
42213
42214         //if(this.inputValue !== undefined){
42215         //this.setValue(this.value);
42216         
42217         
42218         this.grid = new  Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42219         
42220         
42221         this.grid.render();
42222         this.grid.getDataSource().on('remove', this.refreshValue, this);
42223         this.grid.getDataSource().on('update', this.refreshValue, this);
42224         this.grid.on('afteredit', this.refreshValue, this);
42225  
42226     },
42227      
42228     
42229     /**
42230      * Sets the value of the item. 
42231      * @param {String} either an object  or a string..
42232      */
42233     setValue : function(v){
42234         //this.value = v;
42235         v = v || []; // empty set..
42236         // this does not seem smart - it really only affects memoryproxy grids..
42237         if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42238             var  ds = this.grid.getDataSource();
42239             // assumes a json reader..
42240             var  data = {}
42241
42242             data[ds.reader.meta.root ] =  typeof(v) == 'string' ? Roo.decode(v) : v;
42243             ds.loadData( data);
42244         }
42245
42246         Roo.form.GridField.superclass.setValue.call(this, v);
42247         this.refreshValue();
42248         // should load data in the grid really....
42249     },
42250     
42251     // private
42252     refreshValue: function() {
42253          var  D = [];
42254         this.grid.getDataSource().each(function(r) {
42255             D.push(r.data);
42256         });
42257         this.el.dom.value = Roo.encode(D);
42258     }
42259     
42260      
42261     
42262     
42263 });
42264 //<script type="text/javasscript">
42265  
42266
42267 /**
42268  * @class Roo.DDView
42269  * A DnD enabled version of Roo.View.
42270  * @param {Element/String} container The Element in which to create the View.
42271  * @param {String} tpl The template string used to create the markup for each element of the View
42272  * @param {Object} config The configuration properties. These include all the config options of
42273  * {@link Roo.View} plus some specific to this class.<br>
42274  * <p>
42275  * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42276  * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42277  * <p>
42278  * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42279 .x-view-drag-insert-above {
42280         border-top:1px dotted #3366cc;
42281 }
42282 .x-view-drag-insert-below {
42283         border-bottom:1px dotted #3366cc;
42284 }
42285 </code></pre>
42286  * 
42287  */
42288  
42289 Roo.DDView = function(A, B, C) {
42290     Roo.DDView.superclass.constructor.apply(this, arguments);
42291     this.getEl().setStyle("outline", "0px none");
42292     this.getEl().unselectable();
42293     if (this.dragGroup) {
42294                 this.setDraggable(this.dragGroup.split(","));
42295     }
42296     if (this.dropGroup) {
42297                 this.setDroppable(this.dropGroup.split(","));
42298     }
42299     if (this.deletable) {
42300         this.setDeletable();
42301     }
42302
42303     this.isDirtyFlag = false;
42304         this.addEvents({
42305                 "drop" : true
42306         });
42307 };
42308
42309 Roo.extend(Roo.DDView, Roo.View, {
42310 /**     @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42311 /**     @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42312 /**     @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42313 /**     @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42314
42315         isFormField: true,
42316
42317         reset: Roo.emptyFn,
42318         
42319         clearInvalid: Roo.form.Field.prototype.clearInvalid,
42320
42321         validate: function() {
42322                 return  true;
42323         },
42324         
42325         destroy: function() {
42326                 this.purgeListeners();
42327                 this.getEl.removeAllListeners();
42328                 this.getEl().remove();
42329                 if (this.dragZone) {
42330                         if (this.dragZone.destroy) {
42331                                 this.dragZone.destroy();
42332                         }
42333                 }
42334                 if (this.dropZone) {
42335                         if (this.dropZone.destroy) {
42336                                 this.dropZone.destroy();
42337                         }
42338                 }
42339         },
42340
42341 /**     Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42342         getName: function() {
42343                 return  this.name;
42344         },
42345
42346 /**     Loads the View from a JSON string representing the Records to put into the Store. */
42347         setValue: function(v) {
42348                 if (!this.store) {
42349                         throw  "DDView.setValue(). DDView must be constructed with a valid Store";
42350                 }
42351                 var  D = {};
42352                 D[this.store.reader.meta.root] = v ? [].concat(v) : [];
42353                 this.store.proxy = new  Roo.data.MemoryProxy(D);
42354                 this.store.load();
42355         },
42356
42357 /**     @return {String} a parenthesised list of the ids of the Records in the View. */
42358         getValue: function() {
42359                 var  E = '(';
42360                 this.store.each(function(F) {
42361                         E += F.id + ',';
42362                 });
42363                 return  E.substr(0, E.length - 1) + ')';
42364         },
42365         
42366         getIds: function() {
42367                 var  i = 0, F = new  Array(this.store.getCount());
42368                 this.store.each(function(G) {
42369                         F[i++] = G.id;
42370                 });
42371                 return  F;
42372         },
42373         
42374         isDirty: function() {
42375                 return  this.isDirtyFlag;
42376         },
42377
42378 /**
42379  *      Part of the Roo.dd.DropZone interface. If no target node is found, the
42380  *      whole Element becomes the target, and this causes the drop gesture to append.
42381  */
42382     getTargetFromEvent : function(e) {
42383                 var  G = e.getTarget();
42384                 while ((G !== null) && (G.parentNode != this.el.dom)) {
42385                 G = G.parentNode;
42386                 }
42387                 if (!G) {
42388                         G = this.el.dom.lastChild || this.el.dom;
42389                 }
42390                 return  G;
42391     },
42392
42393 /**
42394  *      Create the drag data which consists of an object which has the property "ddel" as
42395  *      the drag proxy element. 
42396  */
42397     getDragData : function(e) {
42398         var  H = this.findItemFromChild(e.getTarget());
42399                 if(H) {
42400                         this.handleSelection(e);
42401                         var  selNodes = this.getSelectedNodes();
42402             var  dragData = {
42403                 source: this,
42404                 copy: this.copy || (this.allowCopy && e.ctrlKey),
42405                 nodes: selNodes,
42406                 records: []
42407                         };
42408                         var  selectedIndices = this.getSelectedIndexes();
42409                         for (var  i = 0; i < selectedIndices.length; i++) {
42410                                 dragData.records.push(this.store.getAt(selectedIndices[i]));
42411                         }
42412                         if (selNodes.length == 1) {
42413                                 dragData.ddel = H.cloneNode(true);      // the div element
42414                         } else  {
42415                                 var  div = document.createElement('div'); // create the multi element drag "ghost"
42416                                 div.className = 'multi-proxy';
42417                                 for (var  i = 0, len = selNodes.length; i < len; i++) {
42418                                         div.appendChild(selNodes[i].cloneNode(true));
42419                                 }
42420
42421                                 dragData.ddel = div;
42422                         }
42423             //console.log(dragData)
42424             //console.log(dragData.ddel.innerHTML)
42425                         return  dragData;
42426                 }
42427         //console.log('nodragData')
42428                 return  false;
42429     },
42430     
42431 /**     Specify to which ddGroup items in this DDView may be dragged. */
42432     setDraggable: function(I) {
42433         if (I  instanceof  Array) {
42434                 Roo.each(I, this.setDraggable, this);
42435                 return;
42436         }
42437         if (this.dragZone) {
42438                 this.dragZone.addToGroup(I);
42439         } else  {
42440                         this.dragZone = new  Roo.dd.DragZone(this.getEl(), {
42441                                 containerScroll: true,
42442                                 ddGroup: I 
42443
42444                         });
42445 //                      Draggability implies selection. DragZone's mousedown selects the element.
42446                         if (!this.multiSelect) { this.singleSelect = true; }
42447
42448
42449 //                      Wire the DragZone's handlers up to methods in *this*
42450                         this.dragZone.getDragData = this.getDragData.createDelegate(this);
42451                 }
42452     },
42453
42454 /**     Specify from which ddGroup this DDView accepts drops. */
42455     setDroppable: function(J) {
42456         if (J  instanceof  Array) {
42457                 Roo.each(J, this.setDroppable, this);
42458                 return;
42459         }
42460         if (this.dropZone) {
42461                 this.dropZone.addToGroup(J);
42462         } else  {
42463                         this.dropZone = new  Roo.dd.DropZone(this.getEl(), {
42464                                 containerScroll: true,
42465                                 ddGroup: J
42466                         });
42467
42468 //                      Wire the DropZone's handlers up to methods in *this*
42469                         this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42470                         this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42471                         this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42472                         this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42473                         this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42474                 }
42475     },
42476
42477 /**     Decide whether to drop above or below a View node. */
42478     getDropPoint : function(e, n, dd){
42479         if (n == this.el.dom) { return  "above"; }
42480                 var  t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42481                 var  c = t + (b - t) / 2;
42482                 var  y = Roo.lib.Event.getPageY(e);
42483                 if(y <= c) {
42484                         return  "above";
42485                 }else {
42486                         return  "below";
42487                 }
42488     },
42489
42490     onNodeEnter : function(n, dd, e, K){
42491                 return  false;
42492     },
42493     
42494     onNodeOver : function(n, dd, e, L){
42495                 var  pt = this.getDropPoint(e, n, dd);
42496                 // set the insert point style on the target node
42497                 var  M = this.dropNotAllowed;
42498                 if (pt) {
42499                         var  targetElClass;
42500                         if (pt == "above"){
42501                                 M = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42502                                 targetElClass = "x-view-drag-insert-above";
42503                         } else  {
42504                                 M = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42505                                 targetElClass = "x-view-drag-insert-below";
42506                         }
42507                         if (this.lastInsertClass != targetElClass){
42508                                 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42509                                 this.lastInsertClass = targetElClass;
42510                         }
42511                 }
42512                 return  M;
42513         },
42514
42515     onNodeOut : function(n, dd, e, N){
42516                 this.removeDropIndicators(n);
42517     },
42518
42519     onNodeDrop : function(n, dd, e, O){
42520         if (this.fireEvent("drop", this, n, dd, e, O) === false) {
42521                 return  false;
42522         }
42523         var  pt = this.getDropPoint(e, n, dd);
42524                 var  P = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42525                 if (pt == "below") { P++; }
42526                 for (var  i = 0; i < O.records.length; i++) {
42527                         var  r = O.records[i];
42528                         var  dup = this.store.getById(r.id);
42529                         if (dup && (dd != this.dragZone)) {
42530                                 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42531                         } else  {
42532                                 if (O.copy) {
42533                                         this.store.insert(P++, r.copy());
42534                                 } else  {
42535                                         O.source.isDirtyFlag = true;
42536                                         r.store.remove(r);
42537                                         this.store.insert(P++, r);
42538                                 }
42539
42540                                 this.isDirtyFlag = true;
42541                         }
42542                 }
42543
42544                 this.dragZone.cachedTarget = null;
42545                 return  true;
42546     },
42547
42548     removeDropIndicators : function(n){
42549                 if(n){
42550                         Roo.fly(n).removeClass([
42551                                 "x-view-drag-insert-above",
42552                                 "x-view-drag-insert-below"]);
42553                         this.lastInsertClass = "_noclass";
42554                 }
42555     },
42556
42557 /**
42558  *      Utility method. Add a delete option to the DDView's context menu.
42559  *      @param {String} imageUrl The URL of the "delete" icon image.
42560  */
42561         setDeletable: function(Q) {
42562                 if (!this.singleSelect && !this.multiSelect) {
42563                         this.singleSelect = true;
42564                 }
42565                 var  c = this.getContextMenu();
42566                 this.contextMenu.on("itemclick", function(R) {
42567                         switch (R.id) {
42568                                 case  "delete":
42569                                         this.remove(this.getSelectedIndexes());
42570                                         break;
42571                         }
42572                 }, this);
42573                 this.contextMenu.add({
42574                         icon: Q,
42575                         id: "delete",
42576                         text: 'Delete'
42577                 });
42578         },
42579         
42580 /**     Return the context menu for this DDView. */
42581         getContextMenu: function() {
42582                 if (!this.contextMenu) {
42583 //                      Create the View's context menu
42584                         this.contextMenu = new  Roo.menu.Menu({
42585                                 id: this.id + "-contextmenu"
42586                         });
42587                         this.el.on("contextmenu", this.showContextMenu, this);
42588                 }
42589                 return  this.contextMenu;
42590         },
42591         
42592         disableContextMenu: function() {
42593                 if (this.contextMenu) {
42594                         this.el.un("contextmenu", this.showContextMenu, this);
42595                 }
42596         },
42597
42598         showContextMenu: function(e, R) {
42599         R = this.findItemFromChild(e.getTarget());
42600                 if (R) {
42601                         e.stopEvent();
42602                         this.select(this.getNode(R), this.multiSelect && e.ctrlKey, true);
42603                         this.contextMenu.showAt(e.getXY());
42604             }
42605     },
42606
42607 /**
42608  *      Remove {@link Roo.data.Record}s at the specified indices.
42609  *      @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42610  */
42611     remove: function(S) {
42612                 S = [].concat(S);
42613                 for (var  i = 0; i < S.length; i++) {
42614                         var  rec = this.store.getAt(S[i]);
42615                         this.store.remove(rec);
42616                 }
42617     },
42618
42619 /**
42620  *      Double click fires the event, but also, if this is draggable, and there is only one other
42621  *      related DropZone, it transfers the selected node.
42622  */
42623     onDblClick : function(e){
42624         var  T = this.findItemFromChild(e.getTarget());
42625         if(T){
42626             if (this.fireEvent("dblclick", this, this.indexOf(T), T, e) === false) {
42627                 return  false;
42628             }
42629             if (this.dragGroup) {
42630                     var  targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42631                     while (targets.indexOf(this.dropZone) > -1) {
42632                             targets.remove(this.dropZone);
42633                                 }
42634                     if (targets.length == 1) {
42635                                         this.dragZone.cachedTarget = null;
42636                         var  el = Roo.get(targets[0].getEl());
42637                         var  box = el.getBox(true);
42638                         targets[0].onNodeDrop(el.dom, {
42639                                 target: el.dom,
42640                                 xy: [box.x, box.y + box.height - 1]
42641                         }, null, this.getDragData(e));
42642                     }
42643                 }
42644         }
42645     },
42646     
42647     handleSelection: function(e) {
42648                 this.dragZone.cachedTarget = null;
42649         var  U = this.findItemFromChild(e.getTarget());
42650         if (!U) {
42651                 this.clearSelections(true);
42652                 return;
42653         }
42654                 if (U && (this.multiSelect || this.singleSelect)){
42655                         if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42656                                 this.select(this.getNodes(this.indexOf(this.lastSelection), U.nodeIndex), false);
42657                         }else  if (this.isSelected(this.getNode(U)) && e.ctrlKey){
42658                                 this.unselect(U);
42659                         } else  {
42660                                 this.select(U, this.multiSelect && e.ctrlKey);
42661                                 this.lastSelection = U;
42662                         }
42663                 }
42664     },
42665
42666     onItemClick : function(V, W, e){
42667                 if(this.fireEvent("beforeclick", this, W, V, e) === false){
42668                         return  false;
42669                 }
42670                 return  true;
42671     },
42672
42673     unselect : function(X, Y){
42674                 var  Z = this.getNode(X);
42675                 if(Z && this.isSelected(Z)){
42676                         if(this.fireEvent("beforeselect", this, Z, this.selections) !== false){
42677                                 Roo.fly(Z).removeClass(this.selectedClass);
42678                                 this.selections.remove(Z);
42679                                 if(!Y){
42680                                         this.fireEvent("selectionchange", this, this.selections);
42681                                 }
42682                         }
42683                 }
42684     }
42685 });
42686
42687 /*
42688  * Based on:
42689  * Ext JS Library 1.1.1
42690  * Copyright(c) 2006-2007, Ext JS, LLC.
42691  *
42692  * Originally Released Under LGPL - original licence link has changed is not relivant.
42693  *
42694  * Fork - LGPL
42695  * <script type="text/javascript">
42696  */
42697  
42698 /**
42699  * @class Roo.LayoutManager
42700  * @extends Roo.util.Observable
42701  * Base class for layout managers.
42702  */
42703 Roo.LayoutManager = function(A, B){
42704     Roo.LayoutManager.superclass.constructor.call(this);
42705     this.el = Roo.get(A);
42706     // ie scrollbar fix
42707     if(this.el.dom == document.body && Roo.isIE && !B.allowScroll){
42708         document.body.scroll = "no";
42709     }else  if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
42710         this.el.position('relative');
42711     }
42712
42713     this.id = this.el.id;
42714     this.el.addClass("x-layout-container");
42715     /** false to disable window resize monitoring @type Boolean */
42716     this.monitorWindowResize = true;
42717     this.regions = {};
42718     this.addEvents({
42719         /**
42720          * @event layout
42721          * Fires when a layout is performed. 
42722          * @param {Roo.LayoutManager} this
42723          */
42724         "layout" : true,
42725         /**
42726          * @event regionresized
42727          * Fires when the user resizes a region. 
42728          * @param {Roo.LayoutRegion} region The resized region
42729          * @param {Number} newSize The new size (width for east/west, height for north/south)
42730          */
42731         "regionresized" : true,
42732         /**
42733          * @event regioncollapsed
42734          * Fires when a region is collapsed. 
42735          * @param {Roo.LayoutRegion} region The collapsed region
42736          */
42737         "regioncollapsed" : true,
42738         /**
42739          * @event regionexpanded
42740          * Fires when a region is expanded.  
42741          * @param {Roo.LayoutRegion} region The expanded region
42742          */
42743         "regionexpanded" : true
42744     });
42745     this.updating = false;
42746     Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42747 };
42748
42749 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42750     /**
42751      * Returns true if this layout is currently being updated
42752      * @return {Boolean}
42753      */
42754     isUpdating : function(){
42755         return  this.updating; 
42756     },
42757     
42758     /**
42759      * Suspend the LayoutManager from doing auto-layouts while
42760      * making multiple add or remove calls
42761      */
42762     beginUpdate : function(){
42763         this.updating = true;    
42764     },
42765     
42766     /**
42767      * Restore auto-layouts and optionally disable the manager from performing a layout
42768      * @param {Boolean} noLayout true to disable a layout update 
42769      */
42770     endUpdate : function(C){
42771         this.updating = false;
42772         if(!C){
42773             this.layout();
42774         }    
42775     },
42776     
42777     layout: function(){
42778         
42779     },
42780     
42781     onRegionResized : function(D, E){
42782         this.fireEvent("regionresized", D, E);
42783         this.layout();
42784     },
42785     
42786     onRegionCollapsed : function(F){
42787         this.fireEvent("regioncollapsed", F);
42788     },
42789     
42790     onRegionExpanded : function(G){
42791         this.fireEvent("regionexpanded", G);
42792     },
42793         
42794     /**
42795      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42796      * performs box-model adjustments.
42797      * @return {Object} The size as an object {width: (the width), height: (the height)}
42798      */
42799     getViewSize : function(){
42800         var  H;
42801         if(this.el.dom != document.body){
42802             H = this.el.getSize();
42803         }else {
42804             H = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42805         }
42806
42807         H.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42808         H.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42809         return  H;
42810     },
42811     
42812     /**
42813      * Returns the Element this layout is bound to.
42814      * @return {Roo.Element}
42815      */
42816     getEl : function(){
42817         return  this.el;
42818     },
42819     
42820     /**
42821      * Returns the specified region.
42822      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42823      * @return {Roo.LayoutRegion}
42824      */
42825     getRegion : function(I){
42826         return  this.regions[I.toLowerCase()];
42827     },
42828     
42829     onWindowResize : function(){
42830         if(this.monitorWindowResize){
42831             this.layout();
42832         }
42833     }
42834 });
42835 /*
42836  * Based on:
42837  * Ext JS Library 1.1.1
42838  * Copyright(c) 2006-2007, Ext JS, LLC.
42839  *
42840  * Originally Released Under LGPL - original licence link has changed is not relivant.
42841  *
42842  * Fork - LGPL
42843  * <script type="text/javascript">
42844  */
42845 /**
42846  * @class Roo.BorderLayout
42847  * @extends Roo.LayoutManager
42848  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42849  * please see: <br><br>
42850  * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
42851  * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
42852  * Example:
42853  <pre><code>
42854  var layout = new Roo.BorderLayout(document.body, {
42855     north: {
42856         initialSize: 25,
42857         titlebar: false
42858     },
42859     west: {
42860         split:true,
42861         initialSize: 200,
42862         minSize: 175,
42863         maxSize: 400,
42864         titlebar: true,
42865         collapsible: true
42866     },
42867     east: {
42868         split:true,
42869         initialSize: 202,
42870         minSize: 175,
42871         maxSize: 400,
42872         titlebar: true,
42873         collapsible: true
42874     },
42875     south: {
42876         split:true,
42877         initialSize: 100,
42878         minSize: 100,
42879         maxSize: 200,
42880         titlebar: true,
42881         collapsible: true
42882     },
42883     center: {
42884         titlebar: true,
42885         autoScroll:true,
42886         resizeTabs: true,
42887         minTabWidth: 50,
42888         preferredTabWidth: 150
42889     }
42890 });
42891
42892 // shorthand
42893 var CP = Roo.ContentPanel;
42894
42895 layout.beginUpdate();
42896 layout.add("north", new CP("north", "North"));
42897 layout.add("south", new CP("south", {title: "South", closable: true}));
42898 layout.add("west", new CP("west", {title: "West"}));
42899 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42900 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42901 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42902 layout.getRegion("center").showPanel("center1");
42903 layout.endUpdate();
42904 </code></pre>
42905
42906 <b>The container the layout is rendered into can be either the body element or any other element.
42907 If it is not the body element, the container needs to either be an absolute positioned element,
42908 or you will need to add "position:relative" to the css of the container.  You will also need to specify
42909 the container size if it is not the body element.</b>
42910
42911 * @constructor
42912 * Create a new BorderLayout
42913 * @param {String/HTMLElement/Element} container The container this layout is bound to
42914 * @param {Object} config Configuration options
42915  */
42916 Roo.BorderLayout = function(A, B){
42917     B = B || {};
42918     Roo.BorderLayout.superclass.constructor.call(this, A, B);
42919     this.factory = B.factory || Roo.BorderLayout.RegionFactory;
42920     for(var  i = 0, len = this.factory.validRegions.length; i < len; i++) {
42921         var  target = this.factory.validRegions[i];
42922         if(B[target]){
42923             this.addRegion(target, B[target]);
42924         }
42925     }
42926 };
42927
42928 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42929     /**
42930      * Creates and adds a new region if it doesn't already exist.
42931      * @param {String} target The target region key (north, south, east, west or center).
42932      * @param {Object} config The regions config object
42933      * @return {BorderLayoutRegion} The new region
42934      */
42935     addRegion : function(C, D){
42936         if(!this.regions[C]){
42937             var  r = this.factory.create(C, this, D);
42938             this.bindRegion(C, r);
42939         }
42940         return  this.regions[C];
42941     },
42942
42943     // private (kinda)
42944     bindRegion : function(E, r){
42945         this.regions[E] = r;
42946         r.on("visibilitychange", this.layout, this);
42947         r.on("paneladded", this.layout, this);
42948         r.on("panelremoved", this.layout, this);
42949         r.on("invalidated", this.layout, this);
42950         r.on("resized", this.onRegionResized, this);
42951         r.on("collapsed", this.onRegionCollapsed, this);
42952         r.on("expanded", this.onRegionExpanded, this);
42953     },
42954
42955     /**
42956      * Performs a layout update.
42957      */
42958     layout : function(){
42959         if(this.updating) return;
42960         var  F = this.getViewSize();
42961         var  w = F.width;
42962         var  h = F.height;
42963         var  G = w;
42964         var  H = h;
42965         var  I = 0;
42966         var  J = 0;
42967         //var x = 0, y = 0;
42968
42969         var  rs = this.regions;
42970         var  K = rs["north"];
42971         var  L = rs["south"]; 
42972         var  M = rs["west"];
42973         var  N = rs["east"];
42974         var  O = rs["center"];
42975         //if(this.hideOnLayout){ // not supported anymore
42976             //c.el.setStyle("display", "none");
42977         //}
42978         if(K && K.isVisible()){
42979             var  b = K.getBox();
42980             var  m = K.getMargins();
42981             b.width = w - (m.left+m.right);
42982             b.x = m.left;
42983             b.y = m.top;
42984             I = b.height + b.y + m.bottom;
42985             H -= I;
42986             K.updateBox(this.safeBox(b));
42987         }
42988         if(L && L.isVisible()){
42989             var  b = L.getBox();
42990             var  m = L.getMargins();
42991             b.width = w - (m.left+m.right);
42992             b.x = m.left;
42993             var  totalHeight = (b.height + m.top + m.bottom);
42994             b.y = h - totalHeight + m.top;
42995             H -= totalHeight;
42996             L.updateBox(this.safeBox(b));
42997         }
42998         if(M && M.isVisible()){
42999             var  b = M.getBox();
43000             var  m = M.getMargins();
43001             b.height = H - (m.top+m.bottom);
43002             b.x = m.left;
43003             b.y = I + m.top;
43004             var  totalWidth = (b.width + m.left + m.right);
43005             J += totalWidth;
43006             G -= totalWidth;
43007             M.updateBox(this.safeBox(b));
43008         }
43009         if(N && N.isVisible()){
43010             var  b = N.getBox();
43011             var  m = N.getMargins();
43012             b.height = H - (m.top+m.bottom);
43013             var  totalWidth = (b.width + m.left + m.right);
43014             b.x = w - totalWidth + m.left;
43015             b.y = I + m.top;
43016             G -= totalWidth;
43017             N.updateBox(this.safeBox(b));
43018         }
43019         if(O){
43020             var  m = O.getMargins();
43021             var  centerBox = {
43022                 x: J + m.left,
43023                 y: I + m.top,
43024                 width: G - (m.left+m.right),
43025                 height: H - (m.top+m.bottom)
43026             };
43027             //if(this.hideOnLayout){
43028                 //center.el.setStyle("display", "block");
43029             //}
43030             O.updateBox(this.safeBox(centerBox));
43031         }
43032
43033         this.el.repaint();
43034         this.fireEvent("layout", this);
43035     },
43036
43037     // private
43038     safeBox : function(P){
43039         P.width = Math.max(0, P.width);
43040         P.height = Math.max(0, P.height);
43041         return  P;
43042     },
43043
43044     /**
43045      * Adds a ContentPanel (or subclass) to this layout.
43046      * @param {String} target The target region key (north, south, east, west or center).
43047      * @param {Roo.ContentPanel} panel The panel to add
43048      * @return {Roo.ContentPanel} The added panel
43049      */
43050     add : function(Q, R){
43051          
43052         Q = Q.toLowerCase();
43053         return  this.regions[Q].add(R);
43054     },
43055
43056     /**
43057      * Remove a ContentPanel (or subclass) to this layout.
43058      * @param {String} target The target region key (north, south, east, west or center).
43059      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43060      * @return {Roo.ContentPanel} The removed panel
43061      */
43062     remove : function(S, T){
43063         S = S.toLowerCase();
43064         return  this.regions[S].remove(T);
43065     },
43066
43067     /**
43068      * Searches all regions for a panel with the specified id
43069      * @param {String} panelId
43070      * @return {Roo.ContentPanel} The panel or null if it wasn't found
43071      */
43072     findPanel : function(U){
43073         var  rs = this.regions;
43074         for(var  S  in  rs){
43075             if(typeof  rs[S] != "function"){
43076                 var  p = rs[S].getPanel(U);
43077                 if(p){
43078                     return  p;
43079                 }
43080             }
43081         }
43082         return  null;
43083     },
43084
43085     /**
43086      * Searches all regions for a panel with the specified id and activates (shows) it.
43087      * @param {String/ContentPanel} panelId The panels id or the panel itself
43088      * @return {Roo.ContentPanel} The shown panel or null
43089      */
43090     showPanel : function(V) {
43091       var  rs = this.regions;
43092       for(var  S  in  rs){
43093          var  r = rs[S];
43094          if(typeof  r != "function"){
43095             if(r.hasPanel(V)){
43096                return  r.showPanel(V);
43097             }
43098          }
43099       }
43100       return  null;
43101    },
43102
43103    /**
43104      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43105      * @param {Roo.state.Provider} provider (optional) An alternate state provider
43106      */
43107     restoreState : function(W){
43108         if(!W){
43109             W = Roo.state.Manager;
43110         }
43111         var  sm = new  Roo.LayoutStateManager();
43112         sm.init(this, W);
43113     },
43114
43115     /**
43116      * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object.  This config
43117      * object should contain properties for each region to add ContentPanels to, and each property's value should be
43118      * a valid ContentPanel config object.  Example:
43119      * <pre><code>
43120 // Create the main layout
43121 var layout = new Roo.BorderLayout('main-ct', {
43122     west: {
43123         split:true,
43124         minSize: 175,
43125         titlebar: true
43126     },
43127     center: {
43128         title:'Components'
43129     }
43130 }, 'main-ct');
43131
43132 // Create and add multiple ContentPanels at once via configs
43133 layout.batchAdd({
43134    west: {
43135        id: 'source-files',
43136        autoCreate:true,
43137        title:'Ext Source Files',
43138        autoScroll:true,
43139        fitToFrame:true
43140    },
43141    center : {
43142        el: cview,
43143        autoScroll:true,
43144        fitToFrame:true,
43145        toolbar: tb,
43146        resizeEl:'cbody'
43147    }
43148 });
43149 </code></pre>
43150      * @param {Object} regions An object containing ContentPanel configs by region name
43151      */
43152     batchAdd : function(X){
43153         this.beginUpdate();
43154         for(var  rname  in  X){
43155             var  lr = this.regions[rname];
43156             if(lr){
43157                 this.addTypedPanels(lr, X[rname]);
43158             }
43159         }
43160
43161         this.endUpdate();
43162     },
43163
43164     // private
43165     addTypedPanels : function(lr, ps){
43166         if(typeof  ps == 'string'){
43167             lr.add(new  Roo.ContentPanel(ps));
43168         }
43169         else  if(ps  instanceof  Array){
43170             for(var  i =0, len = ps.length; i < len; i++){
43171                 this.addTypedPanels(lr, ps[i]);
43172             }
43173         }
43174         else  if(!ps.events){ // raw config?
43175             var  el = ps.el;
43176             delete  ps.el; // prevent conflict
43177             lr.add(new  Roo.ContentPanel(el || Roo.id(), ps));
43178         }
43179         else  {  // panel object assumed!
43180             lr.add(ps);
43181         }
43182     },
43183     /**
43184      * Adds a xtype elements to the layout.
43185      * <pre><code>
43186
43187 layout.addxtype({
43188        xtype : 'ContentPanel',
43189        region: 'west',
43190        items: [ .... ]
43191    }
43192 );
43193
43194 layout.addxtype({
43195         xtype : 'NestedLayoutPanel',
43196         region: 'west',
43197         layout: {
43198            center: { },
43199            west: { }   
43200         },
43201         items : [ ... list of content panels or nested layout panels.. ]
43202    }
43203 );
43204 </code></pre>
43205      * @param {Object} cfg Xtype definition of item to add.
43206      */
43207     addxtype : function(Y)
43208     {
43209         // basically accepts a pannel...
43210         // can accept a layout region..!?!?
43211        // console.log('BorderLayout add ' + cfg.xtype)
43212         
43213         if (!Y.xtype.match(/Panel$/)) {
43214             return  false;
43215         }
43216         var  Z = false;
43217         var  a = Y.region;
43218         delete  Y.region;
43219         
43220           
43221         var  c = [];
43222         if (Y.items) {
43223             c = Y.items;
43224             delete  Y.items;
43225         }
43226         
43227         
43228         switch(Y.xtype) 
43229         {
43230             case  'ContentPanel':  // ContentPanel (el, cfg)
43231                 if(Y.autoCreate) {
43232                     Z = new  Roo[Y.xtype](Y); // new panel!!!!!
43233                 } else  {
43234                     var  el = this.el.createChild();
43235                     Z = new  Roo[Y.xtype](el, Y); // new panel!!!!!
43236                 }
43237
43238                 
43239                 this.add(a, Z);
43240                 break;
43241             
43242             
43243             case  'TreePanel': // our new panel!
43244                 Y.el = this.el.createChild();
43245                 Z = new  Roo[Y.xtype](Y); // new panel!!!!!
43246                 this.add(a, Z);
43247                 break;
43248             
43249             case  'NestedLayoutPanel': 
43250                 // create a new Layout (which is  a Border Layout...
43251                 var  el = this.el.createChild();
43252                 var  clayout = Y.layout;
43253                 delete  Y.layout;
43254                 clayout.items   = clayout.items  || [];
43255                 // replace this exitems with the clayout ones..
43256                 c = clayout.items;
43257                  
43258                 
43259                 if (a == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43260                     Y.background = false;
43261                 }
43262                 var  layout = new  Roo.BorderLayout(el, clayout);
43263                 
43264                 Z = new  Roo[Y.xtype](layout, Y); // new panel!!!!!
43265                 //console.log('adding nested layout panel '  + cfg.toSource());
43266                 this.add(a, Z);
43267                 
43268                 break;
43269                 
43270             case  'GridPanel': 
43271             
43272                 // needs grid and region
43273                 
43274                 //var el = this.getRegion(region).el.createChild();
43275                 var  el = this.el.createChild();
43276                 // create the grid first...
43277                 
43278                 var  grid = new  Roo.grid[Y.grid.xtype](el, Y.grid);
43279                 delete  Y.grid;
43280                 if (a == 'center' && this.active ) {
43281                     Y.background = false;
43282                 }
43283
43284                 Z = new  Roo[Y.xtype](grid, Y); // new panel!!!!!
43285                 
43286                 this.add(a, Z);
43287                 if (Y.background) {
43288                     Z.on('activate', function(gp) {
43289                         if (!gp.grid.rendered) {
43290                             gp.grid.render();
43291                         }
43292                     });
43293                 } else  {
43294                     grid.render();
43295                 }
43296                 break;
43297            
43298                
43299                 
43300                 
43301             default: 
43302                 alert("Can not add '" + Y.xtype + "' to BorderLayout");
43303                 return;
43304              // GridPanel (grid, cfg)
43305             
43306         }
43307
43308         this.beginUpdate();
43309         // add children..
43310         Roo.each(c, function(i)  {
43311             Z.addxtype(i);
43312         });
43313         this.endUpdate();
43314         return  Z;
43315         
43316     }
43317 });
43318
43319 /**
43320  * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43321  * the beginUpdate and endUpdate calls internally.  The key to this method is the <b>panels</b> property that can be
43322  * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43323  * during creation.  The following code is equivalent to the constructor-based example at the beginning of this class:
43324  * <pre><code>
43325 // shorthand
43326 var CP = Roo.ContentPanel;
43327
43328 var layout = Roo.BorderLayout.create({
43329     north: {
43330         initialSize: 25,
43331         titlebar: false,
43332         panels: [new CP("north", "North")]
43333     },
43334     west: {
43335         split:true,
43336         initialSize: 200,
43337         minSize: 175,
43338         maxSize: 400,
43339         titlebar: true,
43340         collapsible: true,
43341         panels: [new CP("west", {title: "West"})]
43342     },
43343     east: {
43344         split:true,
43345         initialSize: 202,
43346         minSize: 175,
43347         maxSize: 400,
43348         titlebar: true,
43349         collapsible: true,
43350         panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43351     },
43352     south: {
43353         split:true,
43354         initialSize: 100,
43355         minSize: 100,
43356         maxSize: 200,
43357         titlebar: true,
43358         collapsible: true,
43359         panels: [new CP("south", {title: "South", closable: true})]
43360     },
43361     center: {
43362         titlebar: true,
43363         autoScroll:true,
43364         resizeTabs: true,
43365         minTabWidth: 50,
43366         preferredTabWidth: 150,
43367         panels: [
43368             new CP("center1", {title: "Close Me", closable: true}),
43369             new CP("center2", {title: "Center Panel", closable: false})
43370         ]
43371     }
43372 }, document.body);
43373
43374 layout.getRegion("center").showPanel("center1");
43375 </code></pre>
43376  * @param config
43377  * @param targetEl
43378  */
43379 Roo.BorderLayout.create = function(d, e){
43380     var  f = new  Roo.BorderLayout(e || document.body, d);
43381     f.beginUpdate();
43382     var  g = Roo.BorderLayout.RegionFactory.validRegions;
43383     for(var  j = 0, jlen = g.length; j < jlen; j++){
43384         var  lr = g[j];
43385         if(f.regions[lr] && d[lr].panels){
43386             var  r = f.regions[lr];
43387             var  ps = d[lr].panels;
43388             f.addTypedPanels(r, ps);
43389         }
43390     }
43391
43392     f.endUpdate();
43393     return  f;
43394 };
43395
43396 // private
43397 Roo.BorderLayout.RegionFactory = {
43398     // private
43399     validRegions : ["north","south","east","west","center"],
43400
43401     // private
43402     create : function(k, l, n){
43403         k = k.toLowerCase();
43404         if(n.lightweight || n.basic){
43405             return  new  Roo.BasicLayoutRegion(l, n, k);
43406         }
43407         switch(k){
43408             case  "north":
43409                 return  new  Roo.NorthLayoutRegion(l, n);
43410             case  "south":
43411                 return  new  Roo.SouthLayoutRegion(l, n);
43412             case  "east":
43413                 return  new  Roo.EastLayoutRegion(l, n);
43414             case  "west":
43415                 return  new  Roo.WestLayoutRegion(l, n);
43416             case  "center":
43417                 return  new  Roo.CenterLayoutRegion(l, n);
43418         }
43419         throw  'Layout region "'+k+'" not supported.';
43420     }
43421 };
43422 /*
43423  * Based on:
43424  * Ext JS Library 1.1.1
43425  * Copyright(c) 2006-2007, Ext JS, LLC.
43426  *
43427  * Originally Released Under LGPL - original licence link has changed is not relivant.
43428  *
43429  * Fork - LGPL
43430  * <script type="text/javascript">
43431  */
43432  
43433 /**
43434  * @class Roo.BasicLayoutRegion
43435  * @extends Roo.util.Observable
43436  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43437  * and does not have a titlebar, tabs or any other features. All it does is size and position 
43438  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43439  */
43440 Roo.BasicLayoutRegion = function(A, B, C, D){
43441     this.mgr = A;
43442     this.position  = C;
43443     this.events = {
43444         /**
43445          * @scope Roo.BasicLayoutRegion
43446          */
43447         
43448         /**
43449          * @event beforeremove
43450          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43451          * @param {Roo.LayoutRegion} this
43452          * @param {Roo.ContentPanel} panel The panel
43453          * @param {Object} e The cancel event object
43454          */
43455         "beforeremove" : true,
43456         /**
43457          * @event invalidated
43458          * Fires when the layout for this region is changed.
43459          * @param {Roo.LayoutRegion} this
43460          */
43461         "invalidated" : true,
43462         /**
43463          * @event visibilitychange
43464          * Fires when this region is shown or hidden 
43465          * @param {Roo.LayoutRegion} this
43466          * @param {Boolean} visibility true or false
43467          */
43468         "visibilitychange" : true,
43469         /**
43470          * @event paneladded
43471          * Fires when a panel is added. 
43472          * @param {Roo.LayoutRegion} this
43473          * @param {Roo.ContentPanel} panel The panel
43474          */
43475         "paneladded" : true,
43476         /**
43477          * @event panelremoved
43478          * Fires when a panel is removed. 
43479          * @param {Roo.LayoutRegion} this
43480          * @param {Roo.ContentPanel} panel The panel
43481          */
43482         "panelremoved" : true,
43483         /**
43484          * @event collapsed
43485          * Fires when this region is collapsed.
43486          * @param {Roo.LayoutRegion} this
43487          */
43488         "collapsed" : true,
43489         /**
43490          * @event expanded
43491          * Fires when this region is expanded.
43492          * @param {Roo.LayoutRegion} this
43493          */
43494         "expanded" : true,
43495         /**
43496          * @event slideshow
43497          * Fires when this region is slid into view.
43498          * @param {Roo.LayoutRegion} this
43499          */
43500         "slideshow" : true,
43501         /**
43502          * @event slidehide
43503          * Fires when this region slides out of view. 
43504          * @param {Roo.LayoutRegion} this
43505          */
43506         "slidehide" : true,
43507         /**
43508          * @event panelactivated
43509          * Fires when a panel is activated. 
43510          * @param {Roo.LayoutRegion} this
43511          * @param {Roo.ContentPanel} panel The activated panel
43512          */
43513         "panelactivated" : true,
43514         /**
43515          * @event resized
43516          * Fires when the user resizes this region. 
43517          * @param {Roo.LayoutRegion} this
43518          * @param {Number} newSize The new size (width for east/west, height for north/south)
43519          */
43520         "resized" : true
43521     };
43522     /** A collection of panels in this region. @type Roo.util.MixedCollection */
43523     this.panels = new  Roo.util.MixedCollection();
43524     this.panels.getKey = this.getPanelId.createDelegate(this);
43525     this.box = null;
43526     this.activePanel = null;
43527     // ensure listeners are added...
43528     
43529     if (B.listeners || B.events) {
43530         Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43531             listeners : B.listeners || {},
43532             events : B.events || {}
43533         });
43534     }
43535     
43536     if(D !== true){
43537         this.applyConfig(B);
43538     }
43539 };
43540
43541 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43542     getPanelId : function(p){
43543         return  p.getId();
43544     },
43545     
43546     applyConfig : function(E){
43547         this.margins = E.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43548         this.config = E;
43549         
43550     },
43551     
43552     /**
43553      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
43554      * the width, for horizontal (north, south) the height.
43555      * @param {Number} newSize The new width or height
43556      */
43557     resizeTo : function(F){
43558         var  el = this.el ? this.el :
43559                  (this.activePanel ? this.activePanel.getEl() : null);
43560         if(el){
43561             switch(this.position){
43562                 case  "east":
43563                 case  "west":
43564                     el.setWidth(F);
43565                     this.fireEvent("resized", this, F);
43566                 break;
43567                 case  "north":
43568                 case  "south":
43569                     el.setHeight(F);
43570                     this.fireEvent("resized", this, F);
43571                 break;                
43572             }
43573         }
43574     },
43575     
43576     getBox : function(){
43577         return  this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43578     },
43579     
43580     getMargins : function(){
43581         return  this.margins;
43582     },
43583     
43584     updateBox : function(G){
43585         this.box = G;
43586         var  el = this.activePanel.getEl();
43587         el.dom.style.left = G.x + "px";
43588         el.dom.style.top = G.y + "px";
43589         this.activePanel.setSize(G.width, G.height);
43590     },
43591     
43592     /**
43593      * Returns the container element for this region.
43594      * @return {Roo.Element}
43595      */
43596     getEl : function(){
43597         return  this.activePanel;
43598     },
43599     
43600     /**
43601      * Returns true if this region is currently visible.
43602      * @return {Boolean}
43603      */
43604     isVisible : function(){
43605         return  this.activePanel ? true : false;
43606     },
43607     
43608     setActivePanel : function(H){
43609         H = this.getPanel(H);
43610         if(this.activePanel && this.activePanel != H){
43611             this.activePanel.setActiveState(false);
43612             this.activePanel.getEl().setLeftTop(-10000,-10000);
43613         }
43614
43615         this.activePanel = H;
43616         H.setActiveState(true);
43617         if(this.box){
43618             H.setSize(this.box.width, this.box.height);
43619         }
43620
43621         this.fireEvent("panelactivated", this, H);
43622         this.fireEvent("invalidated");
43623     },
43624     
43625     /**
43626      * Show the specified panel.
43627      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43628      * @return {Roo.ContentPanel} The shown panel or null
43629      */
43630     showPanel : function(I){
43631         if(I = this.getPanel(I)){
43632             this.setActivePanel(I);
43633         }
43634         return  I;
43635     },
43636     
43637     /**
43638      * Get the active panel for this region.
43639      * @return {Roo.ContentPanel} The active panel or null
43640      */
43641     getActivePanel : function(){
43642         return  this.activePanel;
43643     },
43644     
43645     /**
43646      * Add the passed ContentPanel(s)
43647      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43648      * @return {Roo.ContentPanel} The panel added (if only one was added)
43649      */
43650     add : function(J){
43651         if(arguments.length > 1){
43652             for(var  i = 0, len = arguments.length; i < len; i++) {
43653                 this.add(arguments[i]);
43654             }
43655             return  null;
43656         }
43657         if(this.hasPanel(J)){
43658             this.showPanel(J);
43659             return  J;
43660         }
43661         var  el = J.getEl();
43662         if(el.dom.parentNode != this.mgr.el.dom){
43663             this.mgr.el.dom.appendChild(el.dom);
43664         }
43665         if(J.setRegion){
43666             J.setRegion(this);
43667         }
43668
43669         this.panels.add(J);
43670         el.setStyle("position", "absolute");
43671         if(!J.background){
43672             this.setActivePanel(J);
43673             if(this.config.initialSize && this.panels.getCount()==1){
43674                 this.resizeTo(this.config.initialSize);
43675             }
43676         }
43677
43678         this.fireEvent("paneladded", this, J);
43679         return  J;
43680     },
43681     
43682     /**
43683      * Returns true if the panel is in this region.
43684      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43685      * @return {Boolean}
43686      */
43687     hasPanel : function(K){
43688         if(typeof  K == "object"){ // must be panel obj
43689             K = K.getId();
43690         }
43691         return  this.getPanel(K) ? true : false;
43692     },
43693     
43694     /**
43695      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43696      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43697      * @param {Boolean} preservePanel Overrides the config preservePanel option
43698      * @return {Roo.ContentPanel} The panel that was removed
43699      */
43700     remove : function(L, M){
43701         L = this.getPanel(L);
43702         if(!L){
43703             return  null;
43704         }
43705         var  e = {};
43706         this.fireEvent("beforeremove", this, L, e);
43707         if(e.cancel === true){
43708             return  null;
43709         }
43710         var  N = L.getId();
43711         this.panels.removeKey(N);
43712         return  L;
43713     },
43714     
43715     /**
43716      * Returns the panel specified or null if it's not in this region.
43717      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43718      * @return {Roo.ContentPanel}
43719      */
43720     getPanel : function(id){
43721         if(typeof  id == "object"){ // must be panel obj
43722             return  id;
43723         }
43724         return  this.panels.get(id);
43725     },
43726     
43727     /**
43728      * Returns this regions position (north/south/east/west/center).
43729      * @return {String} 
43730      */
43731     getPosition: function(){
43732         return  this.position;    
43733     }
43734 });
43735 /*
43736  * Based on:
43737  * Ext JS Library 1.1.1
43738  * Copyright(c) 2006-2007, Ext JS, LLC.
43739  *
43740  * Originally Released Under LGPL - original licence link has changed is not relivant.
43741  *
43742  * Fork - LGPL
43743  * <script type="text/javascript">
43744  */
43745  
43746 /**
43747  * @class Roo.LayoutRegion
43748  * @extends Roo.BasicLayoutRegion
43749  * This class represents a region in a layout manager.
43750  * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43751  * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43752  * @cfg {Boolean} floatable False to disable floating (defaults to true)
43753  * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43754  * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
43755  * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43756  * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43757  * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43758  * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43759  * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43760  * @cfg {String} title The title for the region (overrides panel titles)
43761  * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43762  * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43763  * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43764  * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43765  * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43766  * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43767  * the space available, similar to FireFox 1.5 tabs (defaults to false)
43768  * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43769  * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43770  * @cfg {Boolean} showPin True to show a pin button
43771 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43772 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43773 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43774 * @cfg {Number} width  For East/West panels
43775 * @cfg {Number} height For North/South panels
43776 * @cfg {Boolean} split To show the splitter
43777  */
43778 Roo.LayoutRegion = function(A, B, C){
43779     Roo.LayoutRegion.superclass.constructor.call(this, A, B, C, true);
43780     var  dh = Roo.DomHelper;
43781     /** This region's container element 
43782     * @type Roo.Element */
43783     this.el = dh.append(A.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43784     /** This region's title element 
43785     * @type Roo.Element */
43786
43787     this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43788         {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
43789         {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43790     ]}, true);
43791     this.titleEl.enableDisplayMode();
43792     /** This region's title text element 
43793     * @type HTMLElement */
43794     this.titleTextEl = this.titleEl.dom.firstChild;
43795     this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43796     this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43797     this.closeBtn.enableDisplayMode();
43798     this.closeBtn.on("click", this.closeClicked, this);
43799     this.closeBtn.hide();
43800
43801     this.createBody(B);
43802     this.visible = true;
43803     this.collapsed = false;
43804
43805     if(B.hideWhenEmpty){
43806         this.hide();
43807         this.on("paneladded", this.validateVisibility, this);
43808         this.on("panelremoved", this.validateVisibility, this);
43809     }
43810
43811     this.applyConfig(B);
43812 };
43813
43814 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43815
43816     createBody : function(){
43817         /** This region's body element 
43818         * @type Roo.Element */
43819         this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43820     },
43821
43822     applyConfig : function(c){
43823         if(c.collapsible && this.position != "center" && !this.collapsedEl){
43824             var  dh = Roo.DomHelper;
43825             if(c.titlebar !== false){
43826                 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43827                 this.collapseBtn.on("click", this.collapse, this);
43828                 this.collapseBtn.enableDisplayMode();
43829
43830                 if(c.showPin === true || this.showPin){
43831                     this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43832                     this.stickBtn.enableDisplayMode();
43833                     this.stickBtn.on("click", this.expand, this);
43834                     this.stickBtn.hide();
43835                 }
43836             }
43837
43838             /** This region's collapsed element
43839             * @type Roo.Element */
43840             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43841                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43842             ]}, true);
43843             if(c.floatable !== false){
43844                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43845                this.collapsedEl.on("click", this.collapseClick, this);
43846             }
43847
43848             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43849                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43850                    id: "message", unselectable: "on", style:{"float":"left"}});
43851                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43852              }
43853
43854             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43855             this.expandBtn.on("click", this.expand, this);
43856         }
43857         if(this.collapseBtn){
43858             this.collapseBtn.setVisible(c.collapsible == true);
43859         }
43860
43861         this.cmargins = c.cmargins || this.cmargins ||
43862                          (this.position == "west" || this.position == "east" ?
43863                              {top: 0, left: 2, right:2, bottom: 0} :
43864                              {top: 2, left: 0, right:0, bottom: 2});
43865         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43866         this.bottomTabs = c.tabPosition != "top";
43867         this.autoScroll = c.autoScroll || false;
43868         if(this.autoScroll){
43869             this.bodyEl.setStyle("overflow", "auto");
43870         }else {
43871             this.bodyEl.setStyle("overflow", "hidden");
43872         }
43873         //if(c.titlebar !== false){
43874             if((!c.titlebar && !c.title) || c.titlebar === false){
43875                 this.titleEl.hide();
43876             }else {
43877                 this.titleEl.show();
43878                 if(c.title){
43879                     this.titleTextEl.innerHTML = c.title;
43880                 }
43881             }
43882
43883         //}
43884         this.duration = c.duration || .30;
43885         this.slideDuration = c.slideDuration || .45;
43886         this.config = c;
43887         if(c.collapsed){
43888             this.collapse(true);
43889         }
43890         if(c.hidden){
43891             this.hide();
43892         }
43893     },
43894     /**
43895      * Returns true if this region is currently visible.
43896      * @return {Boolean}
43897      */
43898     isVisible : function(){
43899         return  this.visible;
43900     },
43901
43902     /**
43903      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43904      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
43905      */
43906     setCollapsedTitle : function(D){
43907         D = D || "&#160;";
43908         if(this.collapsedTitleTextEl){
43909             this.collapsedTitleTextEl.innerHTML = D;
43910         }
43911     },
43912
43913     getBox : function(){
43914         var  b;
43915         if(!this.collapsed){
43916             b = this.el.getBox(false, true);
43917         }else {
43918             b = this.collapsedEl.getBox(false, true);
43919         }
43920         return  b;
43921     },
43922
43923     getMargins : function(){
43924         return  this.collapsed ? this.cmargins : this.margins;
43925     },
43926
43927     highlight : function(){
43928         this.el.addClass("x-layout-panel-dragover");
43929     },
43930
43931     unhighlight : function(){
43932         this.el.removeClass("x-layout-panel-dragover");
43933     },
43934
43935     updateBox : function(E){
43936         this.box = E;
43937         if(!this.collapsed){
43938             this.el.dom.style.left = E.x + "px";
43939             this.el.dom.style.top = E.y + "px";
43940             this.updateBody(E.width, E.height);
43941         }else {
43942             this.collapsedEl.dom.style.left = E.x + "px";
43943             this.collapsedEl.dom.style.top = E.y + "px";
43944             this.collapsedEl.setSize(E.width, E.height);
43945         }
43946         if(this.tabs){
43947             this.tabs.autoSizeTabs();
43948         }
43949     },
43950
43951     updateBody : function(w, h){
43952         if(w !== null){
43953             this.el.setWidth(w);
43954             w -= this.el.getBorderWidth("rl");
43955             if(this.config.adjustments){
43956                 w += this.config.adjustments[0];
43957             }
43958         }
43959         if(h !== null){
43960             this.el.setHeight(h);
43961             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43962             h -= this.el.getBorderWidth("tb");
43963             if(this.config.adjustments){
43964                 h += this.config.adjustments[1];
43965             }
43966
43967             this.bodyEl.setHeight(h);
43968             if(this.tabs){
43969                 h = this.tabs.syncHeight(h);
43970             }
43971         }
43972         if(this.panelSize){
43973             w = w !== null ? w : this.panelSize.width;
43974             h = h !== null ? h : this.panelSize.height;
43975         }
43976         if(this.activePanel){
43977             var  el = this.activePanel.getEl();
43978             w = w !== null ? w : el.getWidth();
43979             h = h !== null ? h : el.getHeight();
43980             this.panelSize = {width: w, height: h};
43981             this.activePanel.setSize(w, h);
43982         }
43983         if(Roo.isIE && this.tabs){
43984             this.tabs.el.repaint();
43985         }
43986     },
43987
43988     /**
43989      * Returns the container element for this region.
43990      * @return {Roo.Element}
43991      */
43992     getEl : function(){
43993         return  this.el;
43994     },
43995
43996     /**
43997      * Hides this region.
43998      */
43999     hide : function(){
44000         if(!this.collapsed){
44001             this.el.dom.style.left = "-2000px";
44002             this.el.hide();
44003         }else {
44004             this.collapsedEl.dom.style.left = "-2000px";
44005             this.collapsedEl.hide();
44006         }
44007
44008         this.visible = false;
44009         this.fireEvent("visibilitychange", this, false);
44010     },
44011
44012     /**
44013      * Shows this region if it was previously hidden.
44014      */
44015     show : function(){
44016         if(!this.collapsed){
44017             this.el.show();
44018         }else {
44019             this.collapsedEl.show();
44020         }
44021
44022         this.visible = true;
44023         this.fireEvent("visibilitychange", this, true);
44024     },
44025
44026     closeClicked : function(){
44027         if(this.activePanel){
44028             this.remove(this.activePanel);
44029         }
44030     },
44031
44032     collapseClick : function(e){
44033         if(this.isSlid){
44034            e.stopPropagation();
44035            this.slideIn();
44036         }else {
44037            e.stopPropagation();
44038            this.slideOut();
44039         }
44040     },
44041
44042     /**
44043      * Collapses this region.
44044      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44045      */
44046     collapse : function(F){
44047         if(this.collapsed) return;
44048         this.collapsed = true;
44049         if(this.split){
44050             this.split.el.hide();
44051         }
44052         if(this.config.animate && F !== true){
44053             this.fireEvent("invalidated", this);
44054             this.animateCollapse();
44055         }else {
44056             this.el.setLocation(-20000,-20000);
44057             this.el.hide();
44058             this.collapsedEl.show();
44059             this.fireEvent("collapsed", this);
44060             this.fireEvent("invalidated", this);
44061         }
44062     },
44063
44064     animateCollapse : function(){
44065         // overridden
44066     },
44067
44068     /**
44069      * Expands this region if it was previously collapsed.
44070      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44071      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44072      */
44073     expand : function(e, G){
44074         if(e) e.stopPropagation();
44075         if(!this.collapsed || this.el.hasActiveFx()) return;
44076         if(this.isSlid){
44077             this.afterSlideIn();
44078             G = true;
44079         }
44080
44081         this.collapsed = false;
44082         if(this.config.animate && G !== true){
44083             this.animateExpand();
44084         }else {
44085             this.el.show();
44086             if(this.split){
44087                 this.split.el.show();
44088             }
44089
44090             this.collapsedEl.setLocation(-2000,-2000);
44091             this.collapsedEl.hide();
44092             this.fireEvent("invalidated", this);
44093             this.fireEvent("expanded", this);
44094         }
44095     },
44096
44097     animateExpand : function(){
44098         // overridden
44099     },
44100
44101     initTabs : function(){
44102         this.bodyEl.setStyle("overflow", "hidden");
44103         var  ts = new  Roo.TabPanel(this.bodyEl.dom, {
44104             tabPosition: this.bottomTabs ? 'bottom' : 'top',
44105             disableTooltips: this.config.disableTabTips
44106         });
44107         if(this.config.hideTabs){
44108             ts.stripWrap.setDisplayed(false);
44109         }
44110
44111         this.tabs = ts;
44112         ts.resizeTabs = this.config.resizeTabs === true;
44113         ts.minTabWidth = this.config.minTabWidth || 40;
44114         ts.maxTabWidth = this.config.maxTabWidth || 250;
44115         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44116         ts.monitorResize = false;
44117         ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44118         ts.bodyEl.addClass('x-layout-tabs-body');
44119         this.panels.each(this.initPanelAsTab, this);
44120     },
44121
44122     initPanelAsTab : function(H){
44123         var  ti = this.tabs.addTab(H.getEl().id, H.getTitle(), null,
44124                     this.config.closeOnTab && H.isClosable());
44125         if(H.tabTip !== undefined){
44126             ti.setTooltip(H.tabTip);
44127         }
44128
44129         ti.on("activate", function(){
44130               this.setActivePanel(H);
44131         }, this);
44132         if(this.config.closeOnTab){
44133             ti.on("beforeclose", function(t, e){
44134                 e.cancel = true;
44135                 this.remove(H);
44136             }, this);
44137         }
44138         return  ti;
44139     },
44140
44141     updatePanelTitle : function(I, J){
44142         if(this.activePanel == I){
44143             this.updateTitle(J);
44144         }
44145         if(this.tabs){
44146             var  ti = this.tabs.getTab(I.getEl().id);
44147             ti.setText(J);
44148             if(I.tabTip !== undefined){
44149                 ti.setTooltip(I.tabTip);
44150             }
44151         }
44152     },
44153
44154     updateTitle : function(K){
44155         if(this.titleTextEl && !this.config.title){
44156             this.titleTextEl.innerHTML = (typeof  K != "undefined" && K.length > 0 ? K : "&#160;");
44157         }
44158     },
44159
44160     setActivePanel : function(L){
44161         L = this.getPanel(L);
44162         if(this.activePanel && this.activePanel != L){
44163             this.activePanel.setActiveState(false);
44164         }
44165
44166         this.activePanel = L;
44167         L.setActiveState(true);
44168         if(this.panelSize){
44169             L.setSize(this.panelSize.width, this.panelSize.height);
44170         }
44171         if(this.closeBtn){
44172             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && L.isClosable());
44173         }
44174
44175         this.updateTitle(L.getTitle());
44176         if(this.tabs){
44177             this.fireEvent("invalidated", this);
44178         }
44179
44180         this.fireEvent("panelactivated", this, L);
44181     },
44182
44183     /**
44184      * Shows the specified panel.
44185      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44186      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44187      */
44188     showPanel : function(M){
44189         if(M = this.getPanel(M)){
44190             if(this.tabs){
44191                 var  tab = this.tabs.getTab(M.getEl().id);
44192                 if(tab.isHidden()){
44193                     this.tabs.unhideTab(tab.id);
44194                 }
44195
44196                 tab.activate();
44197             }else {
44198                 this.setActivePanel(M);
44199             }
44200         }
44201         return  M;
44202     },
44203
44204     /**
44205      * Get the active panel for this region.
44206      * @return {Roo.ContentPanel} The active panel or null
44207      */
44208     getActivePanel : function(){
44209         return  this.activePanel;
44210     },
44211
44212     validateVisibility : function(){
44213         if(this.panels.getCount() < 1){
44214             this.updateTitle("&#160;");
44215             this.closeBtn.hide();
44216             this.hide();
44217         }else {
44218             if(!this.isVisible()){
44219                 this.show();
44220             }
44221         }
44222     },
44223
44224     /**
44225      * Adds the passed ContentPanel(s) to this region.
44226      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44227      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44228      */
44229     add : function(N){
44230         if(arguments.length > 1){
44231             for(var  i = 0, len = arguments.length; i < len; i++) {
44232                 this.add(arguments[i]);
44233             }
44234             return  null;
44235         }
44236         if(this.hasPanel(N)){
44237             this.showPanel(N);
44238             return  N;
44239         }
44240
44241         N.setRegion(this);
44242         this.panels.add(N);
44243         if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44244             this.bodyEl.dom.appendChild(N.getEl().dom);
44245             if(N.background !== true){
44246                 this.setActivePanel(N);
44247             }
44248
44249             this.fireEvent("paneladded", this, N);
44250             return  N;
44251         }
44252         if(!this.tabs){
44253             this.initTabs();
44254         }else {
44255             this.initPanelAsTab(N);
44256         }
44257         if(N.background !== true){
44258             this.tabs.activate(N.getEl().id);
44259         }
44260
44261         this.fireEvent("paneladded", this, N);
44262         return  N;
44263     },
44264
44265     /**
44266      * Hides the tab for the specified panel.
44267      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44268      */
44269     hidePanel : function(O){
44270         if(this.tabs && (O = this.getPanel(O))){
44271             this.tabs.hideTab(O.getEl().id);
44272         }
44273     },
44274
44275     /**
44276      * Unhides the tab for a previously hidden panel.
44277      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44278      */
44279     unhidePanel : function(P){
44280         if(this.tabs && (P = this.getPanel(P))){
44281             this.tabs.unhideTab(P.getEl().id);
44282         }
44283     },
44284
44285     clearPanels : function(){
44286         while(this.panels.getCount() > 0){
44287              this.remove(this.panels.first());
44288         }
44289     },
44290
44291     /**
44292      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44293      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44294      * @param {Boolean} preservePanel Overrides the config preservePanel option
44295      * @return {Roo.ContentPanel} The panel that was removed
44296      */
44297     remove : function(Q, R){
44298         Q = this.getPanel(Q);
44299         if(!Q){
44300             return  null;
44301         }
44302         var  e = {};
44303         this.fireEvent("beforeremove", this, Q, e);
44304         if(e.cancel === true){
44305             return  null;
44306         }
44307
44308         R = (typeof  R != "undefined" ? R : (this.config.preservePanels === true || Q.preserve === true));
44309         var  S = Q.getId();
44310         this.panels.removeKey(S);
44311         if(R){
44312             document.body.appendChild(Q.getEl().dom);
44313         }
44314         if(this.tabs){
44315             this.tabs.removeTab(Q.getEl().id);
44316         }else  if (!R){
44317             this.bodyEl.dom.removeChild(Q.getEl().dom);
44318         }
44319         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44320             var  p = this.panels.first();
44321             var  tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44322             tempEl.appendChild(p.getEl().dom);
44323             this.bodyEl.update("");
44324             this.bodyEl.dom.appendChild(p.getEl().dom);
44325             tempEl = null;
44326             this.updateTitle(p.getTitle());
44327             this.tabs = null;
44328             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44329             this.setActivePanel(p);
44330         }
44331
44332         Q.setRegion(null);
44333         if(this.activePanel == Q){
44334             this.activePanel = null;
44335         }
44336         if(this.config.autoDestroy !== false && R !== true){
44337             try{Q.destroy();}catch(e){}
44338         }
44339
44340         this.fireEvent("panelremoved", this, Q);
44341         return  Q;
44342     },
44343
44344     /**
44345      * Returns the TabPanel component used by this region
44346      * @return {Roo.TabPanel}
44347      */
44348     getTabs : function(){
44349         return  this.tabs;
44350     },
44351
44352     createTool : function(T, U){
44353         var  V = Roo.DomHelper.append(T, {tag: "div", cls: "x-layout-tools-button",
44354             children: [{tag: "div", cls: "x-layout-tools-button-inner " + U, html: "&#160;"}]}, true);
44355         V.addClassOnOver("x-layout-tools-button-over");
44356         return  V;
44357     }
44358 });
44359 /*
44360  * Based on:
44361  * Ext JS Library 1.1.1
44362  * Copyright(c) 2006-2007, Ext JS, LLC.
44363  *
44364  * Originally Released Under LGPL - original licence link has changed is not relivant.
44365  *
44366  * Fork - LGPL
44367  * <script type="text/javascript">
44368  */
44369  
44370
44371
44372 /**
44373  * @class Roo.SplitLayoutRegion
44374  * @extends Roo.LayoutRegion
44375  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44376  */
44377 Roo.SplitLayoutRegion = function(A, B, C, D){
44378     this.cursor = D;
44379     Roo.SplitLayoutRegion.superclass.constructor.call(this, A, B, C);
44380 };
44381
44382 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44383     splitTip : "Drag to resize.",
44384     collapsibleSplitTip : "Drag to resize. Double click to hide.",
44385     useSplitTips : false,
44386
44387     applyConfig : function(E){
44388         Roo.SplitLayoutRegion.superclass.applyConfig.call(this, E);
44389         if(E.split){
44390             if(!this.split){
44391                 var  splitEl = Roo.DomHelper.append(this.mgr.el.dom, 
44392                         {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: "&#160;"});
44393                 /** The SplitBar for this region 
44394                 * @type Roo.SplitBar */
44395                 this.split = new  Roo.SplitBar(splitEl, this.el, this.orientation);
44396                 this.split.on("moved", this.onSplitMove, this);
44397                 this.split.useShim = E.useShim === true;
44398                 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44399                 if(this.useSplitTips){
44400                     this.split.el.dom.title = E.collapsible ? this.collapsibleSplitTip : this.splitTip;
44401                 }
44402                 if(E.collapsible){
44403                     this.split.el.on("dblclick", this.collapse,  this);
44404                 }
44405             }
44406             if(typeof  E.minSize != "undefined"){
44407                 this.split.minSize = E.minSize;
44408             }
44409             if(typeof  E.maxSize != "undefined"){
44410                 this.split.maxSize = E.maxSize;
44411             }
44412             if(E.hideWhenEmpty || E.hidden || E.collapsed){
44413                 this.hideSplitter();
44414             }
44415         }
44416     },
44417
44418     getHMaxSize : function(){
44419          var  F = this.config.maxSize || 10000;
44420          var  G = this.mgr.getRegion("center");
44421          return  Math.min(F, (this.el.getWidth()+G.getEl().getWidth())-G.getMinWidth());
44422     },
44423
44424     getVMaxSize : function(){
44425          var  H = this.config.maxSize || 10000;
44426          var  I = this.mgr.getRegion("center");
44427          return  Math.min(H, (this.el.getHeight()+I.getEl().getHeight())-I.getMinHeight());
44428     },
44429
44430     onSplitMove : function(J, K){
44431         this.fireEvent("resized", this, K);
44432     },
44433     
44434     /** 
44435      * Returns the {@link Roo.SplitBar} for this region.
44436      * @return {Roo.SplitBar}
44437      */
44438     getSplitBar : function(){
44439         return  this.split;
44440     },
44441     
44442     hide : function(){
44443         this.hideSplitter();
44444         Roo.SplitLayoutRegion.superclass.hide.call(this);
44445     },
44446
44447     hideSplitter : function(){
44448         if(this.split){
44449             this.split.el.setLocation(-2000,-2000);
44450             this.split.el.hide();
44451         }
44452     },
44453
44454     show : function(){
44455         if(this.split){
44456             this.split.el.show();
44457         }
44458
44459         Roo.SplitLayoutRegion.superclass.show.call(this);
44460     },
44461     
44462     beforeSlide: function(){
44463         if(Roo.isGecko){// firefox overflow auto bug workaround
44464             this.bodyEl.clip();
44465             if(this.tabs) this.tabs.bodyEl.clip();
44466             if(this.activePanel){
44467                 this.activePanel.getEl().clip();
44468                 
44469                 if(this.activePanel.beforeSlide){
44470                     this.activePanel.beforeSlide();
44471                 }
44472             }
44473         }
44474     },
44475     
44476     afterSlide : function(){
44477         if(Roo.isGecko){// firefox overflow auto bug workaround
44478             this.bodyEl.unclip();
44479             if(this.tabs) this.tabs.bodyEl.unclip();
44480             if(this.activePanel){
44481                 this.activePanel.getEl().unclip();
44482                 if(this.activePanel.afterSlide){
44483                     this.activePanel.afterSlide();
44484                 }
44485             }
44486         }
44487     },
44488
44489     initAutoHide : function(){
44490         if(this.autoHide !== false){
44491             if(!this.autoHideHd){
44492                 var  st = new  Roo.util.DelayedTask(this.slideIn, this);
44493                 this.autoHideHd = {
44494                     "mouseout": function(e){
44495                         if(!e.within(this.el, true)){
44496                             st.delay(500);
44497                         }
44498                     },
44499                     "mouseover" : function(e){
44500                         st.cancel();
44501                     },
44502                     scope : this
44503                 };
44504             }
44505
44506             this.el.on(this.autoHideHd);
44507         }
44508     },
44509
44510     clearAutoHide : function(){
44511         if(this.autoHide !== false){
44512             this.el.un("mouseout", this.autoHideHd.mouseout);
44513             this.el.un("mouseover", this.autoHideHd.mouseover);
44514         }
44515     },
44516
44517     clearMonitor : function(){
44518         Roo.get(document).un("click", this.slideInIf, this);
44519     },
44520
44521     // these names are backwards but not changed for compat
44522     slideOut : function(){
44523         if(this.isSlid || this.el.hasActiveFx()){
44524             return;
44525         }
44526
44527         this.isSlid = true;
44528         if(this.collapseBtn){
44529             this.collapseBtn.hide();
44530         }
44531
44532         this.closeBtnState = this.closeBtn.getStyle('display');
44533         this.closeBtn.hide();
44534         if(this.stickBtn){
44535             this.stickBtn.show();
44536         }
44537
44538         this.el.show();
44539         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44540         this.beforeSlide();
44541         this.el.setStyle("z-index", 10001);
44542         this.el.slideIn(this.getSlideAnchor(), {
44543             callback: function(){
44544                 this.afterSlide();
44545                 this.initAutoHide();
44546                 Roo.get(document).on("click", this.slideInIf, this);
44547                 this.fireEvent("slideshow", this);
44548             },
44549             scope: this,
44550             block: true
44551         });
44552     },
44553
44554     afterSlideIn : function(){
44555         this.clearAutoHide();
44556         this.isSlid = false;
44557         this.clearMonitor();
44558         this.el.setStyle("z-index", "");
44559         if(this.collapseBtn){
44560             this.collapseBtn.show();
44561         }
44562
44563         this.closeBtn.setStyle('display', this.closeBtnState);
44564         if(this.stickBtn){
44565             this.stickBtn.hide();
44566         }
44567
44568         this.fireEvent("slidehide", this);
44569     },
44570
44571     slideIn : function(cb){
44572         if(!this.isSlid || this.el.hasActiveFx()){
44573             Roo.callback(cb);
44574             return;
44575         }
44576
44577         this.isSlid = false;
44578         this.beforeSlide();
44579         this.el.slideOut(this.getSlideAnchor(), {
44580             callback: function(){
44581                 this.el.setLeftTop(-10000, -10000);
44582                 this.afterSlide();
44583                 this.afterSlideIn();
44584                 Roo.callback(cb);
44585             },
44586             scope: this,
44587             block: true
44588         });
44589     },
44590     
44591     slideInIf : function(e){
44592         if(!e.within(this.el)){
44593             this.slideIn();
44594         }
44595     },
44596
44597     animateCollapse : function(){
44598         this.beforeSlide();
44599         this.el.setStyle("z-index", 20000);
44600         var  L = this.getSlideAnchor();
44601         this.el.slideOut(L, {
44602             callback : function(){
44603                 this.el.setStyle("z-index", "");
44604                 this.collapsedEl.slideIn(L, {duration:.3});
44605                 this.afterSlide();
44606                 this.el.setLocation(-10000,-10000);
44607                 this.el.hide();
44608                 this.fireEvent("collapsed", this);
44609             },
44610             scope: this,
44611             block: true
44612         });
44613     },
44614
44615     animateExpand : function(){
44616         this.beforeSlide();
44617         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44618         this.el.setStyle("z-index", 20000);
44619         this.collapsedEl.hide({
44620             duration:.1
44621         });
44622         this.el.slideIn(this.getSlideAnchor(), {
44623             callback : function(){
44624                 this.el.setStyle("z-index", "");
44625                 this.afterSlide();
44626                 if(this.split){
44627                     this.split.el.show();
44628                 }
44629
44630                 this.fireEvent("invalidated", this);
44631                 this.fireEvent("expanded", this);
44632             },
44633             scope: this,
44634             block: true
44635         });
44636     },
44637
44638     anchors : {
44639         "west" : "left",
44640         "east" : "right",
44641         "north" : "top",
44642         "south" : "bottom"
44643     },
44644
44645     sanchors : {
44646         "west" : "l",
44647         "east" : "r",
44648         "north" : "t",
44649         "south" : "b"
44650     },
44651
44652     canchors : {
44653         "west" : "tl-tr",
44654         "east" : "tr-tl",
44655         "north" : "tl-bl",
44656         "south" : "bl-tl"
44657     },
44658
44659     getAnchor : function(){
44660         return  this.anchors[this.position];
44661     },
44662
44663     getCollapseAnchor : function(){
44664         return  this.canchors[this.position];
44665     },
44666
44667     getSlideAnchor : function(){
44668         return  this.sanchors[this.position];
44669     },
44670
44671     getAlignAdj : function(){
44672         var  cm = this.cmargins;
44673         switch(this.position){
44674             case  "west":
44675                 return  [0, 0];
44676             break;
44677             case  "east":
44678                 return  [0, 0];
44679             break;
44680             case  "north":
44681                 return  [0, 0];
44682             break;
44683             case  "south":
44684                 return  [0, 0];
44685             break;
44686         }
44687     },
44688
44689     getExpandAdj : function(){
44690         var  c = this.collapsedEl, cm = this.cmargins;
44691         switch(this.position){
44692             case  "west":
44693                 return  [-(cm.right+c.getWidth()+cm.left), 0];
44694             break;
44695             case  "east":
44696                 return  [cm.right+c.getWidth()+cm.left, 0];
44697             break;
44698             case  "north":
44699                 return  [0, -(cm.top+cm.bottom+c.getHeight())];
44700             break;
44701             case  "south":
44702                 return  [0, cm.top+cm.bottom+c.getHeight()];
44703             break;
44704         }
44705     }
44706 });
44707 /*
44708  * Based on:
44709  * Ext JS Library 1.1.1
44710  * Copyright(c) 2006-2007, Ext JS, LLC.
44711  *
44712  * Originally Released Under LGPL - original licence link has changed is not relivant.
44713  *
44714  * Fork - LGPL
44715  * <script type="text/javascript">
44716  */
44717 /*
44718  * These classes are private internal classes
44719  */
44720 Roo.CenterLayoutRegion = function(A, B){
44721     Roo.LayoutRegion.call(this, A, B, "center");
44722     this.visible = true;
44723     this.minWidth = B.minWidth || 20;
44724     this.minHeight = B.minHeight || 20;
44725 };
44726
44727 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
44728     hide : function(){
44729         // center panel can't be hidden
44730     },
44731     
44732     show : function(){
44733         // center panel can't be hidden
44734     },
44735     
44736     getMinWidth: function(){
44737         return  this.minWidth;
44738     },
44739     
44740     getMinHeight: function(){
44741         return  this.minHeight;
44742     }
44743 });
44744
44745
44746 Roo.NorthLayoutRegion = function(C, D){
44747     Roo.LayoutRegion.call(this, C, D, "north", "n-resize");
44748     if(this.split){
44749         this.split.placement = Roo.SplitBar.TOP;
44750         this.split.orientation = Roo.SplitBar.VERTICAL;
44751         this.split.el.addClass("x-layout-split-v");
44752     }
44753     var  E = D.initialSize || D.height;
44754     if(typeof  E != "undefined"){
44755         this.el.setHeight(E);
44756     }
44757 };
44758 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
44759     orientation: Roo.SplitBar.VERTICAL,
44760     getBox : function(){
44761         if(this.collapsed){
44762             return  this.collapsedEl.getBox();
44763         }
44764         var  F = this.el.getBox();
44765         if(this.split){
44766             F.height += this.split.el.getHeight();
44767         }
44768         return  F;
44769     },
44770     
44771     updateBox : function(G){
44772         if(this.split && !this.collapsed){
44773             G.height -= this.split.el.getHeight();
44774             this.split.el.setLeft(G.x);
44775             this.split.el.setTop(G.y+G.height);
44776             this.split.el.setWidth(G.width);
44777         }
44778         if(this.collapsed){
44779             this.updateBody(G.width, null);
44780         }
44781
44782         Roo.LayoutRegion.prototype.updateBox.call(this, G);
44783     }
44784 });
44785
44786 Roo.SouthLayoutRegion = function(H, I){
44787     Roo.SplitLayoutRegion.call(this, H, I, "south", "s-resize");
44788     if(this.split){
44789         this.split.placement = Roo.SplitBar.BOTTOM;
44790         this.split.orientation = Roo.SplitBar.VERTICAL;
44791         this.split.el.addClass("x-layout-split-v");
44792     }
44793     var  J = I.initialSize || I.height;
44794     if(typeof  J != "undefined"){
44795         this.el.setHeight(J);
44796     }
44797 };
44798 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44799     orientation: Roo.SplitBar.VERTICAL,
44800     getBox : function(){
44801         if(this.collapsed){
44802             return  this.collapsedEl.getBox();
44803         }
44804         var  K = this.el.getBox();
44805         if(this.split){
44806             var  sh = this.split.el.getHeight();
44807             K.height += sh;
44808             K.y -= sh;
44809         }
44810         return  K;
44811     },
44812     
44813     updateBox : function(L){
44814         if(this.split && !this.collapsed){
44815             var  sh = this.split.el.getHeight();
44816             L.height -= sh;
44817             L.y += sh;
44818             this.split.el.setLeft(L.x);
44819             this.split.el.setTop(L.y-sh);
44820             this.split.el.setWidth(L.width);
44821         }
44822         if(this.collapsed){
44823             this.updateBody(L.width, null);
44824         }
44825
44826         Roo.LayoutRegion.prototype.updateBox.call(this, L);
44827     }
44828 });
44829
44830 Roo.EastLayoutRegion = function(M, N){
44831     Roo.SplitLayoutRegion.call(this, M, N, "east", "e-resize");
44832     if(this.split){
44833         this.split.placement = Roo.SplitBar.RIGHT;
44834         this.split.orientation = Roo.SplitBar.HORIZONTAL;
44835         this.split.el.addClass("x-layout-split-h");
44836     }
44837     var  O = N.initialSize || N.width;
44838     if(typeof  O != "undefined"){
44839         this.el.setWidth(O);
44840     }
44841 };
44842 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44843     orientation: Roo.SplitBar.HORIZONTAL,
44844     getBox : function(){
44845         if(this.collapsed){
44846             return  this.collapsedEl.getBox();
44847         }
44848         var  P = this.el.getBox();
44849         if(this.split){
44850             var  sw = this.split.el.getWidth();
44851             P.width += sw;
44852             P.x -= sw;
44853         }
44854         return  P;
44855     },
44856
44857     updateBox : function(Q){
44858         if(this.split && !this.collapsed){
44859             var  sw = this.split.el.getWidth();
44860             Q.width -= sw;
44861             this.split.el.setLeft(Q.x);
44862             this.split.el.setTop(Q.y);
44863             this.split.el.setHeight(Q.height);
44864             Q.x += sw;
44865         }
44866         if(this.collapsed){
44867             this.updateBody(null, Q.height);
44868         }
44869
44870         Roo.LayoutRegion.prototype.updateBox.call(this, Q);
44871     }
44872 });
44873
44874 Roo.WestLayoutRegion = function(R, S){
44875     Roo.SplitLayoutRegion.call(this, R, S, "west", "w-resize");
44876     if(this.split){
44877         this.split.placement = Roo.SplitBar.LEFT;
44878         this.split.orientation = Roo.SplitBar.HORIZONTAL;
44879         this.split.el.addClass("x-layout-split-h");
44880     }
44881     var  T = S.initialSize || S.width;
44882     if(typeof  T != "undefined"){
44883         this.el.setWidth(T);
44884     }
44885 };
44886 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44887     orientation: Roo.SplitBar.HORIZONTAL,
44888     getBox : function(){
44889         if(this.collapsed){
44890             return  this.collapsedEl.getBox();
44891         }
44892         var  U = this.el.getBox();
44893         if(this.split){
44894             U.width += this.split.el.getWidth();
44895         }
44896         return  U;
44897     },
44898     
44899     updateBox : function(V){
44900         if(this.split && !this.collapsed){
44901             var  sw = this.split.el.getWidth();
44902             V.width -= sw;
44903             this.split.el.setLeft(V.x+V.width);
44904             this.split.el.setTop(V.y);
44905             this.split.el.setHeight(V.height);
44906         }
44907         if(this.collapsed){
44908             this.updateBody(null, V.height);
44909         }
44910
44911         Roo.LayoutRegion.prototype.updateBox.call(this, V);
44912     }
44913 });
44914
44915 /*
44916  * Based on:
44917  * Ext JS Library 1.1.1
44918  * Copyright(c) 2006-2007, Ext JS, LLC.
44919  *
44920  * Originally Released Under LGPL - original licence link has changed is not relivant.
44921  *
44922  * Fork - LGPL
44923  * <script type="text/javascript">
44924  */
44925  
44926  
44927 /*
44928  * Private internal class for reading and applying state
44929  */
44930 Roo.LayoutStateManager = function(A){
44931      // default empty state
44932      this.state = {
44933         north: {},
44934         south: {},
44935         east: {},
44936         west: {}       
44937     };
44938 };
44939
44940 Roo.LayoutStateManager.prototype = {
44941     init : function(B, C){
44942         this.provider = C;
44943         var  D = C.get(B.id+"-layout-state");
44944         if(D){
44945             var  wasUpdating = B.isUpdating();
44946             if(!wasUpdating){
44947                 B.beginUpdate();
44948             }
44949             for(var  key  in  D){
44950                 if(typeof  D[key] != "function"){
44951                     var  rstate = D[key];
44952                     var  r = B.getRegion(key);
44953                     if(r && rstate){
44954                         if(rstate.size){
44955                             r.resizeTo(rstate.size);
44956                         }
44957                         if(rstate.collapsed == true){
44958                             r.collapse(true);
44959                         }else {
44960                             r.expand(null, true);
44961                         }
44962                     }
44963                 }
44964             }
44965             if(!wasUpdating){
44966                 B.endUpdate();
44967             }
44968
44969             this.state = D; 
44970         }
44971
44972         this.layout = B;
44973         B.on("regionresized", this.onRegionResized, this);
44974         B.on("regioncollapsed", this.onRegionCollapsed, this);
44975         B.on("regionexpanded", this.onRegionExpanded, this);
44976     },
44977     
44978     storeState : function(){
44979         this.provider.set(this.layout.id+"-layout-state", this.state);
44980     },
44981     
44982     onRegionResized : function(E, F){
44983         this.state[E.getPosition()].size = F;
44984         this.storeState();
44985     },
44986     
44987     onRegionCollapsed : function(G){
44988         this.state[G.getPosition()].collapsed = true;
44989         this.storeState();
44990     },
44991     
44992     onRegionExpanded : function(H){
44993         this.state[H.getPosition()].collapsed = false;
44994         this.storeState();
44995     }
44996 };
44997 /*
44998  * Based on:
44999  * Ext JS Library 1.1.1
45000  * Copyright(c) 2006-2007, Ext JS, LLC.
45001  *
45002  * Originally Released Under LGPL - original licence link has changed is not relivant.
45003  *
45004  * Fork - LGPL
45005  * <script type="text/javascript">
45006  */
45007 /**
45008  * @class Roo.ContentPanel
45009  * @extends Roo.util.Observable
45010  * A basic ContentPanel element.
45011  * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes  (defaults to false)
45012  * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
45013  * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
45014  * @cfg {Boolean} closable True if the panel can be closed/removed
45015  * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45016  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45017  * @cfg {Toolbar} toolbar A toolbar for this panel
45018  * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45019  * @cfg {String} title The title for this panel
45020  * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45021  * @cfg {String} url Calls {@link #setUrl} with this value
45022  * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45023  * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45024  * @constructor
45025  * Create a new ContentPanel.
45026  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45027  * @param {String/Object} config A string to set only the title or a config object
45028  * @param {String} content (optional) Set the HTML content for this panel
45029  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45030  */
45031 Roo.ContentPanel = function(el, A, B){
45032     
45033      
45034     /*
45035     if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45036         config = el;
45037         el = Roo.id();
45038     }
45039     if (config && config.parentLayout) { 
45040         el = config.parentLayout.el.createChild(); 
45041     }
45042     */
45043     if(el.autoCreate){ // xtype is available if this is called from factory
45044         A = el;
45045         el = Roo.id();
45046     }
45047
45048     this.el = Roo.get(el);
45049     if(!this.el && A && A.autoCreate){
45050         if(typeof  A.autoCreate == "object"){
45051             if(!A.autoCreate.id){
45052                 A.autoCreate.id = A.id||el;
45053             }
45054
45055             this.el = Roo.DomHelper.append(document.body,
45056                         A.autoCreate, true);
45057         }else {
45058             this.el = Roo.DomHelper.append(document.body,
45059                         {tag: "div", cls: "x-layout-inactive-content", id: A.id||el}, true);
45060         }
45061     }
45062
45063     this.closable = false;
45064     this.loaded = false;
45065     this.active = false;
45066     if(typeof  A == "string"){
45067         this.title = A;
45068     }else {
45069         Roo.apply(this, A);
45070     }
45071     
45072     if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45073         this.wrapEl = this.el.wrap();    
45074         this.toolbar = new  Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45075         
45076     }
45077     
45078     
45079     
45080     if(this.resizeEl){
45081         this.resizeEl = Roo.get(this.resizeEl, true);
45082     }else {
45083         this.resizeEl = this.el;
45084     }
45085
45086     this.addEvents({
45087         /**
45088          * @event activate
45089          * Fires when this panel is activated. 
45090          * @param {Roo.ContentPanel} this
45091          */
45092         "activate" : true,
45093         /**
45094          * @event deactivate
45095          * Fires when this panel is activated. 
45096          * @param {Roo.ContentPanel} this
45097          */
45098         "deactivate" : true,
45099
45100         /**
45101          * @event resize
45102          * Fires when this panel is resized if fitToFrame is true.
45103          * @param {Roo.ContentPanel} this
45104          * @param {Number} width The width after any component adjustments
45105          * @param {Number} height The height after any component adjustments
45106          */
45107         "resize" : true
45108     });
45109     if(this.autoScroll){
45110         this.resizeEl.setStyle("overflow", "auto");
45111     }
45112
45113     B = B || this.content;
45114     if(B){
45115         this.setContent(B);
45116     }
45117     if(A && A.url){
45118         this.setUrl(this.url, this.params, this.loadOnce);
45119     }
45120
45121     
45122     
45123     
45124     Roo.ContentPanel.superclass.constructor.call(this);
45125 };
45126
45127 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45128     tabTip:'',
45129     setRegion : function(C){
45130         this.region = C;
45131         if(C){
45132            this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45133         }else {
45134            this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45135         } 
45136     },
45137     
45138     /**
45139      * Returns the toolbar for this Panel if one was configured. 
45140      * @return {Roo.Toolbar} 
45141      */
45142     getToolbar : function(){
45143         return  this.toolbar;
45144     },
45145     
45146     setActiveState : function(D){
45147         this.active = D;
45148         if(!D){
45149             this.fireEvent("deactivate", this);
45150         }else {
45151             this.fireEvent("activate", this);
45152         }
45153     },
45154     /**
45155      * Updates this panel's element
45156      * @param {String} content The new content
45157      * @param {Boolean} loadScripts (optional) true to look for and process scripts
45158     */
45159     setContent : function(E, F){
45160         this.el.update(E, F);
45161     },
45162
45163     ignoreResize : function(w, h){
45164         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45165             return  true;
45166         }else {
45167             this.lastSize = {width: w, height: h};
45168             return  false;
45169         }
45170     },
45171     /**
45172      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45173      * @return {Roo.UpdateManager} The UpdateManager
45174      */
45175     getUpdateManager : function(){
45176         return  this.el.getUpdateManager();
45177     },
45178      /**
45179      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45180      * @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:
45181 <pre><code>
45182 panel.load({
45183     url: "your-url.php",
45184     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45185     callback: yourFunction,
45186     scope: yourObject, //(optional scope)
45187     discardUrl: false,
45188     nocache: false,
45189     text: "Loading...",
45190     timeout: 30,
45191     scripts: false
45192 });
45193 </code></pre>
45194      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45195      * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
45196      * @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}
45197      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45198      * @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.
45199      * @return {Roo.ContentPanel} this
45200      */
45201     load : function(){
45202         var  um = this.el.getUpdateManager();
45203         um.update.apply(um, arguments);
45204         return  this;
45205     },
45206
45207
45208     /**
45209      * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
45210      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45211      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
45212      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
45213      * @return {Roo.UpdateManager} The UpdateManager
45214      */
45215     setUrl : function(G, H, I){
45216         if(this.refreshDelegate){
45217             this.removeListener("activate", this.refreshDelegate);
45218         }
45219
45220         this.refreshDelegate = this._handleRefresh.createDelegate(this, [G, H, I]);
45221         this.on("activate", this.refreshDelegate);
45222         return  this.el.getUpdateManager();
45223     },
45224     
45225     _handleRefresh : function(J, K, L){
45226         if(!L || !this.loaded){
45227             var  updater = this.el.getUpdateManager();
45228             updater.update(J, K, this._setLoaded.createDelegate(this));
45229         }
45230     },
45231     
45232     _setLoaded : function(){
45233         this.loaded = true;
45234     }, 
45235     
45236     /**
45237      * Returns this panel's id
45238      * @return {String} 
45239      */
45240     getId : function(){
45241         return  this.el.id;
45242     },
45243     
45244     /** 
45245      * Returns this panel's element - used by regiosn to add.
45246      * @return {Roo.Element} 
45247      */
45248     getEl : function(){
45249         return  this.wrapEl || this.el;
45250     },
45251     
45252     adjustForComponents : function(M, N){
45253         if(this.resizeEl != this.el){
45254             M -= this.el.getFrameWidth('lr');
45255             N -= this.el.getFrameWidth('tb');
45256         }
45257         if(this.toolbar){
45258             var  te = this.toolbar.getEl();
45259             N -= te.getHeight();
45260             te.setWidth(M);
45261         }
45262         if(this.adjustments){
45263             M += this.adjustments[0];
45264             N += this.adjustments[1];
45265         }
45266         return  {"width": M, "height": N};
45267     },
45268     
45269     setSize : function(O, P){
45270         if(this.fitToFrame && !this.ignoreResize(O, P)){
45271             if(this.fitContainer && this.resizeEl != this.el){
45272                 this.el.setSize(O, P);
45273             }
45274             var  size = this.adjustForComponents(O, P);
45275             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45276             this.fireEvent('resize', this, size.width, size.height);
45277         }
45278     },
45279     
45280     /**
45281      * Returns this panel's title
45282      * @return {String} 
45283      */
45284     getTitle : function(){
45285         return  this.title;
45286     },
45287     
45288     /**
45289      * Set this panel's title
45290      * @param {String} title
45291      */
45292     setTitle : function(Q){
45293         this.title = Q;
45294         if(this.region){
45295             this.region.updatePanelTitle(this, Q);
45296         }
45297     },
45298     
45299     /**
45300      * Returns true is this panel was configured to be closable
45301      * @return {Boolean} 
45302      */
45303     isClosable : function(){
45304         return  this.closable;
45305     },
45306     
45307     beforeSlide : function(){
45308         this.el.clip();
45309         this.resizeEl.clip();
45310     },
45311     
45312     afterSlide : function(){
45313         this.el.unclip();
45314         this.resizeEl.unclip();
45315     },
45316     
45317     /**
45318      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
45319      *   Will fail silently if the {@link #setUrl} method has not been called.
45320      *   This does not activate the panel, just updates its content.
45321      */
45322     refresh : function(){
45323         if(this.refreshDelegate){
45324            this.loaded = false;
45325            this.refreshDelegate();
45326         }
45327     },
45328     
45329     /**
45330      * Destroys this panel
45331      */
45332     destroy : function(){
45333         this.el.removeAllListeners();
45334         var  R = document.createElement("span");
45335         R.appendChild(this.el.dom);
45336         R.innerHTML = "";
45337         this.el.remove();
45338         this.el = null;
45339     },
45340     
45341       /**
45342      * Adds a xtype elements to the panel - currently only supports Forms.
45343      * <pre><code>
45344
45345 layout.addxtype({
45346        xtype : 'Form',
45347        items: [ .... ]
45348    }
45349 );
45350
45351 </code></pre>
45352      * @param {Object} cfg Xtype definition of item to add.
45353      */
45354     
45355     addxtype : function(S) {
45356         // add form..
45357         if (!S.xtype.match(/^Form$/)) {
45358             return  false;
45359         }
45360         var  el = this.el.createChild();
45361
45362         this.form = new   Roo.form.Form(S);
45363         
45364         
45365         if ( this.form.allItems.length) this.form.render(el.dom);
45366         return  this.form;
45367         
45368     }
45369 });
45370
45371 /**
45372  * @class Roo.GridPanel
45373  * @extends Roo.ContentPanel
45374  * @constructor
45375  * Create a new GridPanel.
45376  * @param {Roo.grid.Grid} grid The grid for this panel
45377  * @param {String/Object} config A string to set only the panel's title, or a config object
45378  */
45379 Roo.GridPanel = function(T, U){
45380     
45381   
45382     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45383         {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45384         
45385     this.wrapper.dom.appendChild(T.getGridEl().dom);
45386     
45387     Roo.GridPanel.superclass.constructor.call(this, this.wrapper, U);
45388     
45389     if(this.toolbar){
45390         this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45391     }
45392     // xtype created footer. - not sure if will work as we normally have to render first..
45393     if (this.footer && !this.footer.el && this.footer.xtype) {
45394         
45395         this.footer.container = this.grid.getView().getFooterPanel(true);
45396         this.footer.dataSource = this.grid.dataSource;
45397         this.footer = Roo.factory(this.footer, Roo);
45398         
45399     }
45400
45401     
45402     T.monitorWindowResize = false; // turn off autosizing
45403     T.autoHeight = false;
45404     T.autoWidth = false;
45405     this.grid = T;
45406     this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45407 };
45408
45409 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45410     getId : function(){
45411         return  this.grid.id;
45412     },
45413     
45414     /**
45415      * Returns the grid for this panel
45416      * @return {Roo.grid.Grid} 
45417      */
45418     getGrid : function(){
45419         return  this.grid;    
45420     },
45421     
45422     setSize : function(V, W){
45423         if(!this.ignoreResize(V, W)){
45424             var  T = this.grid;
45425             var  size = this.adjustForComponents(V, W);
45426             T.getGridEl().setSize(size.width, size.height);
45427             T.autoSize();
45428         }
45429     },
45430     
45431     beforeSlide : function(){
45432         this.grid.getView().scroller.clip();
45433     },
45434     
45435     afterSlide : function(){
45436         this.grid.getView().scroller.unclip();
45437     },
45438     
45439     destroy : function(){
45440         this.grid.destroy();
45441         delete  this.grid;
45442         Roo.GridPanel.superclass.destroy.call(this); 
45443     }
45444 });
45445
45446
45447 /**
45448  * @class Roo.NestedLayoutPanel
45449  * @extends Roo.ContentPanel
45450  * @constructor
45451  * Create a new NestedLayoutPanel.
45452  * 
45453  * 
45454  * @param {Roo.BorderLayout} layout The layout for this panel
45455  * @param {String/Object} config A string to set only the title or a config object
45456  */
45457 Roo.NestedLayoutPanel = function(X, Y)
45458 {
45459     // construct with only one argument..
45460     /* FIXME - implement nicer consturctors
45461     if (layout.layout) {
45462         config = layout;
45463         layout = config.layout;
45464         delete config.layout;
45465     }
45466     if (layout.xtype && !layout.getEl) {
45467         // then layout needs constructing..
45468         layout = Roo.factory(layout, Roo);
45469     }
45470     */
45471     
45472     Roo.NestedLayoutPanel.superclass.constructor.call(this, X.getEl(), Y);
45473     
45474     X.monitorWindowResize = false; // turn off autosizing
45475     this.layout = X;
45476     this.layout.getEl().addClass("x-layout-nested-layout");
45477     
45478     
45479     
45480 };
45481
45482 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45483
45484     setSize : function(Z, a){
45485         if(!this.ignoreResize(Z, a)){
45486             var  size = this.adjustForComponents(Z, a);
45487             var  el = this.layout.getEl();
45488             el.setSize(size.width, size.height);
45489             var  touch = el.dom.offsetWidth;
45490             this.layout.layout();
45491             // ie requires a double layout on the first pass
45492             if(Roo.isIE && !this.initialized){
45493                 this.initialized = true;
45494                 this.layout.layout();
45495             }
45496         }
45497     },
45498     
45499     // activate all subpanels if not currently active..
45500     
45501     setActiveState : function(b){
45502         this.active = b;
45503         if(!b){
45504             this.fireEvent("deactivate", this);
45505             return;
45506         }
45507
45508         
45509         this.fireEvent("activate", this);
45510         // not sure if this should happen before or after..
45511         if (!this.layout) {
45512             return; // should not happen..
45513         }
45514         var  c = false;
45515         for (var  r  in  this.layout.regions) {
45516             c = this.layout.getRegion(r);
45517             if (c.getActivePanel()) {
45518                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
45519                 c.setActivePanel(c.getActivePanel());
45520                 continue;
45521             }
45522             if (!c.panels.length) {
45523                 continue;
45524             }
45525
45526             c.showPanel(c.getPanel(0));
45527         }
45528         
45529         
45530         
45531         
45532     },
45533     
45534     /**
45535      * Returns the nested BorderLayout for this panel
45536      * @return {Roo.BorderLayout} 
45537      */
45538     getLayout : function(){
45539         return  this.layout;
45540     },
45541     
45542      /**
45543      * Adds a xtype elements to the layout of the nested panel
45544      * <pre><code>
45545
45546 panel.addxtype({
45547        xtype : 'ContentPanel',
45548        region: 'west',
45549        items: [ .... ]
45550    }
45551 );
45552
45553 panel.addxtype({
45554         xtype : 'NestedLayoutPanel',
45555         region: 'west',
45556         layout: {
45557            center: { },
45558            west: { }   
45559         },
45560         items : [ ... list of content panels or nested layout panels.. ]
45561    }
45562 );
45563 </code></pre>
45564      * @param {Object} cfg Xtype definition of item to add.
45565      */
45566     addxtype : function(d) {
45567         return  this.layout.addxtype(d);
45568     
45569     }
45570 });
45571
45572 Roo.ScrollPanel = function(el, e, f){
45573     e = e || {};
45574     e.fitToFrame = true;
45575     Roo.ScrollPanel.superclass.constructor.call(this, el, e, f);
45576     
45577     this.el.dom.style.overflow = "hidden";
45578     var  g = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45579     this.el.removeClass("x-layout-inactive-content");
45580     this.el.on("mousewheel", this.onWheel, this);
45581
45582     var  up = g.createChild({cls: "x-scroller-up", html: "&#160;"}, this.el.dom);
45583     var  i = g.createChild({cls: "x-scroller-down", html: "&#160;"});
45584     up.unselectable(); i.unselectable();
45585     up.on("click", this.scrollUp, this);
45586     i.on("click", this.scrollDown, this);
45587     up.addClassOnOver("x-scroller-btn-over");
45588     i.addClassOnOver("x-scroller-btn-over");
45589     up.addClassOnClick("x-scroller-btn-click");
45590     i.addClassOnClick("x-scroller-btn-click");
45591     this.adjustments = [0, -(up.getHeight() + i.getHeight())];
45592
45593     this.resizeEl = this.el;
45594     this.el = g; this.up = up; this.down = i;
45595 };
45596
45597 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45598     increment : 100,
45599     wheelIncrement : 5,
45600     scrollUp : function(){
45601         this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45602     },
45603
45604     scrollDown : function(){
45605         this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45606     },
45607
45608     afterScroll : function(){
45609         var  el = this.resizeEl;
45610         var  t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45611         this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45612         this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45613     },
45614
45615     setSize : function(){
45616         Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45617         this.afterScroll();
45618     },
45619
45620     onWheel : function(e){
45621         var  d = e.getWheelDelta();
45622         this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45623         this.afterScroll();
45624         e.stopEvent();
45625     },
45626
45627     setContent : function(j, k){
45628         this.resizeEl.update(j, k);
45629     }
45630
45631 });
45632
45633
45634
45635
45636
45637
45638
45639
45640
45641 /**
45642  * @class Roo.TreePanel
45643  * @extends Roo.ContentPanel
45644  * @constructor
45645  * Create a new TreePanel.
45646  * @param {String/Object} config A string to set only the panel's title, or a config object
45647  * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45648  */
45649 Roo.TreePanel = function(l){
45650     var  el = l.el;
45651     var  m = l.tree;
45652     delete  l.tree; 
45653     delete  l.el; // hopefull!
45654     Roo.TreePanel.superclass.constructor.call(this, el, l);
45655     var  n = el.createChild();
45656     this.tree = new  Roo.tree.TreePanel(n , m);
45657     //console.log(tree);
45658     this.on('activate', function()
45659     {
45660         if (this.tree.rendered) {
45661             return;
45662         }
45663
45664         //console.log('render tree');
45665         this.tree.render();
45666     });
45667     
45668     this.on('resize',  function (cp, w, h) {
45669             this.tree.innerCt.setWidth(w);
45670             this.tree.innerCt.setHeight(h);
45671             this.tree.innerCt.setStyle('overflow-y', 'auto');
45672     });
45673
45674         
45675     
45676 };
45677
45678 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
45679
45680
45681
45682
45683
45684
45685
45686
45687
45688
45689
45690
45691 /*
45692  * Based on:
45693  * Ext JS Library 1.1.1
45694  * Copyright(c) 2006-2007, Ext JS, LLC.
45695  *
45696  * Originally Released Under LGPL - original licence link has changed is not relivant.
45697  *
45698  * Fork - LGPL
45699  * <script type="text/javascript">
45700  */
45701  
45702
45703 /**
45704  * @class Roo.ReaderLayout
45705  * @extends Roo.BorderLayout
45706  * This is a pre-built layout that represents a classic, 5-pane application.  It consists of a header, a primary
45707  * center region containing two nested regions (a top one for a list view and one for item preview below),
45708  * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45709  * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45710  * expedites the setup of the overall layout and regions for this common application style.
45711  * Example:
45712  <pre><code>
45713 var reader = new Roo.ReaderLayout();
45714 var CP = Roo.ContentPanel;  // shortcut for adding
45715
45716 reader.beginUpdate();
45717 reader.add("north", new CP("north", "North"));
45718 reader.add("west", new CP("west", {title: "West"}));
45719 reader.add("east", new CP("east", {title: "East"}));
45720
45721 reader.regions.listView.add(new CP("listView", "List"));
45722 reader.regions.preview.add(new CP("preview", "Preview"));
45723 reader.endUpdate();
45724 </code></pre>
45725 * @constructor
45726 * Create a new ReaderLayout
45727 * @param {Object} config Configuration options
45728 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
45729 * document.body if omitted)
45730 */
45731 Roo.ReaderLayout = function(A, B){
45732     var  c = A || {size:{}};
45733     Roo.ReaderLayout.superclass.constructor.call(this, B || document.body, {
45734         north: c.north !== false ? Roo.apply({
45735             split:false,
45736             initialSize: 32,
45737             titlebar: false
45738         }, c.north) : false,
45739         west: c.west !== false ? Roo.apply({
45740             split:true,
45741             initialSize: 200,
45742             minSize: 175,
45743             maxSize: 400,
45744             titlebar: true,
45745             collapsible: true,
45746             animate: true,
45747             margins:{left:5,right:0,bottom:5,top:5},
45748             cmargins:{left:5,right:5,bottom:5,top:5}
45749         }, c.west) : false,
45750         east: c.east !== false ? Roo.apply({
45751             split:true,
45752             initialSize: 200,
45753             minSize: 175,
45754             maxSize: 400,
45755             titlebar: true,
45756             collapsible: true,
45757             animate: true,
45758             margins:{left:0,right:5,bottom:5,top:5},
45759             cmargins:{left:5,right:5,bottom:5,top:5}
45760         }, c.east) : false,
45761         center: Roo.apply({
45762             tabPosition: 'top',
45763             autoScroll:false,
45764             closeOnTab: true,
45765             titlebar:false,
45766             margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
45767         }, c.center)
45768     });
45769
45770     this.el.addClass('x-reader');
45771
45772     this.beginUpdate();
45773
45774     var  C = new  Roo.BorderLayout(Roo.get(document.body).createChild(), {
45775         south: c.preview !== false ? Roo.apply({
45776             split:true,
45777             initialSize: 200,
45778             minSize: 100,
45779             autoScroll:true,
45780             collapsible:true,
45781             titlebar: true,
45782             cmargins:{top:5,left:0, right:0, bottom:0}
45783         }, c.preview) : false,
45784         center: Roo.apply({
45785             autoScroll:false,
45786             titlebar:false,
45787             minHeight:200
45788         }, c.listView)
45789     });
45790     this.add('center', new  Roo.NestedLayoutPanel(C,
45791             Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45792
45793     this.endUpdate();
45794
45795     this.regions.preview = C.getRegion('south');
45796     this.regions.listView = C.getRegion('center');
45797 };
45798
45799 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);
45800 /*
45801  * Based on:
45802  * Ext JS Library 1.1.1
45803  * Copyright(c) 2006-2007, Ext JS, LLC.
45804  *
45805  * Originally Released Under LGPL - original licence link has changed is not relivant.
45806  *
45807  * Fork - LGPL
45808  * <script type="text/javascript">
45809  */
45810  
45811 /**
45812  * @class Roo.grid.Grid
45813  * @extends Roo.util.Observable
45814  * This class represents the primary interface of a component based grid control.
45815  * <br><br>Usage:<pre><code>
45816  var grid = new Roo.grid.Grid("my-container-id", {
45817      ds: myDataStore,
45818      cm: myColModel,
45819      selModel: mySelectionModel,
45820      autoSizeColumns: true,
45821      monitorWindowResize: false,
45822      trackMouseOver: true
45823  });
45824  // set any options
45825  grid.render();
45826  * </code></pre>
45827  * <b>Common Problems:</b><br/>
45828  * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45829  * element will correct this<br/>
45830  * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45831  * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45832  * are unpredictable.<br/>
45833  * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45834  * grid to calculate dimensions/offsets.<br/>
45835   * @constructor
45836  * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45837  * The container MUST have some type of size defined for the grid to fill. The container will be
45838  * automatically set to position relative if it isn't already.
45839  * @param {Object} config A config object that sets properties on this grid.
45840  */
45841 Roo.grid.Grid = function(A, B){
45842         // initialize the container
45843         this.container = Roo.get(A);
45844         this.container.update("");
45845         this.container.setStyle("overflow", "hidden");
45846     this.container.addClass('x-grid-container');
45847
45848     this.id = this.container.id;
45849
45850     Roo.apply(this, B);
45851     // check and correct shorthanded configs
45852     if(this.ds){
45853         this.dataSource = this.ds;
45854         delete  this.ds;
45855     }
45856     if(this.cm){
45857         this.colModel = this.cm;
45858         delete  this.cm;
45859     }
45860     if(this.sm){
45861         this.selModel = this.sm;
45862         delete  this.sm;
45863     }
45864
45865     if (this.selModel) {
45866         this.selModel = Roo.factory(this.selModel, Roo.grid);
45867         this.sm = this.selModel;
45868         this.sm.xmodule = this.xmodule || false;
45869     }
45870     if (typeof(this.colModel.config) == 'undefined') {
45871         this.colModel = new  Roo.grid.ColumnModel(this.colModel);
45872         this.cm = this.colModel;
45873         this.cm.xmodule = this.xmodule || false;
45874     }
45875     if (this.dataSource) {
45876         this.dataSource= Roo.factory(this.dataSource, Roo.data);
45877         this.ds = this.dataSource;
45878         this.ds.xmodule = this.xmodule || false;
45879         
45880     }
45881     
45882     
45883     
45884     if(this.width){
45885         this.container.setWidth(this.width);
45886     }
45887
45888     if(this.height){
45889         this.container.setHeight(this.height);
45890     }
45891
45892     /** @private */
45893         this.addEvents({
45894             // raw events
45895             /**
45896              * @event click
45897              * The raw click event for the entire grid.
45898              * @param {Roo.EventObject} e
45899              */
45900             "click" : true,
45901             /**
45902              * @event dblclick
45903              * The raw dblclick event for the entire grid.
45904              * @param {Roo.EventObject} e
45905              */
45906             "dblclick" : true,
45907             /**
45908              * @event contextmenu
45909              * The raw contextmenu event for the entire grid.
45910              * @param {Roo.EventObject} e
45911              */
45912             "contextmenu" : true,
45913             /**
45914              * @event mousedown
45915              * The raw mousedown event for the entire grid.
45916              * @param {Roo.EventObject} e
45917              */
45918             "mousedown" : true,
45919             /**
45920              * @event mouseup
45921              * The raw mouseup event for the entire grid.
45922              * @param {Roo.EventObject} e
45923              */
45924             "mouseup" : true,
45925             /**
45926              * @event mouseover
45927              * The raw mouseover event for the entire grid.
45928              * @param {Roo.EventObject} e
45929              */
45930             "mouseover" : true,
45931             /**
45932              * @event mouseout
45933              * The raw mouseout event for the entire grid.
45934              * @param {Roo.EventObject} e
45935              */
45936             "mouseout" : true,
45937             /**
45938              * @event keypress
45939              * The raw keypress event for the entire grid.
45940              * @param {Roo.EventObject} e
45941              */
45942             "keypress" : true,
45943             /**
45944              * @event keydown
45945              * The raw keydown event for the entire grid.
45946              * @param {Roo.EventObject} e
45947              */
45948             "keydown" : true,
45949
45950             // custom events
45951
45952             /**
45953              * @event cellclick
45954              * Fires when a cell is clicked
45955              * @param {Grid} this
45956              * @param {Number} rowIndex
45957              * @param {Number} columnIndex
45958              * @param {Roo.EventObject} e
45959              */
45960             "cellclick" : true,
45961             /**
45962              * @event celldblclick
45963              * Fires when a cell is double clicked
45964              * @param {Grid} this
45965              * @param {Number} rowIndex
45966              * @param {Number} columnIndex
45967              * @param {Roo.EventObject} e
45968              */
45969             "celldblclick" : true,
45970             /**
45971              * @event rowclick
45972              * Fires when a row is clicked
45973              * @param {Grid} this
45974              * @param {Number} rowIndex
45975              * @param {Roo.EventObject} e
45976              */
45977             "rowclick" : true,
45978             /**
45979              * @event rowdblclick
45980              * Fires when a row is double clicked
45981              * @param {Grid} this
45982              * @param {Number} rowIndex
45983              * @param {Roo.EventObject} e
45984              */
45985             "rowdblclick" : true,
45986             /**
45987              * @event headerclick
45988              * Fires when a header is clicked
45989              * @param {Grid} this
45990              * @param {Number} columnIndex
45991              * @param {Roo.EventObject} e
45992              */
45993             "headerclick" : true,
45994             /**
45995              * @event headerdblclick
45996              * Fires when a header cell is double clicked
45997              * @param {Grid} this
45998              * @param {Number} columnIndex
45999              * @param {Roo.EventObject} e
46000              */
46001             "headerdblclick" : true,
46002             /**
46003              * @event rowcontextmenu
46004              * Fires when a row is right clicked
46005              * @param {Grid} this
46006              * @param {Number} rowIndex
46007              * @param {Roo.EventObject} e
46008              */
46009             "rowcontextmenu" : true,
46010             /**
46011          * @event cellcontextmenu
46012          * Fires when a cell is right clicked
46013          * @param {Grid} this
46014          * @param {Number} rowIndex
46015          * @param {Number} cellIndex
46016          * @param {Roo.EventObject} e
46017          */
46018          "cellcontextmenu" : true,
46019             /**
46020              * @event headercontextmenu
46021              * Fires when a header is right clicked
46022              * @param {Grid} this
46023              * @param {Number} columnIndex
46024              * @param {Roo.EventObject} e
46025              */
46026             "headercontextmenu" : true,
46027             /**
46028              * @event bodyscroll
46029              * Fires when the body element is scrolled
46030              * @param {Number} scrollLeft
46031              * @param {Number} scrollTop
46032              */
46033             "bodyscroll" : true,
46034             /**
46035              * @event columnresize
46036              * Fires when the user resizes a column
46037              * @param {Number} columnIndex
46038              * @param {Number} newSize
46039              */
46040             "columnresize" : true,
46041             /**
46042              * @event columnmove
46043              * Fires when the user moves a column
46044              * @param {Number} oldIndex
46045              * @param {Number} newIndex
46046              */
46047             "columnmove" : true,
46048             /**
46049              * @event startdrag
46050              * Fires when row(s) start being dragged
46051              * @param {Grid} this
46052              * @param {Roo.GridDD} dd The drag drop object
46053              * @param {event} e The raw browser event
46054              */
46055             "startdrag" : true,
46056             /**
46057              * @event enddrag
46058              * Fires when a drag operation is complete
46059              * @param {Grid} this
46060              * @param {Roo.GridDD} dd The drag drop object
46061              * @param {event} e The raw browser event
46062              */
46063             "enddrag" : true,
46064             /**
46065              * @event dragdrop
46066              * Fires when dragged row(s) are dropped on a valid DD target
46067              * @param {Grid} this
46068              * @param {Roo.GridDD} dd The drag drop object
46069              * @param {String} targetId The target drag drop object
46070              * @param {event} e The raw browser event
46071              */
46072             "dragdrop" : true,
46073             /**
46074              * @event dragover
46075              * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46076              * @param {Grid} this
46077              * @param {Roo.GridDD} dd The drag drop object
46078              * @param {String} targetId The target drag drop object
46079              * @param {event} e The raw browser event
46080              */
46081             "dragover" : true,
46082             /**
46083              * @event dragenter
46084              *  Fires when the dragged row(s) first cross another DD target while being dragged
46085              * @param {Grid} this
46086              * @param {Roo.GridDD} dd The drag drop object
46087              * @param {String} targetId The target drag drop object
46088              * @param {event} e The raw browser event
46089              */
46090             "dragenter" : true,
46091             /**
46092              * @event dragout
46093              * Fires when the dragged row(s) leave another DD target while being dragged
46094              * @param {Grid} this
46095              * @param {Roo.GridDD} dd The drag drop object
46096              * @param {String} targetId The target drag drop object
46097              * @param {event} e The raw browser event
46098              */
46099             "dragout" : true,
46100         /**
46101          * @event render
46102          * Fires when the grid is rendered
46103          * @param {Grid} grid
46104          */
46105         render : true
46106     });
46107
46108     Roo.grid.Grid.superclass.constructor.call(this);
46109 };
46110 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46111     /**
46112      * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46113          */
46114         minColumnWidth : 25,
46115
46116     /**
46117          * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46118          * <b>on initial render.</b> It is more efficient to explicitly size the columns
46119          * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option.  Default is false.
46120          */
46121         autoSizeColumns : false,
46122
46123         /**
46124          * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46125          */
46126         autoSizeHeaders : true,
46127
46128         /**
46129          * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46130          */
46131         monitorWindowResize : true,
46132
46133         /**
46134          * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46135          * rows measured to get a columns size. Default is 0 (all rows).
46136          */
46137         maxRowsToMeasure : 0,
46138
46139         /**
46140          * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46141          */
46142         trackMouseOver : true,
46143
46144         /**
46145          * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46146          */
46147         enableDragDrop : false,
46148
46149         /**
46150          * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46151          */
46152         enableColumnMove : true,
46153
46154         /**
46155          * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46156          */
46157         enableColumnHide : true,
46158
46159         /**
46160          * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46161          */
46162         enableRowHeightSync : false,
46163
46164         /**
46165          * @cfg {Boolean} stripeRows True to stripe the rows.  Default is true.
46166          */
46167         stripeRows : true,
46168
46169         /**
46170          * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46171          */
46172         autoHeight : false,
46173
46174     /**
46175      * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
46176      */
46177     autoExpandColumn : false,
46178
46179     /**
46180     * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46181     * Default is 50.
46182     */
46183     autoExpandMin : 50,
46184
46185     /**
46186     * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46187     */
46188     autoExpandMax : 1000,
46189
46190     /**
46191          * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46192          */
46193         view : null,
46194
46195         /**
46196      * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46197          */
46198         loadMask : false,
46199
46200     // private
46201     rendered : false,
46202
46203     /**
46204     * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46205     * of a fixed width. Default is false.
46206     */
46207     /**
46208     * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46209     */
46210     /**
46211      * Called once after all setup has been completed and the grid is ready to be rendered.
46212      * @return {Roo.grid.Grid} this
46213      */
46214     render : function(){
46215         var  c = this.container;
46216         // try to detect autoHeight/width mode
46217         if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46218             this.autoHeight = true;
46219         }
46220         var  C = this.getView();
46221         C.init(this);
46222
46223         c.on("click", this.onClick, this);
46224         c.on("dblclick", this.onDblClick, this);
46225         c.on("contextmenu", this.onContextMenu, this);
46226         c.on("keydown", this.onKeyDown, this);
46227
46228         this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46229
46230         this.getSelectionModel().init(this);
46231
46232         C.render();
46233
46234         if(this.loadMask){
46235             this.loadMask = new  Roo.LoadMask(this.container,
46236                     Roo.apply({store:this.dataSource}, this.loadMask));
46237         }
46238         
46239         
46240         if (this.toolbar && this.toolbar.xtype) {
46241             this.toolbar.container = this.getView().getHeaderPanel(true);
46242             this.toolbar = new  Ext.Toolbar(this.toolbar);
46243         }
46244         if (this.footer && this.footer.xtype) {
46245             this.footer.dataSource = this.getDataSource();
46246             this.footer.container = this.getView().getFooterPanel(true);
46247             this.footer = Roo.factory(this.footer, Roo);
46248         }
46249
46250         this.rendered = true;
46251         this.fireEvent('render', this);
46252         return  this;
46253     },
46254
46255         /**
46256          * Reconfigures the grid to use a different Store and Column Model.
46257          * The View will be bound to the new objects and refreshed.
46258          * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46259          * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46260          */
46261     reconfigure : function(D, E){
46262         if(this.loadMask){
46263             this.loadMask.destroy();
46264             this.loadMask = new  Roo.LoadMask(this.container,
46265                     Roo.apply({store:D}, this.loadMask));
46266         }
46267
46268         this.view.bind(D, E);
46269         this.dataSource = D;
46270         this.colModel = E;
46271         this.view.refresh(true);
46272     },
46273
46274     // private
46275     onKeyDown : function(e){
46276         this.fireEvent("keydown", e);
46277     },
46278
46279     /**
46280      * Destroy this grid.
46281      * @param {Boolean} removeEl True to remove the element
46282      */
46283     destroy : function(F, G){
46284         if(this.loadMask){
46285             this.loadMask.destroy();
46286         }
46287         var  c = this.container;
46288         c.removeAllListeners();
46289         this.view.destroy();
46290         this.colModel.purgeListeners();
46291         if(!G){
46292             this.purgeListeners();
46293         }
46294
46295         c.update("");
46296         if(F === true){
46297             c.remove();
46298         }
46299     },
46300
46301     // private
46302     processEvent : function(H, e){
46303         this.fireEvent(H, e);
46304         var  t = e.getTarget();
46305         var  v = this.view;
46306         var  I = v.findHeaderIndex(t);
46307         if(I !== false){
46308             this.fireEvent("header" + H, this, I, e);
46309         }else {
46310             var  row = v.findRowIndex(t);
46311             var  cell = v.findCellIndex(t);
46312             if(row !== false){
46313                 this.fireEvent("row" + H, this, row, e);
46314                 if(cell !== false){
46315                     this.fireEvent("cell" + H, this, row, cell, e);
46316                 }
46317             }
46318         }
46319     },
46320
46321     // private
46322     onClick : function(e){
46323         this.processEvent("click", e);
46324     },
46325
46326     // private
46327     onContextMenu : function(e, t){
46328         this.processEvent("contextmenu", e);
46329     },
46330
46331     // private
46332     onDblClick : function(e){
46333         this.processEvent("dblclick", e);
46334     },
46335
46336     // private
46337     walkCells : function(J, K, L, fn, M){
46338         var  cm = this.colModel, N = cm.getColumnCount();
46339         var  ds = this.dataSource, O = ds.getCount(), P = true;
46340         if(L < 0){
46341             if(K < 0){
46342                 J--;
46343                 P = false;
46344             }
46345             while(J >= 0){
46346                 if(!P){
46347                     K = N-1;
46348                 }
46349
46350                 P = false;
46351                 while(K >= 0){
46352                     if(fn.call(M || this, J, K, cm) === true){
46353                         return  [J, K];
46354                     }
46355
46356                     K--;
46357                 }
46358
46359                 J--;
46360             }
46361         } else  {
46362             if(K >= N){
46363                 J++;
46364                 P = false;
46365             }
46366             while(J < O){
46367                 if(!P){
46368                     K = 0;
46369                 }
46370
46371                 P = false;
46372                 while(K < N){
46373                     if(fn.call(M || this, J, K, cm) === true){
46374                         return  [J, K];
46375                     }
46376
46377                     K++;
46378                 }
46379
46380                 J++;
46381             }
46382         }
46383         return  null;
46384     },
46385
46386     // private
46387     getSelections : function(){
46388         return  this.selModel.getSelections();
46389     },
46390
46391     /**
46392      * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46393      * but if manual update is required this method will initiate it.
46394      */
46395     autoSize : function(){
46396         if(this.rendered){
46397             this.view.layout();
46398             if(this.view.adjustForScroll){
46399                 this.view.adjustForScroll();
46400             }
46401         }
46402     },
46403
46404     /**
46405      * Returns the grid's underlying element.
46406      * @return {Element} The element
46407      */
46408     getGridEl : function(){
46409         return  this.container;
46410     },
46411
46412     // private for compatibility, overridden by editor grid
46413     stopEditing : function(){},
46414
46415     /**
46416      * Returns the grid's SelectionModel.
46417      * @return {SelectionModel}
46418      */
46419     getSelectionModel : function(){
46420         if(!this.selModel){
46421             this.selModel = new  Roo.grid.RowSelectionModel();
46422         }
46423         return  this.selModel;
46424     },
46425
46426     /**
46427      * Returns the grid's DataSource.
46428      * @return {DataSource}
46429      */
46430     getDataSource : function(){
46431         return  this.dataSource;
46432     },
46433
46434     /**
46435      * Returns the grid's ColumnModel.
46436      * @return {ColumnModel}
46437      */
46438     getColumnModel : function(){
46439         return  this.colModel;
46440     },
46441
46442     /**
46443      * Returns the grid's GridView object.
46444      * @return {GridView}
46445      */
46446     getView : function(){
46447         if(!this.view){
46448             this.view = new  Roo.grid.GridView(this.viewConfig);
46449         }
46450         return  this.view;
46451     },
46452     /**
46453      * Called to get grid's drag proxy text, by default returns this.ddText.
46454      * @return {String}
46455      */
46456     getDragDropText : function(){
46457         var  Q = this.selModel.getCount();
46458         return  String.format(this.ddText, Q, Q == 1 ? '' : 's');
46459     }
46460 });
46461 /**
46462  * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46463  * %0 is replaced with the number of selected rows.
46464  * @type String
46465  */
46466 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";
46467 /*
46468  * Based on:
46469  * Ext JS Library 1.1.1
46470  * Copyright(c) 2006-2007, Ext JS, LLC.
46471  *
46472  * Originally Released Under LGPL - original licence link has changed is not relivant.
46473  *
46474  * Fork - LGPL
46475  * <script type="text/javascript">
46476  */
46477  
46478 Roo.grid.AbstractGridView = function(){
46479         this.grid = null;
46480         
46481         this.events = {
46482             "beforerowremoved" : true,
46483             "beforerowsinserted" : true,
46484             "beforerefresh" : true,
46485             "rowremoved" : true,
46486             "rowsinserted" : true,
46487             "rowupdated" : true,
46488             "refresh" : true
46489         };
46490     Roo.grid.AbstractGridView.superclass.constructor.call(this);
46491 };
46492
46493 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46494     rowClass : "x-grid-row",
46495     cellClass : "x-grid-cell",
46496     tdClass : "x-grid-td",
46497     hdClass : "x-grid-hd",
46498     splitClass : "x-grid-hd-split",
46499     
46500         init: function(A){
46501         this.grid = A;
46502                 var  B = this.grid.getGridEl().id;
46503         this.colSelector = "#" + B + " ." + this.cellClass + "-";
46504         this.tdSelector = "#" + B + " ." + this.tdClass + "-";
46505         this.hdSelector = "#" + B + " ." + this.hdClass + "-";
46506         this.splitSelector = "#" + B + " ." + this.splitClass + "-";
46507         },
46508         
46509         getColumnRenderers : function(){
46510         var  C = [];
46511         var  cm = this.grid.colModel;
46512         var  D = cm.getColumnCount();
46513         for(var  i = 0; i < D; i++){
46514             C[i] = cm.getRenderer(i);
46515         }
46516         return  C;
46517     },
46518     
46519     getColumnIds : function(){
46520         var  E = [];
46521         var  cm = this.grid.colModel;
46522         var  F = cm.getColumnCount();
46523         for(var  i = 0; i < F; i++){
46524             E[i] = cm.getColumnId(i);
46525         }
46526         return  E;
46527     },
46528     
46529     getDataIndexes : function(){
46530         if(!this.indexMap){
46531             this.indexMap = this.buildIndexMap();
46532         }
46533         return  this.indexMap.colToData;
46534     },
46535     
46536     getColumnIndexByDataIndex : function(G){
46537         if(!this.indexMap){
46538             this.indexMap = this.buildIndexMap();
46539         }
46540         return  this.indexMap.dataToCol[G];
46541     },
46542     
46543     /**
46544      * Set a css style for a column dynamically. 
46545      * @param {Number} colIndex The index of the column
46546      * @param {String} name The css property name
46547      * @param {String} value The css value
46548      */
46549     setCSSStyle : function(H, I, J){
46550         var  K = "#" + this.grid.id + " .x-grid-col-" + H;
46551         Roo.util.CSS.updateRule(K, I, J);
46552     },
46553     
46554     generateRules : function(cm){
46555         var  L = [], M = this.grid.id + '-cssrules';
46556         Roo.util.CSS.removeStyleSheet(M);
46557         for(var  i = 0, len = cm.getColumnCount(); i < len; i++){
46558             var  B = cm.getColumnId(i);
46559             L.push(this.colSelector, B, " {\n", cm.config[i].css, "}\n",
46560                          this.tdSelector, B, " {\n}\n",
46561                          this.hdSelector, B, " {\n}\n",
46562                          this.splitSelector, B, " {\n}\n");
46563         }
46564         return  Roo.util.CSS.createStyleSheet(L.join(""), M);
46565     }
46566 });
46567 /*
46568  * Based on:
46569  * Ext JS Library 1.1.1
46570  * Copyright(c) 2006-2007, Ext JS, LLC.
46571  *
46572  * Originally Released Under LGPL - original licence link has changed is not relivant.
46573  *
46574  * Fork - LGPL
46575  * <script type="text/javascript">
46576  */
46577
46578 // private
46579 // This is a support class used internally by the Grid components
46580 Roo.grid.HeaderDragZone = function(A, hd, B){
46581     this.grid = A;
46582     this.view = A.getView();
46583     this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46584     Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46585     if(B){
46586         this.setHandleElId(Roo.id(hd));
46587         this.setOuterHandleElId(Roo.id(B));
46588     }
46589
46590     this.scroll = false;
46591 };
46592 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46593     maxDragWidth: 120,
46594     getDragData : function(e){
46595         var  t = Roo.lib.Event.getTarget(e);
46596         var  h = this.view.findHeaderCell(t);
46597         if(h){
46598             return  {ddel: h.firstChild, header:h};
46599         }
46600         return  false;
46601     },
46602
46603     onInitDrag : function(e){
46604         this.view.headersDisabled = true;
46605         var  C = this.dragData.ddel.cloneNode(true);
46606         C.id = Roo.id();
46607         C.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46608         this.proxy.update(C);
46609         return  true;
46610     },
46611
46612     afterValidDrop : function(){
46613         var  v = this.view;
46614         setTimeout(function(){
46615             v.headersDisabled = false;
46616         }, 50);
46617     },
46618
46619     afterInvalidDrop : function(){
46620         var  v = this.view;
46621         setTimeout(function(){
46622             v.headersDisabled = false;
46623         }, 50);
46624     }
46625 });
46626
46627 /*
46628  * Based on:
46629  * Ext JS Library 1.1.1
46630  * Copyright(c) 2006-2007, Ext JS, LLC.
46631  *
46632  * Originally Released Under LGPL - original licence link has changed is not relivant.
46633  *
46634  * Fork - LGPL
46635  * <script type="text/javascript">
46636  */
46637 // private
46638 // This is a support class used internally by the Grid components
46639 Roo.grid.HeaderDropZone = function(A, hd, B){
46640     this.grid = A;
46641     this.view = A.getView();
46642     // split the proxies so they don't interfere with mouse events
46643     this.proxyTop = Roo.DomHelper.append(document.body, {
46644         cls:"col-move-top", html:"&#160;"
46645     }, true);
46646     this.proxyBottom = Roo.DomHelper.append(document.body, {
46647         cls:"col-move-bottom", html:"&#160;"
46648     }, true);
46649     this.proxyTop.hide = this.proxyBottom.hide = function(){
46650         this.setLeftTop(-100,-100);
46651         this.setStyle("visibility", "hidden");
46652     };
46653     this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46654     // temporarily disabled
46655     //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46656     Roo.grid.HeaderDropZone.superclass.constructor.call(this, A.getGridEl().dom);
46657 };
46658 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46659     proxyOffsets : [-4, -9],
46660     fly: Roo.Element.fly,
46661
46662     getTargetFromEvent : function(e){
46663         var  t = Roo.lib.Event.getTarget(e);
46664         var  C = this.view.findCellIndex(t);
46665         if(C !== false){
46666             return  this.view.getHeaderCell(C);
46667         }
46668     },
46669
46670     nextVisible : function(h){
46671         var  v = this.view, cm = this.grid.colModel;
46672         h = h.nextSibling;
46673         while(h){
46674             if(!cm.isHidden(v.getCellIndex(h))){
46675                 return  h;
46676             }
46677
46678             h = h.nextSibling;
46679         }
46680         return  null;
46681     },
46682
46683     prevVisible : function(h){
46684         var  v = this.view, cm = this.grid.colModel;
46685         h = h.prevSibling;
46686         while(h){
46687             if(!cm.isHidden(v.getCellIndex(h))){
46688                 return  h;
46689             }
46690
46691             h = h.prevSibling;
46692         }
46693         return  null;
46694     },
46695
46696     positionIndicator : function(h, n, e){
46697         var  x = Roo.lib.Event.getPageX(e);
46698         var  r = Roo.lib.Dom.getRegion(n.firstChild);
46699         var  px, pt, py = r.top + this.proxyOffsets[1];
46700         if((r.right - x) <= (r.right-r.left)/2){
46701             px = r.right+this.view.borderWidth;
46702             pt = "after";
46703         }else {
46704             px = r.left;
46705             pt = "before";
46706         }
46707         var  D = this.view.getCellIndex(h);
46708         var  E = this.view.getCellIndex(n);
46709
46710         if(this.grid.colModel.isFixed(E)){
46711             return  false;
46712         }
46713
46714         var  F = this.grid.colModel.isLocked(E);
46715
46716         if(pt == "after"){
46717             E++;
46718         }
46719         if(D < E){
46720             E--;
46721         }
46722         if(D == E && (F == this.grid.colModel.isLocked(D))){
46723             return  false;
46724         }
46725
46726         px +=  this.proxyOffsets[0];
46727         this.proxyTop.setLeftTop(px, py);
46728         this.proxyTop.show();
46729         if(!this.bottomOffset){
46730             this.bottomOffset = this.view.mainHd.getHeight();
46731         }
46732
46733         this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
46734         this.proxyBottom.show();
46735         return  pt;
46736     },
46737
46738     onNodeEnter : function(n, dd, e, G){
46739         if(G.header != n){
46740             this.positionIndicator(G.header, n, e);
46741         }
46742     },
46743
46744     onNodeOver : function(n, dd, e, H){
46745         var  I = false;
46746         if(H.header != n){
46747             I = this.positionIndicator(H.header, n, e);
46748         }
46749         if(!I){
46750             this.proxyTop.hide();
46751             this.proxyBottom.hide();
46752         }
46753         return  I ? this.dropAllowed : this.dropNotAllowed;
46754     },
46755
46756     onNodeOut : function(n, dd, e, J){
46757         this.proxyTop.hide();
46758         this.proxyBottom.hide();
46759     },
46760
46761     onNodeDrop : function(n, dd, e, K){
46762         var  h = K.header;
46763         if(h != n){
46764             var  cm = this.grid.colModel;
46765             var  x = Roo.lib.Event.getPageX(e);
46766             var  r = Roo.lib.Dom.getRegion(n.firstChild);
46767             var  pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
46768             var  D = this.view.getCellIndex(h);
46769             var  E = this.view.getCellIndex(n);
46770             var  F = cm.isLocked(E);
46771             if(pt == "after"){
46772                 E++;
46773             }
46774             if(D < E){
46775                 E--;
46776             }
46777             if(D == E && (F == cm.isLocked(D))){
46778                 return  false;
46779             }
46780
46781             cm.setLocked(D, F, true);
46782             cm.moveColumn(D, E);
46783             this.grid.fireEvent("columnmove", D, E);
46784             return  true;
46785         }
46786         return  false;
46787     }
46788 });
46789
46790 /*
46791  * Based on:
46792  * Ext JS Library 1.1.1
46793  * Copyright(c) 2006-2007, Ext JS, LLC.
46794  *
46795  * Originally Released Under LGPL - original licence link has changed is not relivant.
46796  *
46797  * Fork - LGPL
46798  * <script type="text/javascript">
46799  */
46800   
46801 /**
46802  * @class Roo.grid.GridView
46803  * @extends Roo.util.Observable
46804  *
46805  * @constructor
46806  * @param {Object} config
46807  */
46808 Roo.grid.GridView = function(A){
46809     Roo.grid.GridView.superclass.constructor.call(this);
46810     this.el = null;
46811
46812     Roo.apply(this, A);
46813 };
46814
46815 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46816
46817     /**
46818      * Override this function to apply custom css classes to rows during rendering
46819      * @param {Record} record The record
46820      * @param {Number} index
46821      * @method getRowClass
46822      */
46823     rowClass : "x-grid-row",
46824
46825     cellClass : "x-grid-col",
46826
46827     tdClass : "x-grid-td",
46828
46829     hdClass : "x-grid-hd",
46830
46831     splitClass : "x-grid-split",
46832
46833     sortClasses : ["sort-asc", "sort-desc"],
46834
46835     enableMoveAnim : false,
46836
46837     hlColor: "C3DAF9",
46838
46839     dh : Roo.DomHelper,
46840
46841     fly : Roo.Element.fly,
46842
46843     css : Roo.util.CSS,
46844
46845     borderWidth: 1,
46846
46847     splitOffset: 3,
46848
46849     scrollIncrement : 22,
46850
46851     cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46852
46853     findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46854
46855     bind : function(ds, cm){
46856         if(this.ds){
46857             this.ds.un("load", this.onLoad, this);
46858             this.ds.un("datachanged", this.onDataChange, this);
46859             this.ds.un("add", this.onAdd, this);
46860             this.ds.un("remove", this.onRemove, this);
46861             this.ds.un("update", this.onUpdate, this);
46862             this.ds.un("clear", this.onClear, this);
46863         }
46864         if(ds){
46865             ds.on("load", this.onLoad, this);
46866             ds.on("datachanged", this.onDataChange, this);
46867             ds.on("add", this.onAdd, this);
46868             ds.on("remove", this.onRemove, this);
46869             ds.on("update", this.onUpdate, this);
46870             ds.on("clear", this.onClear, this);
46871         }
46872
46873         this.ds = ds;
46874
46875         if(this.cm){
46876             this.cm.un("widthchange", this.onColWidthChange, this);
46877             this.cm.un("headerchange", this.onHeaderChange, this);
46878             this.cm.un("hiddenchange", this.onHiddenChange, this);
46879             this.cm.un("columnmoved", this.onColumnMove, this);
46880             this.cm.un("columnlockchange", this.onColumnLock, this);
46881         }
46882         if(cm){
46883             this.generateRules(cm);
46884             cm.on("widthchange", this.onColWidthChange, this);
46885             cm.on("headerchange", this.onHeaderChange, this);
46886             cm.on("hiddenchange", this.onHiddenChange, this);
46887             cm.on("columnmoved", this.onColumnMove, this);
46888             cm.on("columnlockchange", this.onColumnLock, this);
46889         }
46890
46891         this.cm = cm;
46892     },
46893
46894     init: function(B){
46895                 Roo.grid.GridView.superclass.init.call(this, B);
46896
46897                 this.bind(B.dataSource, B.colModel);
46898
46899             B.on("headerclick", this.handleHeaderClick, this);
46900
46901         if(B.trackMouseOver){
46902             B.on("mouseover", this.onRowOver, this);
46903                 B.on("mouseout", this.onRowOut, this);
46904             }
46905
46906             B.cancelTextSelection = function(){};
46907                 this.gridId = B.id;
46908
46909                 var  C = this.templates || {};
46910
46911                 if(!C.master){
46912                     C.master = new  Roo.Template(
46913                        '<div class="x-grid" hidefocus="true">',
46914                           '<div class="x-grid-topbar"></div>',
46915                           '<div class="x-grid-scroller"><div></div></div>',
46916                           '<div class="x-grid-locked">',
46917                               '<div class="x-grid-header">{lockedHeader}</div>',
46918                               '<div class="x-grid-body">{lockedBody}</div>',
46919                           "</div>",
46920                           '<div class="x-grid-viewport">',
46921                               '<div class="x-grid-header">{header}</div>',
46922                               '<div class="x-grid-body">{body}</div>',
46923                           "</div>",
46924                           '<div class="x-grid-bottombar"></div>',
46925                           '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46926                           '<div class="x-grid-resize-proxy">&#160;</div>',
46927                        "</div>"
46928                     );
46929                     C.master.disableformats = true;
46930                 }
46931
46932                 if(!C.header){
46933                     C.header = new  Roo.Template(
46934                        '<table border="0" cellspacing="0" cellpadding="0">',
46935                        '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46936                        "</table>{splits}"
46937                     );
46938                     C.header.disableformats = true;
46939                 }
46940
46941                 C.header.compile();
46942
46943                 if(!C.hcell){
46944                     C.hcell = new  Roo.Template(
46945                         '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46946                         '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46947                         "</div></td>"
46948                      );
46949                      C.hcell.disableFormats = true;
46950                 }
46951
46952                 C.hcell.compile();
46953
46954                 if(!C.hsplit){
46955                     C.hsplit = new  Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on">&#160;</div>');
46956                     C.hsplit.disableFormats = true;
46957                 }
46958
46959                 C.hsplit.compile();
46960
46961                 if(!C.body){
46962                     C.body = new  Roo.Template(
46963                        '<table border="0" cellspacing="0" cellpadding="0">',
46964                        "<tbody>{rows}</tbody>",
46965                        "</table>"
46966                     );
46967                     C.body.disableFormats = true;
46968                 }
46969
46970                 C.body.compile();
46971
46972                 if(!C.row){
46973                     C.row = new  Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46974                     C.row.disableFormats = true;
46975                 }
46976
46977                 C.row.compile();
46978
46979                 if(!C.cell){
46980                     C.cell = new  Roo.Template(
46981                         '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46982                         '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46983                         "</td>"
46984                     );
46985             C.cell.disableFormats = true;
46986         }
46987
46988                 C.cell.compile();
46989
46990                 this.templates = C;
46991         },
46992
46993         // remap these for backwards compat
46994     onColWidthChange : function(){
46995         this.updateColumns.apply(this, arguments);
46996     },
46997     onHeaderChange : function(){
46998         this.updateHeaders.apply(this, arguments);
46999     }, 
47000     onHiddenChange : function(){
47001         this.handleHiddenChange.apply(this, arguments);
47002     },
47003     onColumnMove : function(){
47004         this.handleColumnMove.apply(this, arguments);
47005     },
47006     onColumnLock : function(){
47007         this.handleLockChange.apply(this, arguments);
47008     },
47009
47010     onDataChange : function(){
47011         this.refresh();
47012         this.updateHeaderSortState();
47013     },
47014
47015         onClear : function(){
47016         this.refresh();
47017     },
47018
47019         onUpdate : function(ds, D){
47020         this.refreshRow(D);
47021     },
47022
47023     refreshRow : function(E){
47024         var  ds = this.ds, F;
47025         if(typeof  E == 'number'){
47026             F = E;
47027             E = ds.getAt(F);
47028         }else {
47029             F = ds.indexOf(E);
47030         }
47031
47032         this.insertRows(ds, F, F, true);
47033         this.onRemove(ds, E, F+1, true);
47034         this.syncRowHeights(F, F);
47035         this.layout();
47036         this.fireEvent("rowupdated", this, F, E);
47037     },
47038
47039     onAdd : function(ds, G, H){
47040         this.insertRows(ds, H, H + (G.length-1));
47041     },
47042
47043     onRemove : function(ds, I, J, K){
47044         if(K !== true){
47045             this.fireEvent("beforerowremoved", this, J, I);
47046         }
47047         var  bt = this.getBodyTable(), lt = this.getLockedTable();
47048         if(bt.rows[J]){
47049             bt.firstChild.removeChild(bt.rows[J]);
47050         }
47051         if(lt.rows[J]){
47052             lt.firstChild.removeChild(lt.rows[J]);
47053         }
47054         if(K !== true){
47055             this.stripeRows(J);
47056             this.syncRowHeights(J, J);
47057             this.layout();
47058             this.fireEvent("rowremoved", this, J, I);
47059         }
47060     },
47061
47062     onLoad : function(){
47063         this.scrollToTop();
47064     },
47065
47066     /**
47067      * Scrolls the grid to the top
47068      */
47069     scrollToTop : function(){
47070         if(this.scroller){
47071             this.scroller.dom.scrollTop = 0;
47072             this.syncScroll();
47073         }
47074     },
47075
47076     /**
47077      * Gets a panel in the header of the grid that can be used for toolbars etc.
47078      * After modifying the contents of this panel a call to grid.autoSize() may be
47079      * required to register any changes in size.
47080      * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47081      * @return Roo.Element
47082      */
47083     getHeaderPanel : function(L){
47084         if(L){
47085             this.headerPanel.show();
47086         }
47087         return  this.headerPanel;
47088         },
47089
47090         /**
47091      * Gets a panel in the footer of the grid that can be used for toolbars etc.
47092      * After modifying the contents of this panel a call to grid.autoSize() may be
47093      * required to register any changes in size.
47094      * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47095      * @return Roo.Element
47096      */
47097     getFooterPanel : function(M){
47098         if(M){
47099             this.footerPanel.show();
47100         }
47101         return  this.footerPanel;
47102         },
47103
47104         initElements : function(){
47105             var  E = Roo.Element;
47106             var  el = this.grid.getGridEl().dom.firstChild;
47107             var  cs = el.childNodes;
47108
47109             this.el = new  E(el);
47110             this.headerPanel = new  E(el.firstChild);
47111             this.headerPanel.enableDisplayMode("block");
47112
47113         this.scroller = new  E(cs[1]);
47114             this.scrollSizer = new  E(this.scroller.dom.firstChild);
47115
47116             this.lockedWrap = new  E(cs[2]);
47117             this.lockedHd = new  E(this.lockedWrap.dom.firstChild);
47118             this.lockedBody = new  E(this.lockedWrap.dom.childNodes[1]);
47119
47120             this.mainWrap = new  E(cs[3]);
47121             this.mainHd = new  E(this.mainWrap.dom.firstChild);
47122             this.mainBody = new  E(this.mainWrap.dom.childNodes[1]);
47123
47124             this.footerPanel = new  E(cs[4]);
47125             this.footerPanel.enableDisplayMode("block");
47126
47127         this.focusEl = new  E(cs[5]);
47128         this.focusEl.swallowEvent("click", true);
47129         this.resizeProxy = new  E(cs[6]);
47130
47131             this.headerSelector = String.format(
47132                '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47133                this.lockedHd.id, this.mainHd.id
47134             );
47135
47136             this.splitterSelector = String.format(
47137                '#{0} div.x-grid-split, #{1} div.x-grid-split',
47138                this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47139             );
47140     },
47141     idToCssName : function(s)
47142     {
47143         return  s.replace(/[^a-z0-9]+/ig, '-');
47144     },
47145
47146         getHeaderCell : function(N){
47147             return  Roo.DomQuery.select(this.headerSelector)[N];
47148         },
47149
47150         getHeaderCellMeasure : function(O){
47151             return  this.getHeaderCell(O).firstChild;
47152         },
47153
47154         getHeaderCellText : function(P){
47155             return  this.getHeaderCell(P).firstChild.firstChild;
47156         },
47157
47158         getLockedTable : function(){
47159             return  this.lockedBody.dom.firstChild;
47160         },
47161
47162         getBodyTable : function(){
47163             return  this.mainBody.dom.firstChild;
47164         },
47165
47166         getLockedRow : function(Q){
47167             return  this.getLockedTable().rows[Q];
47168         },
47169
47170         getRow : function(R){
47171             return  this.getBodyTable().rows[R];
47172         },
47173
47174         getRowComposite : function(S){
47175             if(!this.rowEl){
47176                 this.rowEl = new  Roo.CompositeElementLite();
47177             }
47178         var  T = [], U, V;
47179         if(U = this.getLockedRow(S)){
47180             T.push(U);
47181         }
47182         if(V = this.getRow(S)){
47183             T.push(V);
47184         }
47185
47186         this.rowEl.elements = T;
47187             return  this.rowEl;
47188         },
47189
47190         getCell : function(W, X){
47191             var  Y = this.cm.getLockedCount();
47192             var  Z;
47193             if(X < Y){
47194                 Z = this.lockedBody.dom.firstChild;
47195             }else {
47196                 Z = this.mainBody.dom.firstChild;
47197                 X -= Y;
47198             }
47199         return  Z.rows[W].childNodes[X];
47200         },
47201
47202         getCellText : function(a, b){
47203             return  this.getCell(a, b).firstChild.firstChild;
47204         },
47205
47206         getCellBox : function(c){
47207             var  b = this.fly(c).getBox();
47208         if(Roo.isOpera){ // opera fails to report the Y
47209             b.y = c.offsetTop + this.mainBody.getY();
47210         }
47211         return  b;
47212     },
47213
47214     getCellIndex : function(d){
47215         var  id = String(d.className).match(this.cellRE);
47216         if(id){
47217             return  parseInt(id[1], 10);
47218         }
47219         return  0;
47220     },
47221
47222     findHeaderIndex : function(n){
47223         var  r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47224         return  r ? this.getCellIndex(r) : false;
47225     },
47226
47227     findHeaderCell : function(n){
47228         var  r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47229         return  r ? r : false;
47230     },
47231
47232     findRowIndex : function(n){
47233         if(!n){
47234             return  false;
47235         }
47236         var  r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47237         return  r ? r.rowIndex : false;
47238     },
47239
47240     findCellIndex : function(e){
47241         var  f = this.el.dom;
47242         while(e && e != f){
47243             if(this.findRE.test(e.className)){
47244                 return  this.getCellIndex(e);
47245             }
47246
47247             e = e.parentNode;
47248         }
47249         return  false;
47250     },
47251
47252     getColumnId : function(g){
47253             return  this.cm.getColumnId(g);
47254         },
47255
47256         getSplitters : function(){
47257             if(this.splitterSelector){
47258                return  Roo.DomQuery.select(this.splitterSelector);
47259             }else {
47260                 return  null;
47261             }
47262         },
47263
47264         getSplitter : function(k){
47265             return  this.getSplitters()[k];
47266         },
47267
47268     onRowOver : function(e, t){
47269         var  o;
47270         if((o = this.findRowIndex(t)) !== false){
47271             this.getRowComposite(o).addClass("x-grid-row-over");
47272         }
47273     },
47274
47275     onRowOut : function(e, t){
47276         var  p;
47277         if((p = this.findRowIndex(t)) !== false && p !== this.findRowIndex(e.getRelatedTarget())){
47278             this.getRowComposite(p).removeClass("x-grid-row-over");
47279         }
47280     },
47281
47282     renderHeaders : function(){
47283             var  cm = this.cm;
47284         var  ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47285         var  cb = [], lb = [], sb = [], q = [], p = {};
47286         for(var  i = 0, len = cm.getColumnCount(); i < len; i++){
47287             p.cellId = "x-grid-hd-0-" + i;
47288             p.splitId = "x-grid-csplit-0-" + i;
47289             p.id = cm.getColumnId(i);
47290             p.title = cm.getColumnTooltip(i) || "";
47291             p.value = cm.getColumnHeader(i) || "";
47292             p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47293             if(!cm.isLocked(i)){
47294                 cb[cb.length] = ct.apply(p);
47295                 sb[sb.length] = st.apply(p);
47296             }else {
47297                 lb[lb.length] = ct.apply(p);
47298                 q[q.length] = st.apply(p);
47299             }
47300         }
47301         return  [ht.apply({cells: lb.join(""), splits:q.join("")}),
47302                 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47303         },
47304
47305         updateHeaders : function(){
47306         var  u = this.renderHeaders();
47307         this.lockedHd.update(u[0]);
47308         this.mainHd.update(u[1]);
47309     },
47310
47311     /**
47312      * Focuses the specified row.
47313      * @param {Number} row The row index
47314      */
47315     focusRow : function(v){
47316         var  x = this.scroller.dom.scrollLeft;
47317         this.focusCell(v, 0, false);
47318         this.scroller.dom.scrollLeft = x;
47319     },
47320
47321     /**
47322      * Focuses the specified cell.
47323      * @param {Number} row The row index
47324      * @param {Number} col The column index
47325      * @param {Boolean} hscroll false to disable horizontal scrolling
47326      */
47327     focusCell : function(y, z, AA){
47328         var  el = this.ensureVisible(y, z, AA);
47329         this.focusEl.alignTo(el, "tl-tl");
47330         if(Roo.isGecko){
47331             this.focusEl.focus();
47332         }else {
47333             this.focusEl.focus.defer(1, this.focusEl);
47334         }
47335     },
47336
47337     /**
47338      * Scrolls the specified cell into view
47339      * @param {Number} row The row index
47340      * @param {Number} col The column index
47341      * @param {Boolean} hscroll false to disable horizontal scrolling
47342      */
47343     ensureVisible : function(AB, AC, AD){
47344         if(typeof  AB != "number"){
47345             AB = AB.rowIndex;
47346         }
47347         if(AB < 0 && AB >= this.ds.getCount()){
47348             return;
47349         }
47350
47351         AC = (AC !== undefined ? AC : 0);
47352         var  cm = this.grid.colModel;
47353         while(cm.isHidden(AC)){
47354             AC++;
47355         }
47356
47357         var  el = this.getCell(AB, AC);
47358         if(!el){
47359             return;
47360         }
47361         var  c = this.scroller.dom;
47362
47363         var  AE = parseInt(el.offsetTop, 10);
47364         var  AF = parseInt(el.offsetLeft, 10);
47365         var  AG = AE + el.offsetHeight;
47366         var  AH = AF + el.offsetWidth;
47367
47368         var  ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47369         var  AI = parseInt(c.scrollTop, 10);
47370         var  AJ = parseInt(c.scrollLeft, 10);
47371         var  AK = AI + ch;
47372         var  AL = AJ + c.clientWidth;
47373
47374         if(AE < AI){
47375                 c.scrollTop = AE;
47376         }else  if(AG > AK){
47377             c.scrollTop = AG-ch;
47378         }
47379
47380         if(AD !== false){
47381             if(AF < AJ){
47382                 c.scrollLeft = AF;
47383             }else  if(AH > AL){
47384                 c.scrollLeft = AH-c.clientWidth;
47385             }
47386         }
47387         return  el;
47388     },
47389
47390     updateColumns : function(){
47391         this.grid.stopEditing();
47392         var  cm = this.grid.colModel, AM = this.getColumnIds();
47393         //var totalWidth = cm.getTotalWidth();
47394         var  AN = 0;
47395         for(var  i = 0, len = cm.getColumnCount(); i < len; i++){
47396             //if(cm.isHidden(i)) continue;
47397             var  w = cm.getColumnWidth(i);
47398             this.css.updateRule(this.colSelector+this.idToCssName(AM[i]), "width", (w - this.borderWidth) + "px");
47399             this.css.updateRule(this.hdSelector+this.idToCssName(AM[i]), "width", (w - this.borderWidth) + "px");
47400         }
47401
47402         this.updateSplitters();
47403     },
47404
47405     generateRules : function(cm){
47406         var  AO = [], AP = this.idToCssName(this.grid.id)+ '-cssrules';
47407         Roo.util.CSS.removeStyleSheet(AP);
47408         for(var  i = 0, len = cm.getColumnCount(); i < len; i++){
47409             var  cid = cm.getColumnId(i);
47410             var  align = '';
47411             if(cm.config[i].align){
47412                 align = 'text-align:'+cm.config[i].align+';';
47413             }
47414             var  hidden = '';
47415             if(cm.isHidden(i)){
47416                 hidden = 'display:none;';
47417             }
47418             var  width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47419             AO.push(
47420                     this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47421                     this.hdSelector, cid, " {\n", align, width, "}\n",
47422                     this.tdSelector, cid, " {\n",hidden,"\n}\n",
47423                     this.splitSelector, cid, " {\n", hidden , "\n}\n");
47424         }
47425         return  Roo.util.CSS.createStyleSheet(AO.join(""), AP);
47426     },
47427
47428     updateSplitters : function(){
47429         var  cm = this.cm, s = this.getSplitters();
47430         if(s){ // splitters not created yet
47431             var  AN = 0, Y = true;
47432             for(var  i = 0, len = cm.getColumnCount(); i < len; i++){
47433                 if(cm.isHidden(i)) continue;
47434                 var  w = cm.getColumnWidth(i);
47435                 if(!cm.isLocked(i) && Y){
47436                     AN = 0;
47437                     Y = false;
47438                 }
47439
47440                 AN += w;
47441                 s[i].style.left = (AN-this.splitOffset) + "px";
47442             }
47443         }
47444     },
47445
47446     handleHiddenChange : function(AQ, AR, AS){
47447         if(AS){
47448             this.hideColumn(AR);
47449         }else {
47450             this.unhideColumn(AR);
47451         }
47452     },
47453
47454     hideColumn : function(AT){
47455         var  AU = this.getColumnId(AT);
47456         this.css.updateRule(this.tdSelector+this.idToCssName(AU), "display", "none");
47457         this.css.updateRule(this.splitSelector+this.idToCssName(AU), "display", "none");
47458         if(Roo.isSafari){
47459             this.updateHeaders();
47460         }
47461
47462         this.updateSplitters();
47463         this.layout();
47464     },
47465
47466     unhideColumn : function(AV){
47467         var  AW = this.getColumnId(AV);
47468         this.css.updateRule(this.tdSelector+this.idToCssName(AW), "display", "");
47469         this.css.updateRule(this.splitSelector+this.idToCssName(AW), "display", "");
47470
47471         if(Roo.isSafari){
47472             this.updateHeaders();
47473         }
47474
47475         this.updateSplitters();
47476         this.layout();
47477     },
47478
47479     insertRows : function(dm, AX, AY, AZ){
47480         if(AX == 0 && AY == dm.getCount()-1){
47481             this.refresh();
47482         }else {
47483             if(!AZ){
47484                 this.fireEvent("beforerowsinserted", this, AX, AY);
47485             }
47486             var  s = this.getScrollState();
47487             var  markup = this.renderRows(AX, AY);
47488             this.bufferRows(markup[0], this.getLockedTable(), AX);
47489             this.bufferRows(markup[1], this.getBodyTable(), AX);
47490             this.restoreScroll(s);
47491             if(!AZ){
47492                 this.fireEvent("rowsinserted", this, AX, AY);
47493                 this.syncRowHeights(AX, AY);
47494                 this.stripeRows(AX);
47495                 this.layout();
47496             }
47497         }
47498     },
47499
47500     bufferRows : function(Aa, Ab, Ac){
47501         var  Ad = null, Ae = Ab.rows, Af = Ab.tBodies[0];
47502         if(Ac < Ae.length){
47503             Ad = Ae[Ac];
47504         }
47505         var  b = document.createElement("div");
47506         b.innerHTML = "<table><tbody>"+Aa+"</tbody></table>";
47507         var  Ag = b.firstChild.rows;
47508         for(var  i = 0, len = Ag.length; i < len; i++){
47509             if(Ad){
47510                 Af.insertBefore(Ag[0], Ad);
47511             }else {
47512                 Af.appendChild(Ag[0]);
47513             }
47514         }
47515
47516         b.innerHTML = "";
47517         b = null;
47518     },
47519
47520     deleteRows : function(dm, Ah, Ai){
47521         if(dm.getRowCount()<1){
47522             this.fireEvent("beforerefresh", this);
47523             this.mainBody.update("");
47524             this.lockedBody.update("");
47525             this.fireEvent("refresh", this);
47526         }else {
47527             this.fireEvent("beforerowsdeleted", this, Ah, Ai);
47528             var  bt = this.getBodyTable();
47529             var  Af = bt.firstChild;
47530             var  Ag = bt.rows;
47531             for(var  a = Ah; a <= Ai; a++){
47532                 Af.removeChild(Ag[Ah]);
47533             }
47534
47535             this.stripeRows(Ah);
47536             this.fireEvent("rowsdeleted", this, Ah, Ai);
47537         }
47538     },
47539
47540     updateRows : function(Aj, Ak, Al){
47541         var  s = this.getScrollState();
47542         this.refresh();
47543         this.restoreScroll(s);
47544     },
47545
47546     handleSort : function(Am, An, Ao, Ap){
47547         if(!Ap){
47548            this.refresh();
47549         }
47550
47551         this.updateHeaderSortState();
47552     },
47553
47554     getScrollState : function(){
47555         var  sb = this.scroller.dom;
47556         return  {left: sb.scrollLeft, top: sb.scrollTop};
47557     },
47558
47559     stripeRows : function(Aq){
47560         if(!this.grid.stripeRows || this.ds.getCount() < 1){
47561             return;
47562         }
47563
47564         Aq = Aq || 0;
47565         var  Ar = this.getBodyTable().rows;
47566         var  As = this.getLockedTable().rows;
47567         var  At = ' x-grid-row-alt ';
47568         for(var  i = Aq, len = Ar.length; i < len; i++){
47569             var  AB = Ar[i], U = As[i];
47570             var  isAlt = ((i+1) % 2 == 0);
47571             var  hasAlt = (' '+AB.className + ' ').indexOf(At) != -1;
47572             if(isAlt == hasAlt){
47573                 continue;
47574             }
47575             if(isAlt){
47576                 AB.className += " x-grid-row-alt";
47577             }else {
47578                 AB.className = AB.className.replace("x-grid-row-alt", "");
47579             }
47580             if(U){
47581                 U.className = AB.className;
47582             }
47583         }
47584     },
47585
47586     restoreScroll : function(Au){
47587         var  sb = this.scroller.dom;
47588         sb.scrollLeft = Au.left;
47589         sb.scrollTop = Au.top;
47590         this.syncScroll();
47591     },
47592
47593     syncScroll : function(){
47594         var  sb = this.scroller.dom;
47595         var  sh = this.mainHd.dom;
47596         var  bs = this.mainBody.dom;
47597         var  lv = this.lockedBody.dom;
47598         sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47599         lv.scrollTop = bs.scrollTop = sb.scrollTop;
47600     },
47601
47602     handleScroll : function(e){
47603         this.syncScroll();
47604         var  sb = this.scroller.dom;
47605         this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47606         e.stopEvent();
47607     },
47608
47609     handleWheel : function(e){
47610         var  d = e.getWheelDelta();
47611         this.scroller.dom.scrollTop -= d*22;
47612         // set this here to prevent jumpy scrolling on large tables
47613         this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47614         e.stopEvent();
47615     },
47616
47617     renderRows : function(Av, Aw){
47618         // pull in all the crap needed to render rows
47619         var  g = this.grid, cm = g.colModel, ds = g.dataSource, Ax = g.stripeRows;
47620         var  Ay = cm.getColumnCount();
47621
47622         if(ds.getCount() < 1){
47623             return  ["", ""];
47624         }
47625
47626         // build a map for all the columns
47627         var  cs = [];
47628         for(var  i = 0; i < Ay; i++){
47629             var  name = cm.getDataIndex(i);
47630             cs[i] = {
47631                 name : typeof  name == 'undefined' ? ds.fields.get(i).name : name,
47632                 renderer : cm.getRenderer(i),
47633                 id : cm.getColumnId(i),
47634                 locked : cm.isLocked(i)
47635             };
47636         }
47637
47638
47639         Av = Av || 0;
47640         Aw = typeof  Aw == "undefined"? ds.getCount()-1 : Aw;
47641
47642         // records to render
47643         var  rs = ds.getRange(Av, Aw);
47644
47645         return  this.doRender(cs, rs, ds, Av, Ay, Ax);
47646     },
47647
47648     // As much as I hate to duplicate code, this was branched because FireFox really hates
47649     // [].join("") on strings. The performance difference was substantial enough to
47650     // branch this function
47651     doRender : Roo.isGecko ?
47652             function(cs, rs, ds, Az, A0, A1){
47653                 var  ts = this.templates, ct = ts.cell, rt = ts.row;
47654                 // buffers
47655                 var  A2 = "", A3 = "", cb, A4, c, p = {}, rp = {}, r, a;
47656                 for(var  j = 0, len = rs.length; j < len; j++){
47657                     r = rs[j]; cb = ""; A4 = ""; a = (j+Az);
47658                     for(var  i = 0; i < A0; i++){
47659                         c = cs[i];
47660                         p.cellId = "x-grid-cell-" + a + "-" + i;
47661                         p.id = c.id;
47662                         p.css = p.attr = "";
47663                         p.value = c.renderer(r.data[c.name], p, r, a, i, ds);
47664                         if(p.value == undefined || p.value === "") p.value = "&#160;";
47665                         if(r.dirty && typeof  r.modified[c.name] !== 'undefined'){
47666                             p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47667                         }
47668                         var  Aa = ct.apply(p);
47669                         if(!c.locked){
47670                             cb+= Aa;
47671                         }else {
47672                             A4+= Aa;
47673                         }
47674                     }
47675                     var  alt = [];
47676                     if(A1 && ((a+1) % 2 == 0)){
47677                         alt[0] = "x-grid-row-alt";
47678                     }
47679                     if(r.dirty){
47680                         alt[1] = " x-grid-dirty-row";
47681                     }
47682
47683                     rp.cells = A4;
47684                     if(this.getRowClass){
47685                         alt[2] = this.getRowClass(r, a);
47686                     }
47687
47688                     rp.alt = alt.join(" ");
47689                     A3+= rt.apply(rp);
47690                     rp.cells = cb;
47691                     A2+=  rt.apply(rp);
47692                 }
47693                 return  [A3, A2];
47694             } :
47695             function(cs, rs, ds, A5, A6, A7){
47696                 var  ts = this.templates, ct = ts.cell, rt = ts.row;
47697                 // buffers
47698                 var  A8 = [], A9 = [], cb, BA, c, p = {}, rp = {}, r, a;
47699                 for(var  j = 0, len = rs.length; j < len; j++){
47700                     r = rs[j]; cb = []; BA = []; a = (j+A5);
47701                     for(var  i = 0; i < A6; i++){
47702                         c = cs[i];
47703                         p.cellId = "x-grid-cell-" + a + "-" + i;
47704                         p.id = c.id;
47705                         p.css = p.attr = "";
47706                         p.value = c.renderer(r.data[c.name], p, r, a, i, ds);
47707                         if(p.value == undefined || p.value === "") p.value = "&#160;";
47708                         if(r.dirty && typeof  r.modified[c.name] !== 'undefined'){
47709                             p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47710                         }
47711                         var  Aa = ct.apply(p);
47712                         if(!c.locked){
47713                             cb[cb.length] = Aa;
47714                         }else {
47715                             BA[BA.length] = Aa;
47716                         }
47717                     }
47718                     var  alt = [];
47719                     if(A7 && ((a+1) % 2 == 0)){
47720                         alt[0] = "x-grid-row-alt";
47721                     }
47722                     if(r.dirty){
47723                         alt[1] = " x-grid-dirty-row";
47724                     }
47725
47726                     rp.cells = BA;
47727                     if(this.getRowClass){
47728                         alt[2] = this.getRowClass(r, a);
47729                     }
47730
47731                     rp.alt = alt.join(" ");
47732                     rp.cells = BA.join("");
47733                     A9[A9.length] = rt.apply(rp);
47734                     rp.cells = cb.join("");
47735                     A8[A8.length] =  rt.apply(rp);
47736                 }
47737                 return  [A9.join(""), A8.join("")];
47738             },
47739
47740     renderBody : function(){
47741         var  BB = this.renderRows();
47742         var  bt = this.templates.body;
47743         return  [bt.apply({rows: BB[0]}), bt.apply({rows: BB[1]})];
47744     },
47745
47746     /**
47747      * Refreshes the grid
47748      * @param {Boolean} headersToo
47749      */
47750     refresh : function(BC){
47751         this.fireEvent("beforerefresh", this);
47752         this.grid.stopEditing();
47753         var  BD = this.renderBody();
47754         this.lockedBody.update(BD[0]);
47755         this.mainBody.update(BD[1]);
47756         if(BC === true){
47757             this.updateHeaders();
47758             this.updateColumns();
47759             this.updateSplitters();
47760             this.updateHeaderSortState();
47761         }
47762
47763         this.syncRowHeights();
47764         this.layout();
47765         this.fireEvent("refresh", this);
47766     },
47767
47768     handleColumnMove : function(cm, BE, BF){
47769         this.indexMap = null;
47770         var  s = this.getScrollState();
47771         this.refresh(true);
47772         this.restoreScroll(s);
47773         this.afterMove(BF);
47774     },
47775
47776     afterMove : function(BG){
47777         if(this.enableMoveAnim && Roo.enableFx){
47778             this.fly(this.getHeaderCell(BG).firstChild).highlight(this.hlColor);
47779         }
47780     },
47781
47782     updateCell : function(dm, BH, BI){
47783         var  BJ = this.getColumnIndexByDataIndex(BI);
47784         if(typeof  BJ == "undefined"){ // not present in grid
47785             return;
47786         }
47787         var  cm = this.grid.colModel;
47788         var  BK = this.getCell(BH, BJ);
47789         var  BL = this.getCellText(BH, BJ);
47790
47791         var  p = {
47792             cellId : "x-grid-cell-" + BH + "-" + BJ,
47793             id : cm.getColumnId(BJ),
47794             css: BJ == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
47795         };
47796         var  BM = cm.getRenderer(BJ);
47797         var  BN = BM(dm.getValueAt(BH, BI), p, BH, BJ, dm);
47798         if(typeof  BN == "undefined" || BN === "") BN = "&#160;";
47799         BL.innerHTML = BN;
47800         BK.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
47801         this.syncRowHeights(BH, BH);
47802     },
47803
47804     calcColumnWidth : function(BO, BP){
47805         var  BQ = 0;
47806         if(this.grid.autoSizeHeaders){
47807             var  h = this.getHeaderCellMeasure(BO);
47808             BQ = Math.max(BQ, h.scrollWidth);
47809         }
47810         var  tb, BR;
47811         if(this.cm.isLocked(BO)){
47812             tb = this.getLockedTable();
47813             BR = BO;
47814         }else {
47815             tb = this.getBodyTable();
47816             BR = BO - this.cm.getLockedCount();
47817         }
47818         if(tb && tb.rows){
47819             var  Ar = tb.rows;
47820             var  stopIndex = Math.min(BP || Ar.length, Ar.length);
47821             for(var  i = 0; i < stopIndex; i++){
47822                 var  BK = Ar[i].childNodes[BR].firstChild;
47823                 BQ = Math.max(BQ, BK.scrollWidth);
47824             }
47825         }
47826         return  BQ + /*margin for error in IE*/ 5;
47827     },
47828     /**
47829      * Autofit a column to its content.
47830      * @param {Number} colIndex
47831      * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47832      */
47833      autoSizeColumn : function(BS, BT, BU){
47834          if(this.cm.isHidden(BS)){
47835              return; // can't calc a hidden column
47836          }
47837         if(BT){
47838             var  AW = this.cm.getColumnId(BS);
47839             this.css.updateRule(this.colSelector +this.idToCssName( AW), "width", this.grid.minColumnWidth + "px");
47840            if(this.grid.autoSizeHeaders){
47841                this.css.updateRule(this.hdSelector + this.idToCssName(AW), "width", this.grid.minColumnWidth + "px");
47842            }
47843         }
47844         var  BV = this.calcColumnWidth(BS);
47845         this.cm.setColumnWidth(BS,
47846             Math.max(this.grid.minColumnWidth, BV), BU);
47847         if(!BU){
47848             this.grid.fireEvent("columnresize", BS, BV);
47849         }
47850     },
47851
47852     /**
47853      * Autofits all columns to their content and then expands to fit any extra space in the grid
47854      */
47855      autoSizeColumns : function(){
47856         var  cm = this.grid.colModel;
47857         var  BW = cm.getColumnCount();
47858         for(var  i = 0; i < BW; i++){
47859             this.autoSizeColumn(i, true, true);
47860         }
47861         if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47862             this.fitColumns();
47863         }else {
47864             this.updateColumns();
47865             this.layout();
47866         }
47867     },
47868
47869     /**
47870      * Autofits all columns to the grid's width proportionate with their current size
47871      * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47872      */
47873     fitColumns : function(BX){
47874         var  cm = this.grid.colModel;
47875         var  BY = cm.getColumnCount();
47876         var  BZ = [];
47877         var  Ba = 0;
47878         var  i, w;
47879         for (i = 0; i < BY; i++){
47880             if(!cm.isHidden(i) && !cm.isFixed(i)){
47881                 w = cm.getColumnWidth(i);
47882                 BZ.push(i);
47883                 BZ.push(w);
47884                 Ba += w;
47885             }
47886         }
47887         var  Bb = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47888         if(BX){
47889             Bb -= 17;
47890         }
47891         var  Bc = (Bb - cm.getTotalWidth())/Ba;
47892         while (BZ.length){
47893             w = BZ.pop();
47894             i = BZ.pop();
47895             cm.setColumnWidth(i, Math.floor(w + w*Bc), true);
47896         }
47897
47898         this.updateColumns();
47899         this.layout();
47900     },
47901
47902     onRowSelect : function(Bd){
47903         var  Be = this.getRowComposite(Bd);
47904         Be.addClass("x-grid-row-selected");
47905     },
47906
47907     onRowDeselect : function(Bf){
47908         var  Bg = this.getRowComposite(Bf);
47909         Bg.removeClass("x-grid-row-selected");
47910     },
47911
47912     onCellSelect : function(Bh, Bi){
47913         var  Bj = this.getCell(Bh, Bi);
47914         if(Bj){
47915             Roo.fly(Bj).addClass("x-grid-cell-selected");
47916         }
47917     },
47918
47919     onCellDeselect : function(Bk, Bl){
47920         var  Bm = this.getCell(Bk, Bl);
47921         if(Bm){
47922             Roo.fly(Bm).removeClass("x-grid-cell-selected");
47923         }
47924     },
47925
47926     updateHeaderSortState : function(){
47927         var  Bn = this.ds.getSortState();
47928         if(!Bn){
47929             return;
47930         }
47931
47932         this.sortState = Bn;
47933         var  Bo = this.cm.findColumnIndex(Bn.field);
47934         if(Bo != -1){
47935             var  Ao = Bn.direction;
47936             var  sc = this.sortClasses;
47937             var  hds = this.el.select(this.headerSelector).removeClass(sc);
47938             hds.item(Bo).addClass(sc[Ao == "DESC" ? 1 : 0]);
47939         }
47940     },
47941
47942     handleHeaderClick : function(g, Bp){
47943         if(this.headersDisabled){
47944             return;
47945         }
47946         var  dm = g.dataSource, cm = g.colModel;
47947             if(!cm.isSortable(Bp)){
47948             return;
47949         }
47950
47951             g.stopEditing();
47952         dm.sort(cm.getDataIndex(Bp));
47953     },
47954
47955
47956     destroy : function(){
47957         if(this.colMenu){
47958             this.colMenu.removeAll();
47959             Roo.menu.MenuMgr.unregister(this.colMenu);
47960             this.colMenu.getEl().remove();
47961             delete  this.colMenu;
47962         }
47963         if(this.hmenu){
47964             this.hmenu.removeAll();
47965             Roo.menu.MenuMgr.unregister(this.hmenu);
47966             this.hmenu.getEl().remove();
47967             delete  this.hmenu;
47968         }
47969         if(this.grid.enableColumnMove){
47970             var  dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47971             if(dds){
47972                 for(var  dd  in  dds){
47973                     if(!dds[dd].config.isTarget && dds[dd].dragElId){
47974                         var  elid = dds[dd].dragElId;
47975                         dds[dd].unreg();
47976                         Roo.get(elid).remove();
47977                     } else  if(dds[dd].config.isTarget){
47978                         dds[dd].proxyTop.remove();
47979                         dds[dd].proxyBottom.remove();
47980                         dds[dd].unreg();
47981                     }
47982                     if(Roo.dd.DDM.locationCache[dd]){
47983                         delete  Roo.dd.DDM.locationCache[dd];
47984                     }
47985                 }
47986                 delete  Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47987             }
47988         }
47989
47990         Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47991         this.bind(null, null);
47992         Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47993     },
47994
47995     handleLockChange : function(){
47996         this.refresh(true);
47997     },
47998
47999     onDenyColumnLock : function(){
48000
48001     },
48002
48003     onDenyColumnHide : function(){
48004
48005     },
48006
48007     handleHdMenuClick : function(Bq){
48008         var  Br = this.hdCtxIndex;
48009         var  cm = this.cm, ds = this.ds;
48010         switch(Bq.id){
48011             case  "asc":
48012                 ds.sort(cm.getDataIndex(Br), "ASC");
48013                 break;
48014             case  "desc":
48015                 ds.sort(cm.getDataIndex(Br), "DESC");
48016                 break;
48017             case  "lock":
48018                 var  lc = cm.getLockedCount();
48019                 if(cm.getColumnCount(true) <= lc+1){
48020                     this.onDenyColumnLock();
48021                     return;
48022                 }
48023                 if(lc != Br){
48024                     cm.setLocked(Br, true, true);
48025                     cm.moveColumn(Br, lc);
48026                     this.grid.fireEvent("columnmove", Br, lc);
48027                 }else {
48028                     cm.setLocked(Br, true);
48029                 }
48030             break;
48031             case  "unlock":
48032                 var  lc = cm.getLockedCount();
48033                 if((lc-1) != Br){
48034                     cm.setLocked(Br, false, true);
48035                     cm.moveColumn(Br, lc-1);
48036                     this.grid.fireEvent("columnmove", Br, lc-1);
48037                 }else {
48038                     cm.setLocked(Br, false);
48039                 }
48040             break;
48041             default:
48042                 Br = cm.getIndexById(Bq.id.substr(4));
48043                 if(Br != -1){
48044                     if(Bq.checked && cm.getColumnCount(true) <= 1){
48045                         this.onDenyColumnHide();
48046                         return  false;
48047                     }
48048
48049                     cm.setHidden(Br, Bq.checked);
48050                 }
48051         }
48052         return  true;
48053     },
48054
48055     beforeColMenuShow : function(){
48056         var  cm = this.cm,  Bs = cm.getColumnCount();
48057         this.colMenu.removeAll();
48058         for(var  i = 0; i < Bs; i++){
48059             this.colMenu.add(new  Roo.menu.CheckItem({
48060                 id: "col-"+cm.getColumnId(i),
48061                 text: cm.getColumnHeader(i),
48062                 checked: !cm.isHidden(i),
48063                 hideOnClick:false
48064             }));
48065         }
48066     },
48067
48068     handleHdCtx : function(g, Bt, e){
48069         e.stopEvent();
48070         var  hd = this.getHeaderCell(Bt);
48071         this.hdCtxIndex = Bt;
48072         var  ms = this.hmenu.items, cm = this.cm;
48073         ms.get("asc").setDisabled(!cm.isSortable(Bt));
48074         ms.get("desc").setDisabled(!cm.isSortable(Bt));
48075         if(this.grid.enableColLock !== false){
48076             ms.get("lock").setDisabled(cm.isLocked(Bt));
48077             ms.get("unlock").setDisabled(!cm.isLocked(Bt));
48078         }
48079
48080         this.hmenu.show(hd, "tl-bl");
48081     },
48082
48083     handleHdOver : function(e){
48084         var  hd = this.findHeaderCell(e.getTarget());
48085         if(hd && !this.headersDisabled){
48086             if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48087                this.fly(hd).addClass("x-grid-hd-over");
48088             }
48089         }
48090     },
48091
48092     handleHdOut : function(e){
48093         var  hd = this.findHeaderCell(e.getTarget());
48094         if(hd){
48095             this.fly(hd).removeClass("x-grid-hd-over");
48096         }
48097     },
48098
48099     handleSplitDblClick : function(e, t){
48100         var  i = this.getCellIndex(t);
48101         if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48102             this.autoSizeColumn(i, true);
48103             this.layout();
48104         }
48105     },
48106
48107     render : function(){
48108
48109         var  cm = this.cm;
48110         var  Bu = cm.getColumnCount();
48111
48112         if(this.grid.monitorWindowResize === true){
48113             Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48114         }
48115         var  Bv = this.renderHeaders();
48116         var  Bw = this.templates.body.apply({rows:""});
48117         var  Bx = this.templates.master.apply({
48118             lockedBody: Bw,
48119             body: Bw,
48120             lockedHeader: Bv[0],
48121             header: Bv[1]
48122         });
48123
48124         //this.updateColumns();
48125
48126         this.grid.getGridEl().dom.innerHTML = Bx;
48127
48128         this.initElements();
48129
48130         this.scroller.on("scroll", this.handleScroll, this);
48131         this.lockedBody.on("mousewheel", this.handleWheel, this);
48132         this.mainBody.on("mousewheel", this.handleWheel, this);
48133
48134         this.mainHd.on("mouseover", this.handleHdOver, this);
48135         this.mainHd.on("mouseout", this.handleHdOut, this);
48136         this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48137                 {delegate: "."+this.splitClass});
48138
48139         this.lockedHd.on("mouseover", this.handleHdOver, this);
48140         this.lockedHd.on("mouseout", this.handleHdOut, this);
48141         this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48142                 {delegate: "."+this.splitClass});
48143
48144         if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48145             new  Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48146         }
48147
48148
48149         this.updateSplitters();
48150
48151         if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48152             new  Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48153             new  Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48154         }
48155
48156         if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48157             this.hmenu = new  Roo.menu.Menu({id: this.grid.id + "-hctx"});
48158             this.hmenu.add(
48159                 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48160                 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48161             );
48162             if(this.grid.enableColLock !== false){
48163                 this.hmenu.add('-',
48164                     {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48165                     {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48166                 );
48167             }
48168             if(this.grid.enableColumnHide !== false){
48169
48170                 this.colMenu = new  Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48171                 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48172                 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48173
48174                 this.hmenu.add('-',
48175                     {id:"columns", text: this.columnsText, menu: this.colMenu}
48176                 );
48177             }
48178
48179             this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48180
48181             this.grid.on("headercontextmenu", this.handleHdCtx, this);
48182         }
48183
48184         if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48185             this.dd = new  Roo.grid.GridDragZone(this.grid, {
48186                 ddGroup : this.grid.ddGroup || 'GridDD'
48187             });
48188         }
48189
48190
48191         /*
48192         for(var i = 0; i < colCount; i++){
48193             if(cm.isHidden(i)){
48194                 this.hideColumn(i);
48195             }
48196             if(cm.config[i].align){
48197                 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48198                 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48199             }
48200         }*/
48201         
48202         this.updateHeaderSortState();
48203
48204         this.beforeInitialResize();
48205         this.layout(true);
48206
48207         // two part rendering gives faster view to the user
48208         this.renderPhase2.defer(1, this);
48209     },
48210
48211     renderPhase2 : function(){
48212         // render the rows now
48213         this.refresh();
48214         if(this.grid.autoSizeColumns){
48215             this.autoSizeColumns();
48216         }
48217     },
48218
48219     beforeInitialResize : function(){
48220
48221     },
48222
48223     onColumnSplitterMoved : function(i, w){
48224         this.userResized = true;
48225         var  cm = this.grid.colModel;
48226         cm.setColumnWidth(i, w, true);
48227         var  By = cm.getColumnId(i);
48228         this.css.updateRule(this.colSelector + this.idToCssName(By), "width", (w-this.borderWidth) + "px");
48229         this.css.updateRule(this.hdSelector + this.idToCssName(By), "width", (w-this.borderWidth) + "px");
48230         this.updateSplitters();
48231         this.layout();
48232         this.grid.fireEvent("columnresize", i, w);
48233     },
48234
48235     syncRowHeights : function(Bz, B0){
48236         if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48237             Bz = Bz || 0;
48238             var  mrows = this.getBodyTable().rows;
48239             var  As = this.getLockedTable().rows;
48240             var  len = mrows.length-1;
48241             B0 = Math.min(B0 || len, len);
48242             for(var  i = Bz; i <= B0; i++){
48243                 var  m = mrows[i], l = As[i];
48244                 var  h = Math.max(m.offsetHeight, l.offsetHeight);
48245                 m.style.height = l.style.height = h + "px";
48246             }
48247         }
48248     },
48249
48250     layout : function(B1, B2){
48251         var  g = this.grid;
48252         var  B3 = g.autoHeight;
48253         var  B4 = 16;
48254         var  c = g.getGridEl(), cm = this.cm,
48255                 B5 = g.autoExpandColumn,
48256                 gv = this;
48257         //c.beginMeasure();
48258
48259         if(!c.dom.offsetWidth){ // display:none?
48260             if(B1){
48261                 this.lockedWrap.show();
48262                 this.mainWrap.show();
48263             }
48264             return;
48265         }
48266
48267         var  B6 = this.cm.isLocked(0);
48268
48269         var  B7 = this.headerPanel.getHeight();
48270         var  B8 = this.footerPanel.getHeight();
48271
48272         if(B3){
48273             var  ch = this.getBodyTable().offsetHeight + B7 + B8 + this.mainHd.getHeight();
48274             var  newHeight = ch + c.getBorderWidth("tb");
48275             if(g.maxHeight){
48276                 newHeight = Math.min(g.maxHeight, newHeight);
48277             }
48278
48279             c.setHeight(newHeight);
48280         }
48281
48282         if(g.autoWidth){
48283             c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48284         }
48285
48286         var  s = this.scroller;
48287
48288         var  B9 = c.getSize(true);
48289
48290         this.el.setSize(B9.width, B9.height);
48291
48292         this.headerPanel.setWidth(B9.width);
48293         this.footerPanel.setWidth(B9.width);
48294
48295         var  CA = this.mainHd.getHeight();
48296         var  vw = B9.width;
48297         var  vh = B9.height - (B7 + B8);
48298
48299         s.setSize(vw, vh);
48300
48301         var  bt = this.getBodyTable();
48302         var  CB = B6 ?
48303                       Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48304
48305         var  CC = bt.offsetHeight;
48306         var  CD = CB + bt.offsetWidth;
48307         var  CE = false, CF = false;
48308
48309         this.scrollSizer.setSize(CD, CC+CA);
48310
48311         var  lw = this.lockedWrap, mw = this.mainWrap;
48312         var  lb = this.lockedBody, mb = this.mainBody;
48313
48314         setTimeout(function(){
48315             var  t = s.dom.offsetTop;
48316             var  w = s.dom.clientWidth,
48317                 h = s.dom.clientHeight;
48318
48319             lw.setTop(t);
48320             lw.setSize(CB, h);
48321
48322             mw.setLeftTop(CB, t);
48323             mw.setSize(w-CB, h);
48324
48325             lb.setHeight(h-CA);
48326             mb.setHeight(h-CA);
48327
48328             if(B2 !== true && !gv.userResized && B5){
48329                 // high speed resize without full column calculation
48330                 
48331                 var  ci = cm.getIndexById(B5);
48332                 if (ci < 0) {
48333                     ci = cm.findColumnIndex(B5);
48334                 }
48335
48336                 ci = Math.max(0, ci); // make sure it's got at least the first col.
48337                 var  expandId = cm.getColumnId(ci);
48338                 var   tw = cm.getTotalWidth(false);
48339                 var  currentWidth = cm.getColumnWidth(ci);
48340                 var  cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48341                 if(currentWidth != cw){
48342                     cm.setColumnWidth(ci, cw, true);
48343                     gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48344                     gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48345                     gv.updateSplitters();
48346                     gv.layout(false, true);
48347                 }
48348             }
48349
48350             if(B1){
48351                 lw.show();
48352                 mw.show();
48353             }
48354             //c.endMeasure();
48355         }, 10);
48356     },
48357
48358     onWindowResize : function(){
48359         if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48360             return;
48361         }
48362
48363         this.layout();
48364     },
48365
48366     appendFooter : function(CG){
48367         return  null;
48368     },
48369
48370     sortAscText : "Sort Ascending",
48371     sortDescText : "Sort Descending",
48372     lockText : "Lock Column",
48373     unlockText : "Unlock Column",
48374     columnsText : "Columns"
48375 });
48376
48377
48378 Roo.grid.GridView.ColumnDragZone = function(CH, hd){
48379     Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, CH, hd, null);
48380     this.proxy.el.addClass('x-grid3-col-dd');
48381 };
48382
48383 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48384     handleMouseDown : function(e){
48385
48386     },
48387
48388     callHandleMouseDown : function(e){
48389         Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48390     }
48391 });
48392
48393 /*
48394  * Based on:
48395  * Ext JS Library 1.1.1
48396  * Copyright(c) 2006-2007, Ext JS, LLC.
48397  *
48398  * Originally Released Under LGPL - original licence link has changed is not relivant.
48399  *
48400  * Fork - LGPL
48401  * <script type="text/javascript">
48402  */
48403  
48404 // private
48405 // This is a support class used internally by the Grid components
48406 Roo.grid.SplitDragZone = function(A, hd, B){
48407     this.grid = A;
48408     this.view = A.getView();
48409     this.proxy = this.view.resizeProxy;
48410     Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48411         "gridSplitters" + this.grid.getGridEl().id, {
48412         dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48413     });
48414     this.setHandleElId(Roo.id(hd));
48415     this.setOuterHandleElId(Roo.id(B));
48416     this.scroll = false;
48417 };
48418 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48419     fly: Roo.Element.fly,
48420
48421     b4StartDrag : function(x, y){
48422         this.view.headersDisabled = true;
48423         this.proxy.setHeight(this.view.mainWrap.getHeight());
48424         var  w = this.cm.getColumnWidth(this.cellIndex);
48425         var  C = Math.max(w-this.grid.minColumnWidth, 0);
48426         this.resetConstraints();
48427         this.setXConstraint(C, 1000);
48428         this.setYConstraint(0, 0);
48429         this.minX = x - C;
48430         this.maxX = x + 1000;
48431         this.startPos = x;
48432         Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48433     },
48434
48435
48436     handleMouseDown : function(e){
48437         ev = Roo.EventObject.setEvent(e);
48438         var  t = this.fly(ev.getTarget());
48439         if(t.hasClass("x-grid-split")){
48440             this.cellIndex = this.view.getCellIndex(t.dom);
48441             this.split = t.dom;
48442             this.cm = this.grid.colModel;
48443             if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48444                 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48445             }
48446         }
48447     },
48448
48449     endDrag : function(e){
48450         this.view.headersDisabled = false;
48451         var  D = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48452         var  E = D - this.startPos;
48453         this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+E);
48454     },
48455
48456     autoOffset : function(){
48457         this.setDelta(0,0);
48458     }
48459 });
48460 /*
48461  * Based on:
48462  * Ext JS Library 1.1.1
48463  * Copyright(c) 2006-2007, Ext JS, LLC.
48464  *
48465  * Originally Released Under LGPL - original licence link has changed is not relivant.
48466  *
48467  * Fork - LGPL
48468  * <script type="text/javascript">
48469  */
48470  
48471 // private
48472 // This is a support class used internally by the Grid components
48473 Roo.grid.GridDragZone = function(A, B){
48474     this.view = A.getView();
48475     Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, B);
48476     if(this.view.lockedBody){
48477         this.setHandleElId(Roo.id(this.view.mainBody.dom));
48478         this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48479     }
48480
48481     this.scroll = false;
48482     this.grid = A;
48483     this.ddel = document.createElement('div');
48484     this.ddel.className = 'x-grid-dd-wrap';
48485 };
48486
48487 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48488     ddGroup : "GridDD",
48489
48490     getDragData : function(e){
48491         var  t = Roo.lib.Event.getTarget(e);
48492         var  C = this.view.findRowIndex(t);
48493         if(C !== false){
48494             var  sm = this.grid.selModel;
48495             //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48496               //  sm.mouseDown(e, t);
48497             //}
48498             if (e.hasModifier()){
48499                 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48500             }
48501             return  {grid: this.grid, ddel: this.ddel, rowIndex: C, selections:sm.getSelections()};
48502         }
48503         return  false;
48504     },
48505
48506     onInitDrag : function(e){
48507         var  D = this.dragData;
48508         this.ddel.innerHTML = this.grid.getDragDropText();
48509         this.proxy.update(this.ddel);
48510         // fire start drag?
48511     },
48512
48513     afterRepair : function(){
48514         this.dragging = false;
48515     },
48516
48517     getRepairXY : function(e, E){
48518         return  false;
48519     },
48520
48521     onEndDrag : function(F, e){
48522         // fire end drag?
48523     },
48524
48525     onValidDrop : function(dd, e, id){
48526         // fire drag drop?
48527         this.hideProxy();
48528     },
48529
48530     beforeInvalidDrop : function(e, id){
48531
48532     }
48533 });
48534 /*
48535  * Based on:
48536  * Ext JS Library 1.1.1
48537  * Copyright(c) 2006-2007, Ext JS, LLC.
48538  *
48539  * Originally Released Under LGPL - original licence link has changed is not relivant.
48540  *
48541  * Fork - LGPL
48542  * <script type="text/javascript">
48543  */
48544  
48545
48546 /**
48547  * @class Roo.grid.ColumnModel
48548  * @extends Roo.util.Observable
48549  * This is the default implementation of a ColumnModel used by the Grid. It defines
48550  * the columns in the grid.
48551  * <br>Usage:<br>
48552  <pre><code>
48553  var colModel = new Roo.grid.ColumnModel([
48554         {header: "Ticker", width: 60, sortable: true, locked: true},
48555         {header: "Company Name", width: 150, sortable: true},
48556         {header: "Market Cap.", width: 100, sortable: true},
48557         {header: "$ Sales", width: 100, sortable: true, renderer: money},
48558         {header: "Employees", width: 100, sortable: true, resizable: false}
48559  ]);
48560  </code></pre>
48561  * <p>
48562  
48563  * The config options listed for this class are options which may appear in each
48564  * individual column definition.
48565  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48566  * @constructor
48567  * @param {Object} config An Array of column config objects. See this class's
48568  * config objects for details.
48569 */
48570 Roo.grid.ColumnModel = function(A){
48571         /**
48572      * The config passed into the constructor
48573      */
48574     this.config = A;
48575     this.lookup = {};
48576
48577     // if no id, create one
48578     // if the column does not have a dataIndex mapping,
48579     // map it to the order it is in the config
48580     for(var  i = 0, len = A.length; i < len; i++){
48581         var  c = A[i];
48582         if(typeof  c.dataIndex == "undefined"){
48583             c.dataIndex = i;
48584         }
48585         if(typeof  c.renderer == "string"){
48586             c.renderer = Roo.util.Format[c.renderer];
48587         }
48588         if(typeof  c.id == "undefined"){
48589             c.id = Roo.id();
48590         }
48591         if(c.editor && c.editor.xtype){
48592             c.editor  = Roo.factory(c.editor, Roo.grid);
48593         }
48594         if(c.editor && c.editor.isFormField){
48595             c.editor = new  Roo.grid.GridEditor(c.editor);
48596         }
48597
48598         this.lookup[c.id] = c;
48599     }
48600
48601
48602     /**
48603      * The width of columns which have no width specified (defaults to 100)
48604      * @type Number
48605      */
48606     this.defaultWidth = 100;
48607
48608     /**
48609      * Default sortable of columns which have no sortable specified (defaults to false)
48610      * @type Boolean
48611      */
48612     this.defaultSortable = false;
48613
48614     this.addEvents({
48615         /**
48616              * @event widthchange
48617              * Fires when the width of a column changes.
48618              * @param {ColumnModel} this
48619              * @param {Number} columnIndex The column index
48620              * @param {Number} newWidth The new width
48621              */
48622             "widthchange": true,
48623         /**
48624              * @event headerchange
48625              * Fires when the text of a header changes.
48626              * @param {ColumnModel} this
48627              * @param {Number} columnIndex The column index
48628              * @param {Number} newText The new header text
48629              */
48630             "headerchange": true,
48631         /**
48632              * @event hiddenchange
48633              * Fires when a column is hidden or "unhidden".
48634              * @param {ColumnModel} this
48635              * @param {Number} columnIndex The column index
48636              * @param {Boolean} hidden true if hidden, false otherwise
48637              */
48638             "hiddenchange": true,
48639             /**
48640          * @event columnmoved
48641          * Fires when a column is moved.
48642          * @param {ColumnModel} this
48643          * @param {Number} oldIndex
48644          * @param {Number} newIndex
48645          */
48646         "columnmoved" : true,
48647         /**
48648          * @event columlockchange
48649          * Fires when a column's locked state is changed
48650          * @param {ColumnModel} this
48651          * @param {Number} colIndex
48652          * @param {Boolean} locked true if locked
48653          */
48654         "columnlockchange" : true
48655     });
48656     Roo.grid.ColumnModel.superclass.constructor.call(this);
48657 };
48658 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48659     /**
48660      * @cfg {String} header The header text to display in the Grid view.
48661      */
48662     /**
48663      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48664      * {@link Roo.data.Record} definition from which to draw the column's value. If not
48665      * specified, the column's index is used as an index into the Record's data Array.
48666      */
48667     /**
48668      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48669      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48670      */
48671     /**
48672      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48673      * Defaults to the value of the {@link #defaultSortable} property.
48674      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48675      */
48676     /**
48677      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
48678      */
48679     /**
48680      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
48681      */
48682     /**
48683      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48684      */
48685     /**
48686      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48687      */
48688     /**
48689      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48690      * given the cell's data value. See {@link #setRenderer}. If not specified, the
48691      * default renderer uses the raw data value.
48692      */
48693        /**
48694      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
48695      */
48696     /**
48697      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
48698      */
48699
48700     /**
48701      * Returns the id of the column at the specified index.
48702      * @param {Number} index The column index
48703      * @return {String} the id
48704      */
48705     getColumnId : function(B){
48706         return  this.config[B].id;
48707     },
48708
48709     /**
48710      * Returns the column for a specified id.
48711      * @param {String} id The column id
48712      * @return {Object} the column
48713      */
48714     getColumnById : function(id){
48715         return  this.lookup[id];
48716     },
48717
48718     /**
48719      * Returns the index for a specified column id.
48720      * @param {String} id The column id
48721      * @return {Number} the index, or -1 if not found
48722      */
48723     getIndexById : function(id){
48724         for(var  i = 0, len = this.config.length; i < len; i++){
48725             if(this.config[i].id == id){
48726                 return  i;
48727             }
48728         }
48729         return  -1;
48730     },
48731     /**
48732      * Returns the index for a specified column dataIndex.
48733      * @param {String} dataIndex The column dataIndex
48734      * @return {Number} the index, or -1 if not found
48735      */
48736     
48737     findColumnIndex : function(C){
48738         for(var  i = 0, len = this.config.length; i < len; i++){
48739             if(this.config[i].dataIndex == C){
48740                 return  i;
48741             }
48742         }
48743         return  -1;
48744     },
48745     
48746     
48747     moveColumn : function(D, E){
48748         var  c = this.config[D];
48749         this.config.splice(D, 1);
48750         this.config.splice(E, 0, c);
48751         this.dataMap = null;
48752         this.fireEvent("columnmoved", this, D, E);
48753     },
48754
48755     isLocked : function(F){
48756         return  this.config[F].locked === true;
48757     },
48758
48759     setLocked : function(G, H, I){
48760         if(this.isLocked(G) == H){
48761             return;
48762         }
48763
48764         this.config[G].locked = H;
48765         if(!I){
48766             this.fireEvent("columnlockchange", this, G, H);
48767         }
48768     },
48769
48770     getTotalLockedWidth : function(){
48771         var  J = 0;
48772         for(var  i = 0; i < this.config.length; i++){
48773             if(this.isLocked(i) && !this.isHidden(i)){
48774                 this.totalWidth += this.getColumnWidth(i);
48775             }
48776         }
48777         return  J;
48778     },
48779
48780     getLockedCount : function(){
48781         for(var  i = 0, len = this.config.length; i < len; i++){
48782             if(!this.isLocked(i)){
48783                 return  i;
48784             }
48785         }
48786     },
48787
48788     /**
48789      * Returns the number of columns.
48790      * @return {Number}
48791      */
48792     getColumnCount : function(K){
48793         if(K === true){
48794             var  c = 0;
48795             for(var  i = 0, len = this.config.length; i < len; i++){
48796                 if(!this.isHidden(i)){
48797                     c++;
48798                 }
48799             }
48800             return  c;
48801         }
48802         return  this.config.length;
48803     },
48804
48805     /**
48806      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
48807      * @param {Function} fn
48808      * @param {Object} scope (optional)
48809      * @return {Array} result
48810      */
48811     getColumnsBy : function(fn, L){
48812         var  r = [];
48813         for(var  i = 0, len = this.config.length; i < len; i++){
48814             var  c = this.config[i];
48815             if(fn.call(L||this, c, i) === true){
48816                 r[r.length] = c;
48817             }
48818         }
48819         return  r;
48820     },
48821
48822     /**
48823      * Returns true if the specified column is sortable.
48824      * @param {Number} col The column index
48825      * @return {Boolean}
48826      */
48827     isSortable : function(M){
48828         if(typeof  this.config[M].sortable == "undefined"){
48829             return  this.defaultSortable;
48830         }
48831         return  this.config[M].sortable;
48832     },
48833
48834     /**
48835      * Returns the rendering (formatting) function defined for the column.
48836      * @param {Number} col The column index.
48837      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
48838      */
48839     getRenderer : function(N){
48840         if(!this.config[N].renderer){
48841             return  Roo.grid.ColumnModel.defaultRenderer;
48842         }
48843         return  this.config[N].renderer;
48844     },
48845
48846     /**
48847      * Sets the rendering (formatting) function for a column.
48848      * @param {Number} col The column index
48849      * @param {Function} fn The function to use to process the cell's raw data
48850      * to return HTML markup for the grid view. The render function is called with
48851      * the following parameters:<ul>
48852      * <li>Data value.</li>
48853      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48854      * <li>css A CSS style string to apply to the table cell.</li>
48855      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48856      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48857      * <li>Row index</li>
48858      * <li>Column index</li>
48859      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48860      */
48861     setRenderer : function(O, fn){
48862         this.config[O].renderer = fn;
48863     },
48864
48865     /**
48866      * Returns the width for the specified column.
48867      * @param {Number} col The column index
48868      * @return {Number}
48869      */
48870     getColumnWidth : function(P){
48871         return  this.config[P].width || this.defaultWidth;
48872     },
48873
48874     /**
48875      * Sets the width for a column.
48876      * @param {Number} col The column index
48877      * @param {Number} width The new width
48878      */
48879     setColumnWidth : function(Q, R, S){
48880         this.config[Q].width = R;
48881         this.totalWidth = null;
48882         if(!S){
48883              this.fireEvent("widthchange", this, Q, R);
48884         }
48885     },
48886
48887     /**
48888      * Returns the total width of all columns.
48889      * @param {Boolean} includeHidden True to include hidden column widths
48890      * @return {Number}
48891      */
48892     getTotalWidth : function(T){
48893         if(!this.totalWidth){
48894             this.totalWidth = 0;
48895             for(var  i = 0, len = this.config.length; i < len; i++){
48896                 if(T || !this.isHidden(i)){
48897                     this.totalWidth += this.getColumnWidth(i);
48898                 }
48899             }
48900         }
48901         return  this.totalWidth;
48902     },
48903
48904     /**
48905      * Returns the header for the specified column.
48906      * @param {Number} col The column index
48907      * @return {String}
48908      */
48909     getColumnHeader : function(U){
48910         return  this.config[U].header;
48911     },
48912
48913     /**
48914      * Sets the header for a column.
48915      * @param {Number} col The column index
48916      * @param {String} header The new header
48917      */
48918     setColumnHeader : function(V, W){
48919         this.config[V].header = W;
48920         this.fireEvent("headerchange", this, V, W);
48921     },
48922
48923     /**
48924      * Returns the tooltip for the specified column.
48925      * @param {Number} col The column index
48926      * @return {String}
48927      */
48928     getColumnTooltip : function(X){
48929             return  this.config[X].tooltip;
48930     },
48931     /**
48932      * Sets the tooltip for a column.
48933      * @param {Number} col The column index
48934      * @param {String} tooltip The new tooltip
48935      */
48936     setColumnTooltip : function(Y, Z){
48937             this.config[Y].tooltip = Z;
48938     },
48939
48940     /**
48941      * Returns the dataIndex for the specified column.
48942      * @param {Number} col The column index
48943      * @return {Number}
48944      */
48945     getDataIndex : function(a){
48946         return  this.config[a].dataIndex;
48947     },
48948
48949     /**
48950      * Sets the dataIndex for a column.
48951      * @param {Number} col The column index
48952      * @param {Number} dataIndex The new dataIndex
48953      */
48954     setDataIndex : function(b, d){
48955         this.config[b].dataIndex = d;
48956     },
48957
48958     
48959     
48960     /**
48961      * Returns true if the cell is editable.
48962      * @param {Number} colIndex The column index
48963      * @param {Number} rowIndex The row index
48964      * @return {Boolean}
48965      */
48966     isCellEditable : function(e, f){
48967         return  (this.config[e].editable || (typeof  this.config[e].editable == "undefined" && this.config[e].editor)) ? true : false;
48968     },
48969
48970     /**
48971      * Returns the editor defined for the cell/column.
48972      * return false or null to disable editing.
48973      * @param {Number} colIndex The column index
48974      * @param {Number} rowIndex The row index
48975      * @return {Object}
48976      */
48977     getCellEditor : function(g, h){
48978         return  this.config[g].editor;
48979     },
48980
48981     /**
48982      * Sets if a column is editable.
48983      * @param {Number} col The column index
48984      * @param {Boolean} editable True if the column is editable
48985      */
48986     setEditable : function(j, k){
48987         this.config[j].editable = k;
48988     },
48989
48990
48991     /**
48992      * Returns true if the column is hidden.
48993      * @param {Number} colIndex The column index
48994      * @return {Boolean}
48995      */
48996     isHidden : function(l){
48997         return  this.config[l].hidden;
48998     },
48999
49000
49001     /**
49002      * Returns true if the column width cannot be changed
49003      */
49004     isFixed : function(m){
49005         return  this.config[m].fixed;
49006     },
49007
49008     /**
49009      * Returns true if the column can be resized
49010      * @return {Boolean}
49011      */
49012     isResizable : function(n){
49013         return  n >= 0 && this.config[n].resizable !== false && this.config[n].fixed !== true;
49014     },
49015     /**
49016      * Sets if a column is hidden.
49017      * @param {Number} colIndex The column index
49018      * @param {Boolean} hidden True if the column is hidden
49019      */
49020     setHidden : function(o, p){
49021         this.config[o].hidden = p;
49022         this.totalWidth = null;
49023         this.fireEvent("hiddenchange", this, o, p);
49024     },
49025
49026     /**
49027      * Sets the editor for a column.
49028      * @param {Number} col The column index
49029      * @param {Object} editor The editor object
49030      */
49031     setEditor : function(q, s){
49032         this.config[q].editor = s;
49033     }
49034 });
49035
49036 Roo.grid.ColumnModel.defaultRenderer = function(t){
49037         if(typeof  t == "string" && t.length < 1){
49038             return  "&#160;";
49039         }
49040         return  t;
49041 };
49042
49043 // Alias for backwards compatibility
49044 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49045
49046 /*
49047  * Based on:
49048  * Ext JS Library 1.1.1
49049  * Copyright(c) 2006-2007, Ext JS, LLC.
49050  *
49051  * Originally Released Under LGPL - original licence link has changed is not relivant.
49052  *
49053  * Fork - LGPL
49054  * <script type="text/javascript">
49055  */
49056
49057 /**
49058  * @class Roo.grid.AbstractSelectionModel
49059  * @extends Roo.util.Observable
49060  * Abstract base class for grid SelectionModels.  It provides the interface that should be
49061  * implemented by descendant classes.  This class should not be directly instantiated.
49062  * @constructor
49063  */
49064 Roo.grid.AbstractSelectionModel = function(){
49065     this.locked = false;
49066     Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49067 };
49068
49069 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable,  {
49070     /** @ignore Called by the grid automatically. Do not call directly. */
49071     init : function(A){
49072         this.grid = A;
49073         this.initEvents();
49074     },
49075
49076     /**
49077      * Locks the selections.
49078      */
49079     lock : function(){
49080         this.locked = true;
49081     },
49082
49083     /**
49084      * Unlocks the selections.
49085      */
49086     unlock : function(){
49087         this.locked = false;
49088     },
49089
49090     /**
49091      * Returns true if the selections are locked.
49092      * @return {Boolean}
49093      */
49094     isLocked : function(){
49095         return  this.locked;
49096     }
49097 });
49098 /*
49099  * Based on:
49100  * Ext JS Library 1.1.1
49101  * Copyright(c) 2006-2007, Ext JS, LLC.
49102  *
49103  * Originally Released Under LGPL - original licence link has changed is not relivant.
49104  *
49105  * Fork - LGPL
49106  * <script type="text/javascript">
49107  */
49108 /**
49109  * @extends Roo.grid.AbstractSelectionModel
49110  * @class Roo.grid.RowSelectionModel
49111  * The default SelectionModel used by {@link Roo.grid.Grid}.
49112  * It supports multiple selections and keyboard selection/navigation. 
49113  * @constructor
49114  * @param {Object} config
49115  */
49116 Roo.grid.RowSelectionModel = function(A){
49117     Roo.apply(this, A);
49118     this.selections = new  Roo.util.MixedCollection(false, function(o){
49119         return  o.id;
49120     });
49121
49122     this.last = false;
49123     this.lastActive = false;
49124
49125     this.addEvents({
49126         /**
49127              * @event selectionchange
49128              * Fires when the selection changes
49129              * @param {SelectionModel} this
49130              */
49131             "selectionchange" : true,
49132         /**
49133              * @event afterselectionchange
49134              * Fires after the selection changes (eg. by key press or clicking)
49135              * @param {SelectionModel} this
49136              */
49137             "afterselectionchange" : true,
49138         /**
49139              * @event beforerowselect
49140              * Fires when a row is selected being selected, return false to cancel.
49141              * @param {SelectionModel} this
49142              * @param {Number} rowIndex The selected index
49143              * @param {Boolean} keepExisting False if other selections will be cleared
49144              */
49145             "beforerowselect" : true,
49146         /**
49147              * @event rowselect
49148              * Fires when a row is selected.
49149              * @param {SelectionModel} this
49150              * @param {Number} rowIndex The selected index
49151              * @param {Roo.data.Record} r The record
49152              */
49153             "rowselect" : true,
49154         /**
49155              * @event rowdeselect
49156              * Fires when a row is deselected.
49157              * @param {SelectionModel} this
49158              * @param {Number} rowIndex The selected index
49159              */
49160         "rowdeselect" : true
49161     });
49162     Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49163     this.locked = false;
49164 };
49165
49166 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
49167     /**
49168      * @cfg {Boolean} singleSelect
49169      * True to allow selection of only one row at a time (defaults to false)
49170      */
49171     singleSelect : false,
49172
49173     // private
49174     initEvents : function(){
49175
49176         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49177             this.grid.on("mousedown", this.handleMouseDown, this);
49178         }else { // allow click to work like normal
49179             this.grid.on("rowclick", this.handleDragableRowClick, this);
49180         }
49181
49182
49183         this.rowNav = new  Roo.KeyNav(this.grid.getGridEl(), {
49184             "up" : function(e){
49185                 if(!e.shiftKey){
49186                     this.selectPrevious(e.shiftKey);
49187                 }else  if(this.last !== false && this.lastActive !== false){
49188                     var  last = this.last;
49189                     this.selectRange(this.last,  this.lastActive-1);
49190                     this.grid.getView().focusRow(this.lastActive);
49191                     if(last !== false){
49192                         this.last = last;
49193                     }
49194                 }else {
49195                     this.selectFirstRow();
49196                 }
49197
49198                 this.fireEvent("afterselectionchange", this);
49199             },
49200             "down" : function(e){
49201                 if(!e.shiftKey){
49202                     this.selectNext(e.shiftKey);
49203                 }else  if(this.last !== false && this.lastActive !== false){
49204                     var  last = this.last;
49205                     this.selectRange(this.last,  this.lastActive+1);
49206                     this.grid.getView().focusRow(this.lastActive);
49207                     if(last !== false){
49208                         this.last = last;
49209                     }
49210                 }else {
49211                     this.selectFirstRow();
49212                 }
49213
49214                 this.fireEvent("afterselectionchange", this);
49215             },
49216             scope: this
49217         });
49218
49219         var  B = this.grid.view;
49220         B.on("refresh", this.onRefresh, this);
49221         B.on("rowupdated", this.onRowUpdated, this);
49222         B.on("rowremoved", this.onRemove, this);
49223     },
49224
49225     // private
49226     onRefresh : function(){
49227         var  ds = this.grid.dataSource, i, v = this.grid.view;
49228         var  s = this.selections;
49229         s.each(function(r){
49230             if((i = ds.indexOfId(r.id)) != -1){
49231                 v.onRowSelect(i);
49232             }else {
49233                 s.remove(r);
49234             }
49235         });
49236     },
49237
49238     // private
49239     onRemove : function(v, C, r){
49240         this.selections.remove(r);
49241     },
49242
49243     // private
49244     onRowUpdated : function(v, D, r){
49245         if(this.isSelected(r)){
49246             v.onRowSelect(D);
49247         }
49248     },
49249
49250     /**
49251      * Select records.
49252      * @param {Array} records The records to select
49253      * @param {Boolean} keepExisting (optional) True to keep existing selections
49254      */
49255     selectRecords : function(E, F){
49256         if(!F){
49257             this.clearSelections();
49258         }
49259         var  ds = this.grid.dataSource;
49260         for(var  i = 0, len = E.length; i < len; i++){
49261             this.selectRow(ds.indexOf(E[i]), true);
49262         }
49263     },
49264
49265     /**
49266      * Gets the number of selected rows.
49267      * @return {Number}
49268      */
49269     getCount : function(){
49270         return  this.selections.length;
49271     },
49272
49273     /**
49274      * Selects the first row in the grid.
49275      */
49276     selectFirstRow : function(){
49277         this.selectRow(0);
49278     },
49279
49280     /**
49281      * Select the last row.
49282      * @param {Boolean} keepExisting (optional) True to keep existing selections
49283      */
49284     selectLastRow : function(G){
49285         this.selectRow(this.grid.dataSource.getCount() - 1, G);
49286     },
49287
49288     /**
49289      * Selects the row immediately following the last selected row.
49290      * @param {Boolean} keepExisting (optional) True to keep existing selections
49291      */
49292     selectNext : function(H){
49293         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49294             this.selectRow(this.last+1, H);
49295             this.grid.getView().focusRow(this.last);
49296         }
49297     },
49298
49299     /**
49300      * Selects the row that precedes the last selected row.
49301      * @param {Boolean} keepExisting (optional) True to keep existing selections
49302      */
49303     selectPrevious : function(I){
49304         if(this.last){
49305             this.selectRow(this.last-1, I);
49306             this.grid.getView().focusRow(this.last);
49307         }
49308     },
49309
49310     /**
49311      * Returns the selected records
49312      * @return {Array} Array of selected records
49313      */
49314     getSelections : function(){
49315         return  [].concat(this.selections.items);
49316     },
49317
49318     /**
49319      * Returns the first selected record.
49320      * @return {Record}
49321      */
49322     getSelected : function(){
49323         return  this.selections.itemAt(0);
49324     },
49325
49326
49327     /**
49328      * Clears all selections.
49329      */
49330     clearSelections : function(J){
49331         if(this.locked) return;
49332         if(J !== true){
49333             var  ds = this.grid.dataSource;
49334             var  s = this.selections;
49335             s.each(function(r){
49336                 this.deselectRow(ds.indexOfId(r.id));
49337             }, this);
49338             s.clear();
49339         }else {
49340             this.selections.clear();
49341         }
49342
49343         this.last = false;
49344     },
49345
49346
49347     /**
49348      * Selects all rows.
49349      */
49350     selectAll : function(){
49351         if(this.locked) return;
49352         this.selections.clear();
49353         for(var  i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49354             this.selectRow(i, true);
49355         }
49356     },
49357
49358     /**
49359      * Returns True if there is a selection.
49360      * @return {Boolean}
49361      */
49362     hasSelection : function(){
49363         return  this.selections.length > 0;
49364     },
49365
49366     /**
49367      * Returns True if the specified row is selected.
49368      * @param {Number/Record} record The record or index of the record to check
49369      * @return {Boolean}
49370      */
49371     isSelected : function(K){
49372         var  r = typeof  K == "number" ? this.grid.dataSource.getAt(K) : K;
49373         return  (r && this.selections.key(r.id) ? true : false);
49374     },
49375
49376     /**
49377      * Returns True if the specified record id is selected.
49378      * @param {String} id The id of record to check
49379      * @return {Boolean}
49380      */
49381     isIdSelected : function(id){
49382         return  (this.selections.key(id) ? true : false);
49383     },
49384
49385     // private
49386     handleMouseDown : function(e, t){
49387         var  L = this.grid.getView(), M;
49388         if(this.isLocked() || (M = L.findRowIndex(t)) === false){
49389             return;
49390         };
49391         if(e.shiftKey && this.last !== false){
49392             var  last = this.last;
49393             this.selectRange(last, M, e.ctrlKey);
49394             this.last = last; // reset the last
49395             L.focusRow(M);
49396         }else {
49397             var  isSelected = this.isSelected(M);
49398             if(e.button !== 0 && isSelected){
49399                 L.focusRow(M);
49400             }else  if(e.ctrlKey && isSelected){
49401                 this.deselectRow(M);
49402             }else  if(!isSelected){
49403                 this.selectRow(M, e.button === 0 && (e.ctrlKey || e.shiftKey));
49404                 L.focusRow(M);
49405             }
49406         }
49407
49408         this.fireEvent("afterselectionchange", this);
49409     },
49410     // private
49411     handleDragableRowClick :  function(N, O, e) 
49412     {
49413         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49414             this.selectRow(O, false);
49415             N.view.focusRow(O);
49416              this.fireEvent("afterselectionchange", this);
49417         }
49418     },
49419     
49420     /**
49421      * Selects multiple rows.
49422      * @param {Array} rows Array of the indexes of the row to select
49423      * @param {Boolean} keepExisting (optional) True to keep existing selections
49424      */
49425     selectRows : function(P, Q){
49426         if(!Q){
49427             this.clearSelections();
49428         }
49429         for(var  i = 0, len = P.length; i < len; i++){
49430             this.selectRow(P[i], true);
49431         }
49432     },
49433
49434     /**
49435      * Selects a range of rows. All rows in between startRow and endRow are also selected.
49436      * @param {Number} startRow The index of the first row in the range
49437      * @param {Number} endRow The index of the last row in the range
49438      * @param {Boolean} keepExisting (optional) True to retain existing selections
49439      */
49440     selectRange : function(R, S, T){
49441         if(this.locked) return;
49442         if(!T){
49443             this.clearSelections();
49444         }
49445         if(R <= S){
49446             for(var  i = R; i <= S; i++){
49447                 this.selectRow(i, true);
49448             }
49449         }else {
49450             for(var  i = R; i >= S; i--){
49451                 this.selectRow(i, true);
49452             }
49453         }
49454     },
49455
49456     /**
49457      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49458      * @param {Number} startRow The index of the first row in the range
49459      * @param {Number} endRow The index of the last row in the range
49460      */
49461     deselectRange : function(U, V, W){
49462         if(this.locked) return;
49463         for(var  i = U; i <= V; i++){
49464             this.deselectRow(i, W);
49465         }
49466     },
49467
49468     /**
49469      * Selects a row.
49470      * @param {Number} row The index of the row to select
49471      * @param {Boolean} keepExisting (optional) True to keep existing selections
49472      */
49473     selectRow : function(X, Y, Z){
49474         if(this.locked || (X < 0 || X >= this.grid.dataSource.getCount())) return;
49475         if(this.fireEvent("beforerowselect", this, X, Y) !== false){
49476             if(!Y || this.singleSelect){
49477                 this.clearSelections();
49478             }
49479             var  r = this.grid.dataSource.getAt(X);
49480             this.selections.add(r);
49481             this.last = this.lastActive = X;
49482             if(!Z){
49483                 this.grid.getView().onRowSelect(X);
49484             }
49485
49486             this.fireEvent("rowselect", this, X, r);
49487             this.fireEvent("selectionchange", this);
49488         }
49489     },
49490
49491     /**
49492      * Deselects a row.
49493      * @param {Number} row The index of the row to deselect
49494      */
49495     deselectRow : function(a, b){
49496         if(this.locked) return;
49497         if(this.last == a){
49498             this.last = false;
49499         }
49500         if(this.lastActive == a){
49501             this.lastActive = false;
49502         }
49503         var  r = this.grid.dataSource.getAt(a);
49504         this.selections.remove(r);
49505         if(!b){
49506             this.grid.getView().onRowDeselect(a);
49507         }
49508
49509         this.fireEvent("rowdeselect", this, a);
49510         this.fireEvent("selectionchange", this);
49511     },
49512
49513     // private
49514     restoreLast : function(){
49515         if(this._last){
49516             this.last = this._last;
49517         }
49518     },
49519
49520     // private
49521     acceptsNav : function(c, d, cm){
49522         return  !cm.isHidden(d) && cm.isCellEditable(d, c);
49523     },
49524
49525     // private
49526     onEditorKey : function(f, e){
49527         var  k = e.getKey(), h, g = this.grid, ed = g.activeEditor;
49528         if(k == e.TAB){
49529             e.stopEvent();
49530             ed.completeEdit();
49531             if(e.shiftKey){
49532                 h = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49533             }else {
49534                 h = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49535             }
49536         }else  if(k == e.ENTER && !e.ctrlKey){
49537             e.stopEvent();
49538             ed.completeEdit();
49539             if(e.shiftKey){
49540                 h = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49541             }else {
49542                 h = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49543             }
49544         }else  if(k == e.ESC){
49545             ed.cancelEdit();
49546         }
49547         if(h){
49548             g.startEditing(h[0], h[1]);
49549         }
49550     }
49551 });
49552 /*
49553  * Based on:
49554  * Ext JS Library 1.1.1
49555  * Copyright(c) 2006-2007, Ext JS, LLC.
49556  *
49557  * Originally Released Under LGPL - original licence link has changed is not relivant.
49558  *
49559  * Fork - LGPL
49560  * <script type="text/javascript">
49561  */
49562 /**
49563  * @class Roo.grid.CellSelectionModel
49564  * @extends Roo.grid.AbstractSelectionModel
49565  * This class provides the basic implementation for cell selection in a grid.
49566  * @constructor
49567  * @param {Object} config The object containing the configuration of this model.
49568  */
49569 Roo.grid.CellSelectionModel = function(A){
49570     Roo.apply(this, A);
49571
49572     this.selection = null;
49573
49574     this.addEvents({
49575         /**
49576              * @event beforerowselect
49577              * Fires before a cell is selected.
49578              * @param {SelectionModel} this
49579              * @param {Number} rowIndex The selected row index
49580              * @param {Number} colIndex The selected cell index
49581              */
49582             "beforecellselect" : true,
49583         /**
49584              * @event cellselect
49585              * Fires when a cell is selected.
49586              * @param {SelectionModel} this
49587              * @param {Number} rowIndex The selected row index
49588              * @param {Number} colIndex The selected cell index
49589              */
49590             "cellselect" : true,
49591         /**
49592              * @event selectionchange
49593              * Fires when the active selection changes.
49594              * @param {SelectionModel} this
49595              * @param {Object} selection null for no selection or an object (o) with two properties
49596                 <ul>
49597                 <li>o.record: the record object for the row the selection is in</li>
49598                 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49599                 </ul>
49600              */
49601             "selectionchange" : true
49602     });
49603     Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49604 };
49605
49606 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
49607
49608     /** @ignore */
49609     initEvents : function(){
49610         this.grid.on("mousedown", this.handleMouseDown, this);
49611         this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49612         var  B = this.grid.view;
49613         B.on("refresh", this.onViewChange, this);
49614         B.on("rowupdated", this.onRowUpdated, this);
49615         B.on("beforerowremoved", this.clearSelections, this);
49616         B.on("beforerowsinserted", this.clearSelections, this);
49617         if(this.grid.isEditor){
49618             this.grid.on("beforeedit", this.beforeEdit,  this);
49619         }
49620     },
49621
49622         //private
49623     beforeEdit : function(e){
49624         this.select(e.row, e.column, false, true, e.record);
49625     },
49626
49627         //private
49628     onRowUpdated : function(v, C, r){
49629         if(this.selection && this.selection.record == r){
49630             v.onCellSelect(C, this.selection.cell[1]);
49631         }
49632     },
49633
49634         //private
49635     onViewChange : function(){
49636         this.clearSelections(true);
49637     },
49638
49639         /**
49640          * Returns the currently selected cell,.
49641          * @return {Array} The selected cell (row, column) or null if none selected.
49642          */
49643     getSelectedCell : function(){
49644         return  this.selection ? this.selection.cell : null;
49645     },
49646
49647     /**
49648      * Clears all selections.
49649      * @param {Boolean} true to prevent the gridview from being notified about the change.
49650      */
49651     clearSelections : function(D){
49652         var  s = this.selection;
49653         if(s){
49654             if(D !== true){
49655                 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49656             }
49657
49658             this.selection = null;
49659             this.fireEvent("selectionchange", this, null);
49660         }
49661     },
49662
49663     /**
49664      * Returns true if there is a selection.
49665      * @return {Boolean}
49666      */
49667     hasSelection : function(){
49668         return  this.selection ? true : false;
49669     },
49670
49671     /** @ignore */
49672     handleMouseDown : function(e, t){
49673         var  v = this.grid.getView();
49674         if(this.isLocked()){
49675             return;
49676         };
49677         var  E = v.findRowIndex(t);
49678         var  F = v.findCellIndex(t);
49679         if(E !== false && F !== false){
49680             this.select(E, F);
49681         }
49682     },
49683
49684     /**
49685      * Selects a cell.
49686      * @param {Number} rowIndex
49687      * @param {Number} collIndex
49688      */
49689     select : function(G, H, I, J, /*internal*/ r){
49690         if(this.fireEvent("beforecellselect", this, G, H) !== false){
49691             this.clearSelections();
49692             r = r || this.grid.dataSource.getAt(G);
49693             this.selection = {
49694                 record : r,
49695                 cell : [G, H]
49696             };
49697             if(!I){
49698                 var  v = this.grid.getView();
49699                 v.onCellSelect(G, H);
49700                 if(J !== true){
49701                     v.focusCell(G, H);
49702                 }
49703             }
49704
49705             this.fireEvent("cellselect", this, G, H);
49706             this.fireEvent("selectionchange", this, this.selection);
49707         }
49708     },
49709
49710         //private
49711     isSelectable : function(K, L, cm){
49712         return  !cm.isHidden(L);
49713     },
49714
49715     /** @ignore */
49716     handleKeyDown : function(e){
49717         if(!e.isNavKeyPress()){
49718             return;
49719         }
49720         var  g = this.grid, s = this.selection;
49721         if(!s){
49722             e.stopEvent();
49723             var  F = g.walkCells(0, 0, 1, this.isSelectable,  this);
49724             if(F){
49725                 this.select(F[0], F[1]);
49726             }
49727             return;
49728         }
49729         var  sm = this;
49730         var  M = function(O, P, Q){
49731             return  g.walkCells(O, P, Q, sm.isSelectable,  sm);
49732         };
49733         var  k = e.getKey(), r = s.cell[0], c = s.cell[1];
49734         var  N;
49735
49736         switch(k){
49737              case  e.TAB:
49738                  if(e.shiftKey){
49739                      N = M(r, c-1, -1);
49740                  }else {
49741                      N = M(r, c+1, 1);
49742                  }
49743              break;
49744              case  e.DOWN:
49745                  N = M(r+1, c, 1);
49746              break;
49747              case  e.UP:
49748                  N = M(r-1, c, -1);
49749              break;
49750              case  e.RIGHT:
49751                  N = M(r, c+1, 1);
49752              break;
49753              case  e.LEFT:
49754                  N = M(r, c-1, -1);
49755              break;
49756              case  e.ENTER:
49757                  if(g.isEditor && !g.editing){
49758                     g.startEditing(r, c);
49759                     e.stopEvent();
49760                     return;
49761                 }
49762              break;
49763         };
49764         if(N){
49765             this.select(N[0], N[1]);
49766             e.stopEvent();
49767         }
49768     },
49769
49770     acceptsNav : function(O, P, cm){
49771         return  !cm.isHidden(P) && cm.isCellEditable(P, O);
49772     },
49773
49774     onEditorKey : function(Q, e){
49775         var  k = e.getKey(), R, g = this.grid, ed = g.activeEditor;
49776         if(k == e.TAB){
49777             if(e.shiftKey){
49778                 R = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49779             }else {
49780                 R = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49781             }
49782
49783             e.stopEvent();
49784         }else  if(k == e.ENTER && !e.ctrlKey){
49785             ed.completeEdit();
49786             e.stopEvent();
49787         }else  if(k == e.ESC){
49788             ed.cancelEdit();
49789         }
49790         if(R){
49791             g.startEditing(R[0], R[1]);
49792         }
49793     }
49794 });
49795 /*
49796  * Based on:
49797  * Ext JS Library 1.1.1
49798  * Copyright(c) 2006-2007, Ext JS, LLC.
49799  *
49800  * Originally Released Under LGPL - original licence link has changed is not relivant.
49801  *
49802  * Fork - LGPL
49803  * <script type="text/javascript">
49804  */
49805  
49806 /**
49807  * @class Roo.grid.EditorGrid
49808  * @extends Roo.grid.Grid
49809  * Class for creating and editable grid.
49810  * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered - 
49811  * The container MUST have some type of size defined for the grid to fill. The container will be 
49812  * automatically set to position relative if it isn't already.
49813  * @param {Object} dataSource The data model to bind to
49814  * @param {Object} colModel The column model with info about this grid's columns
49815  */
49816 Roo.grid.EditorGrid = function(A, B){
49817     Roo.grid.EditorGrid.superclass.constructor.call(this, A, B);
49818     this.getGridEl().addClass("xedit-grid");
49819
49820     if(!this.selModel){
49821         this.selModel = new  Roo.grid.CellSelectionModel();
49822     }
49823
49824
49825     this.activeEditor = null;
49826
49827         this.addEvents({
49828             /**
49829              * @event beforeedit
49830              * Fires before cell editing is triggered. The edit event object has the following properties <br />
49831              * <ul style="padding:5px;padding-left:16px;">
49832              * <li>grid - This grid</li>
49833              * <li>record - The record being edited</li>
49834              * <li>field - The field name being edited</li>
49835              * <li>value - The value for the field being edited.</li>
49836              * <li>row - The grid row index</li>
49837              * <li>column - The grid column index</li>
49838              * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49839              * </ul>
49840              * @param {Object} e An edit event (see above for description)
49841              */
49842             "beforeedit" : true,
49843             /**
49844              * @event afteredit
49845              * Fires after a cell is edited. <br />
49846              * <ul style="padding:5px;padding-left:16px;">
49847              * <li>grid - This grid</li>
49848              * <li>record - The record being edited</li>
49849              * <li>field - The field name being edited</li>
49850              * <li>value - The value being set</li>
49851              * <li>originalValue - The original value for the field, before the edit.</li>
49852              * <li>row - The grid row index</li>
49853              * <li>column - The grid column index</li>
49854              * </ul>
49855              * @param {Object} e An edit event (see above for description)
49856              */
49857             "afteredit" : true,
49858             /**
49859              * @event validateedit
49860              * Fires after a cell is edited, but before the value is set in the record. 
49861          * You can use this to modify the value being set in the field, Return false
49862              * to cancel the change. The edit event object has the following properties <br />
49863              * <ul style="padding:5px;padding-left:16px;">
49864          * <li>editor - This editor</li>
49865              * <li>grid - This grid</li>
49866              * <li>record - The record being edited</li>
49867              * <li>field - The field name being edited</li>
49868              * <li>value - The value being set</li>
49869              * <li>originalValue - The original value for the field, before the edit.</li>
49870              * <li>row - The grid row index</li>
49871              * <li>column - The grid column index</li>
49872              * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49873              * </ul>
49874              * @param {Object} e An edit event (see above for description)
49875              */
49876             "validateedit" : true
49877         });
49878     this.on("bodyscroll", this.stopEditing,  this);
49879     this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick,  this);
49880 };
49881
49882 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49883     /**
49884      * @cfg {Number} clicksToEdit
49885      * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49886      */
49887     clicksToEdit: 2,
49888
49889     // private
49890     isEditor : true,
49891     // private
49892     trackMouseOver: false, // causes very odd FF errors
49893
49894     onCellDblClick : function(g, C, D){
49895         this.startEditing(C, D);
49896     },
49897
49898     onEditComplete : function(ed, E, F){
49899         this.editing = false;
49900         this.activeEditor = null;
49901         ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49902         var  r = ed.record;
49903         var  G = this.colModel.getDataIndex(ed.col);
49904         var  e = {
49905             grid: this,
49906             record: r,
49907             field: G,
49908             originalValue: F,
49909             value: E,
49910             row: ed.row,
49911             column: ed.col,
49912             cancel:false,
49913             editor: ed
49914         };
49915         if(String(E) !== String(F)){
49916             
49917             if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49918                 r.set(G, e.value);
49919                 delete  e.cancel; //?? why!!!
49920                 this.fireEvent("afteredit", e);
49921             }
49922         } else  {
49923             this.fireEvent("afteredit", e); // always fir it!
49924         }
49925
49926         this.view.focusCell(ed.row, ed.col);
49927     },
49928
49929     /**
49930      * Starts editing the specified for the specified row/column
49931      * @param {Number} rowIndex
49932      * @param {Number} colIndex
49933      */
49934     startEditing : function(H, I){
49935         this.stopEditing();
49936         if(this.colModel.isCellEditable(I, H)){
49937             this.view.ensureVisible(H, I, true);
49938             var  r = this.dataSource.getAt(H);
49939             var  G = this.colModel.getDataIndex(I);
49940             var  e = {
49941                 grid: this,
49942                 record: r,
49943                 field: G,
49944                 value: r.data[G],
49945                 row: H,
49946                 column: I,
49947                 cancel:false
49948             };
49949             if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49950                 this.editing = true;
49951                 var  ed = this.colModel.getCellEditor(I, H);
49952                 if (!ed) {
49953                     return;
49954                 }
49955                 if(!ed.rendered){
49956                     ed.render(ed.parentEl || document.body);
49957                 }
49958                 (function(){ // complex but required for focus issues in safari, ie and opera
49959                     ed.row = H;
49960                     ed.col = I;
49961                     ed.record = r;
49962                     ed.on("complete", this.onEditComplete, this, {single: true});
49963                     ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49964                     this.activeEditor = ed;
49965                     var  v = r.data[G];
49966                     ed.startEdit(this.view.getCell(H, I), v);
49967                 }).defer(50, this);
49968             }
49969         }
49970     },
49971         
49972     /**
49973      * Stops any active editing
49974      */
49975     stopEditing : function(){
49976         if(this.activeEditor){
49977             this.activeEditor.completeEdit();
49978         }
49979
49980         this.activeEditor = null;
49981     }
49982 });
49983 /*
49984  * Based on:
49985  * Ext JS Library 1.1.1
49986  * Copyright(c) 2006-2007, Ext JS, LLC.
49987  *
49988  * Originally Released Under LGPL - original licence link has changed is not relivant.
49989  *
49990  * Fork - LGPL
49991  * <script type="text/javascript">
49992  */
49993
49994 // private - not really -- you end up using it !
49995 // This is a support class used internally by the Grid components
49996
49997 /**
49998  * @class Roo.grid.GridEditor
49999  * @extends Roo.Editor
50000  * Class for creating and editable grid elements.
50001  * @param {Object} config any settings (must include field)
50002  */
50003 Roo.grid.GridEditor = function(A, B){
50004     if (!B && A.field) {
50005         B = A;
50006         A = Roo.factory(B.field, Roo.form);
50007     }
50008
50009     Roo.grid.GridEditor.superclass.constructor.call(this, A, B);
50010     A.monitorTab = false;
50011 };
50012
50013 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50014     
50015     /**
50016      * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50017      */
50018     
50019     alignment: "tl-tl",
50020     autoSize: "width",
50021     hideEl : false,
50022     cls: "x-small-editor x-grid-editor",
50023     shim:false,
50024     shadow:"frame"
50025 });
50026 /*
50027  * Based on:
50028  * Ext JS Library 1.1.1
50029  * Copyright(c) 2006-2007, Ext JS, LLC.
50030  *
50031  * Originally Released Under LGPL - original licence link has changed is not relivant.
50032  *
50033  * Fork - LGPL
50034  * <script type="text/javascript">
50035  */
50036   
50037
50038   
50039 Roo.grid.PropertyRecord = Roo.data.Record.create([
50040     {name:'name',type:'string'},  'value'
50041 ]);
50042
50043
50044 Roo.grid.PropertyStore = function(A, B){
50045     this.grid = A;
50046     this.store = new  Roo.data.Store({
50047         recordType : Roo.grid.PropertyRecord
50048     });
50049     this.store.on('update', this.onUpdate,  this);
50050     if(B){
50051         this.setSource(B);
50052     }
50053
50054     Roo.grid.PropertyStore.superclass.constructor.call(this);
50055 };
50056
50057
50058
50059 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50060     setSource : function(o){
50061         this.source = o;
50062         this.store.removeAll();
50063         var  C = [];
50064         for(var  k  in  o){
50065             if(this.isEditableValue(o[k])){
50066                 C.push(new  Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50067             }
50068         }
50069
50070         this.store.loadRecords({records: C}, {}, true);
50071     },
50072
50073     onUpdate : function(ds, D, E){
50074         if(E == Roo.data.Record.EDIT){
50075             var  v = D.data['value'];
50076             var  oldValue = D.modified['value'];
50077             if(this.grid.fireEvent('beforepropertychange', this.source, D.id, v, oldValue) !== false){
50078                 this.source[D.id] = v;
50079                 D.commit();
50080                 this.grid.fireEvent('propertychange', this.source, D.id, v, oldValue);
50081             }else {
50082                 D.reject();
50083             }
50084         }
50085     },
50086
50087     getProperty : function(F){
50088        return  this.store.getAt(F);
50089     },
50090
50091     isEditableValue: function(G){
50092         if(G && G  instanceof  Date){
50093             return  true;
50094         }else  if(typeof  G == 'object' || typeof  G == 'function'){
50095             return  false;
50096         }
50097         return  true;
50098     },
50099
50100     setValue : function(H, I){
50101         this.source[H] = I;
50102         this.store.getById(H).set('value', I);
50103     },
50104
50105     getSource : function(){
50106         return  this.source;
50107     }
50108 });
50109
50110 Roo.grid.PropertyColumnModel = function(J, K){
50111     this.grid = J;
50112     var  g = Roo.grid;
50113     g.PropertyColumnModel.superclass.constructor.call(this, [
50114         {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50115         {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50116     ]);
50117     this.store = K;
50118     this.bselect = Roo.DomHelper.append(document.body, {
50119         tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50120             {tag: 'option', value: 'true', html: 'true'},
50121             {tag: 'option', value: 'false', html: 'false'}
50122         ]
50123     });
50124     Roo.id(this.bselect);
50125     var  f = Roo.form;
50126     this.editors = {
50127         'date' : new  g.GridEditor(new  f.DateField({selectOnFocus:true})),
50128         'string' : new  g.GridEditor(new  f.TextField({selectOnFocus:true})),
50129         'number' : new  g.GridEditor(new  f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50130         'int' : new  g.GridEditor(new  f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50131         'boolean' : new  g.GridEditor(new  f.Field({el:this.bselect,selectOnFocus:true}))
50132     };
50133     this.renderCellDelegate = this.renderCell.createDelegate(this);
50134     this.renderPropDelegate = this.renderProp.createDelegate(this);
50135 };
50136
50137 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50138     
50139     
50140     nameText : 'Name',
50141     valueText : 'Value',
50142     
50143     dateFormat : 'm/j/Y',
50144     
50145     
50146     renderDate : function(L){
50147         return  L.dateFormat(this.dateFormat);
50148     },
50149
50150     renderBool : function(M){
50151         return  M ? 'true' : 'false';
50152     },
50153
50154     isCellEditable : function(N, O){
50155         return  N == 1;
50156     },
50157
50158     getRenderer : function(P){
50159         return  P == 1 ?
50160             this.renderCellDelegate : this.renderPropDelegate;
50161     },
50162
50163     renderProp : function(v){
50164         return  this.getPropertyName(v);
50165     },
50166
50167     renderCell : function(Q){
50168         var  rv = Q;
50169         if(Q  instanceof  Date){
50170             rv = this.renderDate(Q);
50171         }else  if(typeof  Q == 'boolean'){
50172             rv = this.renderBool(Q);
50173         }
50174         return  Roo.util.Format.htmlEncode(rv);
50175     },
50176
50177     getPropertyName : function(R){
50178         var  pn = this.grid.propertyNames;
50179         return  pn && pn[R] ? pn[R] : R;
50180     },
50181
50182     getCellEditor : function(S, T){
50183         var  p = this.store.getProperty(T);
50184         var  n = p.data['name'], U = p.data['value'];
50185         
50186         if(typeof(this.grid.customEditors[n]) == 'string'){
50187             return  this.editors[this.grid.customEditors[n]];
50188         }
50189         if(typeof(this.grid.customEditors[n]) != 'undefined'){
50190             return  this.grid.customEditors[n];
50191         }
50192         if(U  instanceof  Date){
50193             return  this.editors['date'];
50194         }else  if(typeof  U == 'number'){
50195             return  this.editors['number'];
50196         }else  if(typeof  U == 'boolean'){
50197             return  this.editors['boolean'];
50198         }else {
50199             return  this.editors['string'];
50200         }
50201     }
50202 });
50203
50204 /**
50205  * @class Roo.grid.PropertyGrid
50206  * @extends Roo.grid.EditorGrid
50207  * This class represents the  interface of a component based property grid control.
50208  * <br><br>Usage:<pre><code>
50209  var grid = new Roo.grid.PropertyGrid("my-container-id", {
50210       
50211  });
50212  // set any options
50213  grid.render();
50214  * </code></pre>
50215   
50216  * @constructor
50217  * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50218  * The container MUST have some type of size defined for the grid to fill. The container will be
50219  * automatically set to position relative if it isn't already.
50220  * @param {Object} config A config object that sets properties on this grid.
50221  */
50222 Roo.grid.PropertyGrid = function(V, W){
50223     W = W || {};
50224     var  X = new  Roo.grid.PropertyStore(this);
50225     this.store = X;
50226     var  cm = new  Roo.grid.PropertyColumnModel(this, X);
50227     X.store.sort('name', 'ASC');
50228     Roo.grid.PropertyGrid.superclass.constructor.call(this, V, Roo.apply({
50229         ds: X.store,
50230         cm: cm,
50231         enableColLock:false,
50232         enableColumnMove:false,
50233         stripeRows:false,
50234         trackMouseOver: false,
50235         clicksToEdit:1
50236     }, W));
50237     this.getGridEl().addClass('x-props-grid');
50238     this.lastEditRow = null;
50239     this.on('columnresize', this.onColumnResize, this);
50240     this.addEvents({
50241          /**
50242              * @event beforepropertychange
50243              * Fires before a property changes (return false to stop?)
50244              * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50245              * @param {String} id Record Id
50246              * @param {String} newval New Value
50247          * @param {String} oldval Old Value
50248              */
50249         "beforepropertychange": true,
50250         /**
50251              * @event propertychange
50252              * Fires after a property changes
50253              * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50254              * @param {String} id Record Id
50255              * @param {String} newval New Value
50256          * @param {String} oldval Old Value
50257              */
50258         "propertychange": true
50259     });
50260     this.customEditors = this.customEditors || {};
50261 };
50262 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50263     
50264      /**
50265      * @cfg {Object} customEditors map of colnames=> custom editors.
50266      * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50267      * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50268      * false disables editing of the field.
50269          */
50270     
50271       /**
50272      * @cfg {Object} propertyNames map of property Names to their displayed value
50273          */
50274     
50275     render : function(){
50276         Roo.grid.PropertyGrid.superclass.render.call(this);
50277         this.autoSize.defer(100, this);
50278     },
50279
50280     autoSize : function(){
50281         Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50282         if(this.view){
50283             this.view.fitColumns();
50284         }
50285     },
50286
50287     onColumnResize : function(){
50288         this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50289         this.autoSize();
50290     },
50291     /**
50292      * Sets the data for the Grid
50293      * accepts a Key => Value object of all the elements avaiable.
50294      * @param {Object} data  to appear in grid.
50295      */
50296     setSource : function(Y){
50297         this.store.setSource(Y);
50298         //this.autoSize();
50299     },
50300     /**
50301      * Gets all the data from the grid.
50302      * @return {Object} data  data stored in grid
50303      */
50304     getSource : function(){
50305         return  this.store.getSource();
50306     }
50307 });
50308 /*
50309  * Based on:
50310  * Ext JS Library 1.1.1
50311  * Copyright(c) 2006-2007, Ext JS, LLC.
50312  *
50313  * Originally Released Under LGPL - original licence link has changed is not relivant.
50314  *
50315  * Fork - LGPL
50316  * <script type="text/javascript">
50317  */
50318  
50319 /**
50320  * @class Roo.LoadMask
50321  * A simple utility class for generically masking elements while loading data.  If the element being masked has
50322  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50323  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
50324  * element's UpdateManager load indicator and will be destroyed after the initial load.
50325  * @constructor
50326  * Create a new LoadMask
50327  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50328  * @param {Object} config The config object
50329  */
50330 Roo.LoadMask = function(el, A){
50331     this.el = Roo.get(el);
50332     Roo.apply(this, A);
50333     if(this.store){
50334         this.store.on('beforeload', this.onBeforeLoad, this);
50335         this.store.on('load', this.onLoad, this);
50336         this.store.on('loadexception', this.onLoad, this);
50337         this.removeMask = false;
50338     }else {
50339         var  um = this.el.getUpdateManager();
50340         um.showLoadIndicator = false; // disable the default indicator
50341         um.on('beforeupdate', this.onBeforeLoad, this);
50342         um.on('update', this.onLoad, this);
50343         um.on('failure', this.onLoad, this);
50344         this.removeMask = true;
50345     }
50346 };
50347
50348 Roo.LoadMask.prototype = {
50349     /**
50350      * @cfg {Boolean} removeMask
50351      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50352      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
50353      */
50354     /**
50355      * @cfg {String} msg
50356      * The text to display in a centered loading message box (defaults to 'Loading...')
50357      */
50358     msg : 'Loading...',
50359     /**
50360      * @cfg {String} msgCls
50361      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50362      */
50363     msgCls : 'x-mask-loading',
50364
50365     /**
50366      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50367      * @type Boolean
50368      */
50369     disabled: false,
50370
50371     /**
50372      * Disables the mask to prevent it from being displayed
50373      */
50374     disable : function(){
50375        this.disabled = true;
50376     },
50377
50378     /**
50379      * Enables the mask so that it can be displayed
50380      */
50381     enable : function(){
50382         this.disabled = false;
50383     },
50384
50385     // private
50386     onLoad : function(){
50387         this.el.unmask(this.removeMask);
50388     },
50389
50390     // private
50391     onBeforeLoad : function(){
50392         if(!this.disabled){
50393             this.el.mask(this.msg, this.msgCls);
50394         }
50395     },
50396
50397     // private
50398     destroy : function(){
50399         if(this.store){
50400             this.store.un('beforeload', this.onBeforeLoad, this);
50401             this.store.un('load', this.onLoad, this);
50402             this.store.un('loadexception', this.onLoad, this);
50403         }else {
50404             var  um = this.el.getUpdateManager();
50405             um.un('beforeupdate', this.onBeforeLoad, this);
50406             um.un('update', this.onLoad, this);
50407             um.un('failure', this.onLoad, this);
50408         }
50409     }
50410 };
50411 /*
50412  * Based on:
50413  * Ext JS Library 1.1.1
50414  * Copyright(c) 2006-2007, Ext JS, LLC.
50415  *
50416  * Originally Released Under LGPL - original licence link has changed is not relivant.
50417  *
50418  * Fork - LGPL
50419  * <script type="text/javascript">
50420  */
50421 Roo.XTemplate = function(){
50422     Roo.XTemplate.superclass.constructor.apply(this, arguments);
50423     var  s = this.html;
50424
50425     s = ['<tpl>', s, '</tpl>'].join('');
50426
50427     var  re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50428
50429     var  A = /^<tpl\b[^>]*?for="(.*?)"/;
50430     var  B = /^<tpl\b[^>]*?if="(.*?)"/;
50431     var  C = /^<tpl\b[^>]*?exec="(.*?)"/;
50432     var  m, id = 0;
50433     var  D = [];
50434
50435     while(m = s.match(re)){
50436        var  m2 = m[0].match(A);
50437        var  m3 = m[0].match(B);
50438        var  m4 = m[0].match(C);
50439        var  exp = null, fn = null, exec = null;
50440        var  name = m2 && m2[1] ? m2[1] : '';
50441        if(m3){
50442            exp = m3 && m3[1] ? m3[1] : null;
50443            if(exp){
50444                fn = new  Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50445            }
50446        }
50447        if(m4){
50448            exp = m4 && m4[1] ? m4[1] : null;
50449            if(exp){
50450                exec = new  Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50451            }
50452        }
50453        if(name){
50454            switch(name){
50455                case  '.': name = new  Function('values', 'parent', 'with(values){ return values; }'); break;
50456                case  '..': name = new  Function('values', 'parent', 'with(values){ return parent; }'); break;
50457                default: name = new  Function('values', 'parent', 'with(values){ return '+name+'; }');
50458            }
50459        }
50460
50461        D.push({
50462             id: id,
50463             target: name,
50464             exec: exec,
50465             test: fn,
50466             body: m[1]||''
50467         });
50468        s = s.replace(m[0], '{xtpl'+ id + '}');
50469        ++id;
50470     }
50471     for(var  i = D.length-1; i >= 0; --i){
50472         this.compileTpl(D[i]);
50473     }
50474
50475     this.master = D[D.length-1];
50476     this.tpls = D;
50477 };
50478 Roo.extend(Roo.XTemplate, Roo.Template, {
50479
50480     re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50481
50482     applySubTemplate : function(id, E, F){
50483         var  t = this.tpls[id];
50484         if(t.test && !t.test.call(this, E, F)){
50485             return  '';
50486         }
50487         if(t.exec && t.exec.call(this, E, F)){
50488             return  '';
50489         }
50490         var  vs = t.target ? t.target.call(this, E, F) : E;
50491         F = t.target ? E : F;
50492         if(t.target && vs  instanceof  Array){
50493             var  buf = [];
50494             for(var  i = 0, len = vs.length; i < len; i++){
50495                 buf[buf.length] = t.compiled.call(this, vs[i], F);
50496             }
50497             return  buf.join('');
50498         }
50499         return  t.compiled.call(this, vs, F);
50500     },
50501
50502     compileTpl : function(G){
50503         var  fm = Roo.util.Format;
50504         var  H = this.disableFormats !== true;
50505         var  I = Roo.isGecko ? "+" : ",";
50506         var  fn = function(m, K, L, M){
50507             if(K.substr(0, 4) == 'xtpl'){
50508                 return  "'"+ I +'this.applySubTemplate('+K.substr(4)+', values, parent)'+I+"'";
50509             }
50510             var  v;
50511             if(K.indexOf('.') != -1){
50512                 v = K;
50513             }else {
50514                 v = "values['" + K + "']";
50515             }
50516             if(L && H){
50517                 M = M ? ',' + M : "";
50518                 if(L.substr(0, 5) != "this."){
50519                     L = "fm." + L + '(';
50520                 }else {
50521                     L = 'this.call("'+ L.substr(5) + '", ';
50522                     M = ", values";
50523                 }
50524             }else {
50525                 M= ''; L = "("+v+" === undefined ? '' : ";
50526             }
50527             return  "'"+ I + L + v + M + ")"+I+"'";
50528         };
50529         var  J;
50530         // branched to use + in gecko and [].join() in others
50531         if(Roo.isGecko){
50532             J = "tpl.compiled = function(values, parent){ return '" +
50533                    G.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50534                     "';};";
50535         }else {
50536             J = ["tpl.compiled = function(values, parent){ return ['"];
50537             J.push(G.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50538             J.push("'].join('');};");
50539             J = J.join('');
50540         }
50541
50542         /** eval:var:zzzzzzz */
50543         eval(J);
50544         return  this;
50545     },
50546
50547     applyTemplate : function(K){
50548         return  this.master.compiled.call(this, K, {});
50549         var  s = this.subs;
50550     },
50551
50552     apply : function(){
50553         return  this.applyTemplate.apply(this, arguments);
50554     },
50555
50556     compile : function(){return  this;}
50557 });
50558
50559 Roo.XTemplate.from = function(el){
50560     el = Roo.getDom(el);
50561     return  new  Roo.XTemplate(el.value || el.innerHTML);
50562 };