roojs-ui-debug.js
[roojs1] / roojs-ui-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11
12
13
14 /*
15  * These classes are derivatives of the similarly named classes in the YUI Library.
16  * The original license:
17  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18  * Code licensed under the BSD License:
19  * http://developer.yahoo.net/yui/license.txt
20  */
21
22 (function() {
23
24 var Event=Roo.EventManager;
25 var Dom=Roo.lib.Dom;
26
27 /**
28  * @class Roo.dd.DragDrop
29  * @extends Roo.util.Observable
30  * Defines the interface and base operation of items that that can be
31  * dragged or can be drop targets.  It was designed to be extended, overriding
32  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
33  * Up to three html elements can be associated with a DragDrop instance:
34  * <ul>
35  * <li>linked element: the element that is passed into the constructor.
36  * This is the element which defines the boundaries for interaction with
37  * other DragDrop objects.</li>
38  * <li>handle element(s): The drag operation only occurs if the element that
39  * was clicked matches a handle element.  By default this is the linked
40  * element, but there are times that you will want only a portion of the
41  * linked element to initiate the drag operation, and the setHandleElId()
42  * method provides a way to define this.</li>
43  * <li>drag element: this represents the element that would be moved along
44  * with the cursor during a drag operation.  By default, this is the linked
45  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
46  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
47  * </li>
48  * </ul>
49  * This class should not be instantiated until the onload event to ensure that
50  * the associated elements are available.
51  * The following would define a DragDrop obj that would interact with any
52  * other DragDrop obj in the "group1" group:
53  * <pre>
54  *  dd = new Roo.dd.DragDrop("div1", "group1");
55  * </pre>
56  * Since none of the event handlers have been implemented, nothing would
57  * actually happen if you were to run the code above.  Normally you would
58  * override this class or one of the default implementations, but you can
59  * also override the methods you want on an instance of the class...
60  * <pre>
61  *  dd.onDragDrop = function(e, id) {
62  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
63  *  }
64  * </pre>
65  * @constructor
66  * @param {String} id of the element that is linked to this instance
67  * @param {String} sGroup the group of related DragDrop objects
68  * @param {object} config an object containing configurable attributes
69  *                Valid properties for DragDrop:
70  *                    padding, isTarget, maintainOffset, primaryButtonOnly
71  */
72 Roo.dd.DragDrop = function(id, sGroup, config) {
73     if (id) {
74         this.init(id, sGroup, config);
75     }
76     
77 };
78
79 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
80
81     /**
82      * The id of the element associated with this object.  This is what we
83      * refer to as the "linked element" because the size and position of
84      * this element is used to determine when the drag and drop objects have
85      * interacted.
86      * @property id
87      * @type String
88      */
89     id: null,
90
91     /**
92      * Configuration attributes passed into the constructor
93      * @property config
94      * @type object
95      */
96     config: null,
97
98     /**
99      * The id of the element that will be dragged.  By default this is same
100      * as the linked element , but could be changed to another element. Ex:
101      * Roo.dd.DDProxy
102      * @property dragElId
103      * @type String
104      * @private
105      */
106     dragElId: null,
107
108     /**
109      * the id of the element that initiates the drag operation.  By default
110      * this is the linked element, but could be changed to be a child of this
111      * element.  This lets us do things like only starting the drag when the
112      * header element within the linked html element is clicked.
113      * @property handleElId
114      * @type String
115      * @private
116      */
117     handleElId: null,
118
119     /**
120      * An associative array of HTML tags that will be ignored if clicked.
121      * @property invalidHandleTypes
122      * @type {string: string}
123      */
124     invalidHandleTypes: null,
125
126     /**
127      * An associative array of ids for elements that will be ignored if clicked
128      * @property invalidHandleIds
129      * @type {string: string}
130      */
131     invalidHandleIds: null,
132
133     /**
134      * An indexted array of css class names for elements that will be ignored
135      * if clicked.
136      * @property invalidHandleClasses
137      * @type string[]
138      */
139     invalidHandleClasses: null,
140
141     /**
142      * The linked element's absolute X position at the time the drag was
143      * started
144      * @property startPageX
145      * @type int
146      * @private
147      */
148     startPageX: 0,
149
150     /**
151      * The linked element's absolute X position at the time the drag was
152      * started
153      * @property startPageY
154      * @type int
155      * @private
156      */
157     startPageY: 0,
158
159     /**
160      * The group defines a logical collection of DragDrop objects that are
161      * related.  Instances only get events when interacting with other
162      * DragDrop object in the same group.  This lets us define multiple
163      * groups using a single DragDrop subclass if we want.
164      * @property groups
165      * @type {string: string}
166      */
167     groups: null,
168
169     /**
170      * Individual drag/drop instances can be locked.  This will prevent
171      * onmousedown start drag.
172      * @property locked
173      * @type boolean
174      * @private
175      */
176     locked: false,
177
178     /**
179      * Lock this instance
180      * @method lock
181      */
182     lock: function() { this.locked = true; },
183
184     /**
185      * Unlock this instace
186      * @method unlock
187      */
188     unlock: function() { this.locked = false; },
189
190     /**
191      * By default, all insances can be a drop target.  This can be disabled by
192      * setting isTarget to false.
193      * @method isTarget
194      * @type boolean
195      */
196     isTarget: true,
197
198     /**
199      * The padding configured for this drag and drop object for calculating
200      * the drop zone intersection with this object.
201      * @method padding
202      * @type int[]
203      */
204     padding: null,
205
206     /**
207      * Cached reference to the linked element
208      * @property _domRef
209      * @private
210      */
211     _domRef: null,
212
213     /**
214      * Internal typeof flag
215      * @property __ygDragDrop
216      * @private
217      */
218     __ygDragDrop: true,
219
220     /**
221      * Set to true when horizontal contraints are applied
222      * @property constrainX
223      * @type boolean
224      * @private
225      */
226     constrainX: false,
227
228     /**
229      * Set to true when vertical contraints are applied
230      * @property constrainY
231      * @type boolean
232      * @private
233      */
234     constrainY: false,
235
236     /**
237      * The left constraint
238      * @property minX
239      * @type int
240      * @private
241      */
242     minX: 0,
243
244     /**
245      * The right constraint
246      * @property maxX
247      * @type int
248      * @private
249      */
250     maxX: 0,
251
252     /**
253      * The up constraint
254      * @property minY
255      * @type int
256      * @type int
257      * @private
258      */
259     minY: 0,
260
261     /**
262      * The down constraint
263      * @property maxY
264      * @type int
265      * @private
266      */
267     maxY: 0,
268
269     /**
270      * Maintain offsets when we resetconstraints.  Set to true when you want
271      * the position of the element relative to its parent to stay the same
272      * when the page changes
273      *
274      * @property maintainOffset
275      * @type boolean
276      */
277     maintainOffset: false,
278
279     /**
280      * Array of pixel locations the element will snap to if we specified a
281      * horizontal graduation/interval.  This array is generated automatically
282      * when you define a tick interval.
283      * @property xTicks
284      * @type int[]
285      */
286     xTicks: null,
287
288     /**
289      * Array of pixel locations the element will snap to if we specified a
290      * vertical graduation/interval.  This array is generated automatically
291      * when you define a tick interval.
292      * @property yTicks
293      * @type int[]
294      */
295     yTicks: null,
296
297     /**
298      * By default the drag and drop instance will only respond to the primary
299      * button click (left button for a right-handed mouse).  Set to true to
300      * allow drag and drop to start with any mouse click that is propogated
301      * by the browser
302      * @property primaryButtonOnly
303      * @type boolean
304      */
305     primaryButtonOnly: true,
306
307     /**
308      * The availabe property is false until the linked dom element is accessible.
309      * @property available
310      * @type boolean
311      */
312     available: false,
313
314     /**
315      * By default, drags can only be initiated if the mousedown occurs in the
316      * region the linked element is.  This is done in part to work around a
317      * bug in some browsers that mis-report the mousedown if the previous
318      * mouseup happened outside of the window.  This property is set to true
319      * if outer handles are defined.
320      *
321      * @property hasOuterHandles
322      * @type boolean
323      * @default false
324      */
325     hasOuterHandles: false,
326
327     /**
328      * Code that executes immediately before the startDrag event
329      * @method b4StartDrag
330      * @private
331      */
332     b4StartDrag: function(x, y) { },
333
334     /**
335      * Abstract method called after a drag/drop object is clicked
336      * and the drag or mousedown time thresholds have beeen met.
337      * @method startDrag
338      * @param {int} X click location
339      * @param {int} Y click location
340      */
341     startDrag: function(x, y) { /* override this */ },
342
343     /**
344      * Code that executes immediately before the onDrag event
345      * @method b4Drag
346      * @private
347      */
348     b4Drag: function(e) { },
349
350     /**
351      * Abstract method called during the onMouseMove event while dragging an
352      * object.
353      * @method onDrag
354      * @param {Event} e the mousemove event
355      */
356     onDrag: function(e) { /* override this */ },
357
358     /**
359      * Abstract method called when this element fist begins hovering over
360      * another DragDrop obj
361      * @method onDragEnter
362      * @param {Event} e the mousemove event
363      * @param {String|DragDrop[]} id In POINT mode, the element
364      * id this is hovering over.  In INTERSECT mode, an array of one or more
365      * dragdrop items being hovered over.
366      */
367     onDragEnter: function(e, id) { /* override this */ },
368
369     /**
370      * Code that executes immediately before the onDragOver event
371      * @method b4DragOver
372      * @private
373      */
374     b4DragOver: function(e) { },
375
376     /**
377      * Abstract method called when this element is hovering over another
378      * DragDrop obj
379      * @method onDragOver
380      * @param {Event} e the mousemove event
381      * @param {String|DragDrop[]} id In POINT mode, the element
382      * id this is hovering over.  In INTERSECT mode, an array of dd items
383      * being hovered over.
384      */
385     onDragOver: function(e, id) { /* override this */ },
386
387     /**
388      * Code that executes immediately before the onDragOut event
389      * @method b4DragOut
390      * @private
391      */
392     b4DragOut: function(e) { },
393
394     /**
395      * Abstract method called when we are no longer hovering over an element
396      * @method onDragOut
397      * @param {Event} e the mousemove event
398      * @param {String|DragDrop[]} id In POINT mode, the element
399      * id this was hovering over.  In INTERSECT mode, an array of dd items
400      * that the mouse is no longer over.
401      */
402     onDragOut: function(e, id) { /* override this */ },
403
404     /**
405      * Code that executes immediately before the onDragDrop event
406      * @method b4DragDrop
407      * @private
408      */
409     b4DragDrop: function(e) { },
410
411     /**
412      * Abstract method called when this item is dropped on another DragDrop
413      * obj
414      * @method onDragDrop
415      * @param {Event} e the mouseup event
416      * @param {String|DragDrop[]} id In POINT mode, the element
417      * id this was dropped on.  In INTERSECT mode, an array of dd items this
418      * was dropped on.
419      */
420     onDragDrop: function(e, id) { /* override this */ },
421
422     /**
423      * Abstract method called when this item is dropped on an area with no
424      * drop target
425      * @method onInvalidDrop
426      * @param {Event} e the mouseup event
427      */
428     onInvalidDrop: function(e) { /* override this */ },
429
430     /**
431      * Code that executes immediately before the endDrag event
432      * @method b4EndDrag
433      * @private
434      */
435     b4EndDrag: function(e) { },
436
437     /**
438      * Fired when we are done dragging the object
439      * @method endDrag
440      * @param {Event} e the mouseup event
441      */
442     endDrag: function(e) { /* override this */ },
443
444     /**
445      * Code executed immediately before the onMouseDown event
446      * @method b4MouseDown
447      * @param {Event} e the mousedown event
448      * @private
449      */
450     b4MouseDown: function(e) {  },
451
452     /**
453      * Event handler that fires when a drag/drop obj gets a mousedown
454      * @method onMouseDown
455      * @param {Event} e the mousedown event
456      */
457     onMouseDown: function(e) { /* override this */ },
458
459     /**
460      * Event handler that fires when a drag/drop obj gets a mouseup
461      * @method onMouseUp
462      * @param {Event} e the mouseup event
463      */
464     onMouseUp: function(e) { /* override this */ },
465
466     /**
467      * Override the onAvailable method to do what is needed after the initial
468      * position was determined.
469      * @method onAvailable
470      */
471     onAvailable: function () {
472     },
473
474     /*
475      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
476      * @type Object
477      */
478     defaultPadding : {left:0, right:0, top:0, bottom:0},
479
480     /*
481      * Initializes the drag drop object's constraints to restrict movement to a certain element.
482  *
483  * Usage:
484  <pre><code>
485  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
486                 { dragElId: "existingProxyDiv" });
487  dd.startDrag = function(){
488      this.constrainTo("parent-id");
489  };
490  </code></pre>
491  * Or you can initalize it using the {@link Roo.Element} object:
492  <pre><code>
493  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
494      startDrag : function(){
495          this.constrainTo("parent-id");
496      }
497  });
498  </code></pre>
499      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
500      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
501      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
502      * an object containing the sides to pad. For example: {right:10, bottom:10}
503      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
504      */
505     constrainTo : function(constrainTo, pad, inContent){
506         if(typeof pad == "number"){
507             pad = {left: pad, right:pad, top:pad, bottom:pad};
508         }
509         pad = pad || this.defaultPadding;
510         var b = Roo.get(this.getEl()).getBox();
511         var ce = Roo.get(constrainTo);
512         var s = ce.getScroll();
513         var c, cd = ce.dom;
514         if(cd == document.body){
515             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
516         }else{
517             xy = ce.getXY();
518             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
519         }
520
521
522         var topSpace = b.y - c.y;
523         var leftSpace = b.x - c.x;
524
525         this.resetConstraints();
526         this.setXConstraint(leftSpace - (pad.left||0), // left
527                 c.width - leftSpace - b.width - (pad.right||0) //right
528         );
529         this.setYConstraint(topSpace - (pad.top||0), //top
530                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
531         );
532     },
533
534     /**
535      * Returns a reference to the linked element
536      * @method getEl
537      * @return {HTMLElement} the html element
538      */
539     getEl: function() {
540         if (!this._domRef) {
541             this._domRef = Roo.getDom(this.id);
542         }
543
544         return this._domRef;
545     },
546
547     /**
548      * Returns a reference to the actual element to drag.  By default this is
549      * the same as the html element, but it can be assigned to another
550      * element. An example of this can be found in Roo.dd.DDProxy
551      * @method getDragEl
552      * @return {HTMLElement} the html element
553      */
554     getDragEl: function() {
555         return Roo.getDom(this.dragElId);
556     },
557
558     /**
559      * Sets up the DragDrop object.  Must be called in the constructor of any
560      * Roo.dd.DragDrop subclass
561      * @method init
562      * @param id the id of the linked element
563      * @param {String} sGroup the group of related items
564      * @param {object} config configuration attributes
565      */
566     init: function(id, sGroup, config) {
567         this.initTarget(id, sGroup, config);
568         Event.on(this.id, "mousedown", this.handleMouseDown, this);
569         // Event.on(this.id, "selectstart", Event.preventDefault);
570     },
571
572     /**
573      * Initializes Targeting functionality only... the object does not
574      * get a mousedown handler.
575      * @method initTarget
576      * @param id the id of the linked element
577      * @param {String} sGroup the group of related items
578      * @param {object} config configuration attributes
579      */
580     initTarget: function(id, sGroup, config) {
581
582         // configuration attributes
583         this.config = config || {};
584
585         // create a local reference to the drag and drop manager
586         this.DDM = Roo.dd.DDM;
587         // initialize the groups array
588         this.groups = {};
589
590         // assume that we have an element reference instead of an id if the
591         // parameter is not a string
592         if (typeof id !== "string") {
593             id = Roo.id(id);
594         }
595
596         // set the id
597         this.id = id;
598
599         // add to an interaction group
600         this.addToGroup((sGroup) ? sGroup : "default");
601
602         // We don't want to register this as the handle with the manager
603         // so we just set the id rather than calling the setter.
604         this.handleElId = id;
605
606         // the linked element is the element that gets dragged by default
607         this.setDragElId(id);
608
609         // by default, clicked anchors will not start drag operations.
610         this.invalidHandleTypes = { A: "A" };
611         this.invalidHandleIds = {};
612         this.invalidHandleClasses = [];
613
614         this.applyConfig();
615
616         this.handleOnAvailable();
617     },
618
619     /**
620      * Applies the configuration parameters that were passed into the constructor.
621      * This is supposed to happen at each level through the inheritance chain.  So
622      * a DDProxy implentation will execute apply config on DDProxy, DD, and
623      * DragDrop in order to get all of the parameters that are available in
624      * each object.
625      * @method applyConfig
626      */
627     applyConfig: function() {
628
629         // configurable properties:
630         //    padding, isTarget, maintainOffset, primaryButtonOnly
631         this.padding           = this.config.padding || [0, 0, 0, 0];
632         this.isTarget          = (this.config.isTarget !== false);
633         this.maintainOffset    = (this.config.maintainOffset);
634         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
635
636     },
637
638     /**
639      * Executed when the linked element is available
640      * @method handleOnAvailable
641      * @private
642      */
643     handleOnAvailable: function() {
644         this.available = true;
645         this.resetConstraints();
646         this.onAvailable();
647     },
648
649      /**
650      * Configures the padding for the target zone in px.  Effectively expands
651      * (or reduces) the virtual object size for targeting calculations.
652      * Supports css-style shorthand; if only one parameter is passed, all sides
653      * will have that padding, and if only two are passed, the top and bottom
654      * will have the first param, the left and right the second.
655      * @method setPadding
656      * @param {int} iTop    Top pad
657      * @param {int} iRight  Right pad
658      * @param {int} iBot    Bot pad
659      * @param {int} iLeft   Left pad
660      */
661     setPadding: function(iTop, iRight, iBot, iLeft) {
662         // this.padding = [iLeft, iRight, iTop, iBot];
663         if (!iRight && 0 !== iRight) {
664             this.padding = [iTop, iTop, iTop, iTop];
665         } else if (!iBot && 0 !== iBot) {
666             this.padding = [iTop, iRight, iTop, iRight];
667         } else {
668             this.padding = [iTop, iRight, iBot, iLeft];
669         }
670     },
671
672     /**
673      * Stores the initial placement of the linked element.
674      * @method setInitialPosition
675      * @param {int} diffX   the X offset, default 0
676      * @param {int} diffY   the Y offset, default 0
677      */
678     setInitPosition: function(diffX, diffY) {
679         var el = this.getEl();
680
681         if (!this.DDM.verifyEl(el)) {
682             return;
683         }
684
685         var dx = diffX || 0;
686         var dy = diffY || 0;
687
688         var p = Dom.getXY( el );
689
690         this.initPageX = p[0] - dx;
691         this.initPageY = p[1] - dy;
692
693         this.lastPageX = p[0];
694         this.lastPageY = p[1];
695
696
697         this.setStartPosition(p);
698     },
699
700     /**
701      * Sets the start position of the element.  This is set when the obj
702      * is initialized, the reset when a drag is started.
703      * @method setStartPosition
704      * @param pos current position (from previous lookup)
705      * @private
706      */
707     setStartPosition: function(pos) {
708         var p = pos || Dom.getXY( this.getEl() );
709         this.deltaSetXY = null;
710
711         this.startPageX = p[0];
712         this.startPageY = p[1];
713     },
714
715     /**
716      * Add this instance to a group of related drag/drop objects.  All
717      * instances belong to at least one group, and can belong to as many
718      * groups as needed.
719      * @method addToGroup
720      * @param sGroup {string} the name of the group
721      */
722     addToGroup: function(sGroup) {
723         this.groups[sGroup] = true;
724         this.DDM.regDragDrop(this, sGroup);
725     },
726
727     /**
728      * Remove's this instance from the supplied interaction group
729      * @method removeFromGroup
730      * @param {string}  sGroup  The group to drop
731      */
732     removeFromGroup: function(sGroup) {
733         if (this.groups[sGroup]) {
734             delete this.groups[sGroup];
735         }
736
737         this.DDM.removeDDFromGroup(this, sGroup);
738     },
739
740     /**
741      * Allows you to specify that an element other than the linked element
742      * will be moved with the cursor during a drag
743      * @method setDragElId
744      * @param id {string} the id of the element that will be used to initiate the drag
745      */
746     setDragElId: function(id) {
747         this.dragElId = id;
748     },
749
750     /**
751      * Allows you to specify a child of the linked element that should be
752      * used to initiate the drag operation.  An example of this would be if
753      * you have a content div with text and links.  Clicking anywhere in the
754      * content area would normally start the drag operation.  Use this method
755      * to specify that an element inside of the content div is the element
756      * that starts the drag operation.
757      * @method setHandleElId
758      * @param id {string} the id of the element that will be used to
759      * initiate the drag.
760      */
761     setHandleElId: function(id) {
762         if (typeof id !== "string") {
763             id = Roo.id(id);
764         }
765         this.handleElId = id;
766         this.DDM.regHandle(this.id, id);
767     },
768
769     /**
770      * Allows you to set an element outside of the linked element as a drag
771      * handle
772      * @method setOuterHandleElId
773      * @param id the id of the element that will be used to initiate the drag
774      */
775     setOuterHandleElId: function(id) {
776         if (typeof id !== "string") {
777             id = Roo.id(id);
778         }
779         Event.on(id, "mousedown",
780                 this.handleMouseDown, this);
781         this.setHandleElId(id);
782
783         this.hasOuterHandles = true;
784     },
785
786     /**
787      * Remove all drag and drop hooks for this element
788      * @method unreg
789      */
790     unreg: function() {
791         Event.un(this.id, "mousedown",
792                 this.handleMouseDown);
793         this._domRef = null;
794         this.DDM._remove(this);
795     },
796
797     destroy : function(){
798         this.unreg();
799     },
800
801     /**
802      * Returns true if this instance is locked, or the drag drop mgr is locked
803      * (meaning that all drag/drop is disabled on the page.)
804      * @method isLocked
805      * @return {boolean} true if this obj or all drag/drop is locked, else
806      * false
807      */
808     isLocked: function() {
809         return (this.DDM.isLocked() || this.locked);
810     },
811
812     /**
813      * Fired when this object is clicked
814      * @method handleMouseDown
815      * @param {Event} e
816      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
817      * @private
818      */
819     handleMouseDown: function(e, oDD){
820         if (this.primaryButtonOnly && e.button != 0) {
821             return;
822         }
823
824         if (this.isLocked()) {
825             return;
826         }
827
828         this.DDM.refreshCache(this.groups);
829
830         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
831         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
832         } else {
833             if (this.clickValidator(e)) {
834
835                 // set the initial element position
836                 this.setStartPosition();
837
838
839                 this.b4MouseDown(e);
840                 this.onMouseDown(e);
841
842                 this.DDM.handleMouseDown(e, this);
843
844                 this.DDM.stopEvent(e);
845             } else {
846
847
848             }
849         }
850     },
851
852     clickValidator: function(e) {
853         var target = e.getTarget();
854         return ( this.isValidHandleChild(target) &&
855                     (this.id == this.handleElId ||
856                         this.DDM.handleWasClicked(target, this.id)) );
857     },
858
859     /**
860      * Allows you to specify a tag name that should not start a drag operation
861      * when clicked.  This is designed to facilitate embedding links within a
862      * drag handle that do something other than start the drag.
863      * @method addInvalidHandleType
864      * @param {string} tagName the type of element to exclude
865      */
866     addInvalidHandleType: function(tagName) {
867         var type = tagName.toUpperCase();
868         this.invalidHandleTypes[type] = type;
869     },
870
871     /**
872      * Lets you to specify an element id for a child of a drag handle
873      * that should not initiate a drag
874      * @method addInvalidHandleId
875      * @param {string} id the element id of the element you wish to ignore
876      */
877     addInvalidHandleId: function(id) {
878         if (typeof id !== "string") {
879             id = Roo.id(id);
880         }
881         this.invalidHandleIds[id] = id;
882     },
883
884     /**
885      * Lets you specify a css class of elements that will not initiate a drag
886      * @method addInvalidHandleClass
887      * @param {string} cssClass the class of the elements you wish to ignore
888      */
889     addInvalidHandleClass: function(cssClass) {
890         this.invalidHandleClasses.push(cssClass);
891     },
892
893     /**
894      * Unsets an excluded tag name set by addInvalidHandleType
895      * @method removeInvalidHandleType
896      * @param {string} tagName the type of element to unexclude
897      */
898     removeInvalidHandleType: function(tagName) {
899         var type = tagName.toUpperCase();
900         // this.invalidHandleTypes[type] = null;
901         delete this.invalidHandleTypes[type];
902     },
903
904     /**
905      * Unsets an invalid handle id
906      * @method removeInvalidHandleId
907      * @param {string} id the id of the element to re-enable
908      */
909     removeInvalidHandleId: function(id) {
910         if (typeof id !== "string") {
911             id = Roo.id(id);
912         }
913         delete this.invalidHandleIds[id];
914     },
915
916     /**
917      * Unsets an invalid css class
918      * @method removeInvalidHandleClass
919      * @param {string} cssClass the class of the element(s) you wish to
920      * re-enable
921      */
922     removeInvalidHandleClass: function(cssClass) {
923         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
924             if (this.invalidHandleClasses[i] == cssClass) {
925                 delete this.invalidHandleClasses[i];
926             }
927         }
928     },
929
930     /**
931      * Checks the tag exclusion list to see if this click should be ignored
932      * @method isValidHandleChild
933      * @param {HTMLElement} node the HTMLElement to evaluate
934      * @return {boolean} true if this is a valid tag type, false if not
935      */
936     isValidHandleChild: function(node) {
937
938         var valid = true;
939         // var n = (node.nodeName == "#text") ? node.parentNode : node;
940         var nodeName;
941         try {
942             nodeName = node.nodeName.toUpperCase();
943         } catch(e) {
944             nodeName = node.nodeName;
945         }
946         valid = valid && !this.invalidHandleTypes[nodeName];
947         valid = valid && !this.invalidHandleIds[node.id];
948
949         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
950             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
951         }
952
953
954         return valid;
955
956     },
957
958     /**
959      * Create the array of horizontal tick marks if an interval was specified
960      * in setXConstraint().
961      * @method setXTicks
962      * @private
963      */
964     setXTicks: function(iStartX, iTickSize) {
965         this.xTicks = [];
966         this.xTickSize = iTickSize;
967
968         var tickMap = {};
969
970         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
971             if (!tickMap[i]) {
972                 this.xTicks[this.xTicks.length] = i;
973                 tickMap[i] = true;
974             }
975         }
976
977         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
978             if (!tickMap[i]) {
979                 this.xTicks[this.xTicks.length] = i;
980                 tickMap[i] = true;
981             }
982         }
983
984         this.xTicks.sort(this.DDM.numericSort) ;
985     },
986
987     /**
988      * Create the array of vertical tick marks if an interval was specified in
989      * setYConstraint().
990      * @method setYTicks
991      * @private
992      */
993     setYTicks: function(iStartY, iTickSize) {
994         this.yTicks = [];
995         this.yTickSize = iTickSize;
996
997         var tickMap = {};
998
999         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1000             if (!tickMap[i]) {
1001                 this.yTicks[this.yTicks.length] = i;
1002                 tickMap[i] = true;
1003             }
1004         }
1005
1006         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1007             if (!tickMap[i]) {
1008                 this.yTicks[this.yTicks.length] = i;
1009                 tickMap[i] = true;
1010             }
1011         }
1012
1013         this.yTicks.sort(this.DDM.numericSort) ;
1014     },
1015
1016     /**
1017      * By default, the element can be dragged any place on the screen.  Use
1018      * this method to limit the horizontal travel of the element.  Pass in
1019      * 0,0 for the parameters if you want to lock the drag to the y axis.
1020      * @method setXConstraint
1021      * @param {int} iLeft the number of pixels the element can move to the left
1022      * @param {int} iRight the number of pixels the element can move to the
1023      * right
1024      * @param {int} iTickSize optional parameter for specifying that the
1025      * element
1026      * should move iTickSize pixels at a time.
1027      */
1028     setXConstraint: function(iLeft, iRight, iTickSize) {
1029         this.leftConstraint = iLeft;
1030         this.rightConstraint = iRight;
1031
1032         this.minX = this.initPageX - iLeft;
1033         this.maxX = this.initPageX + iRight;
1034         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1035
1036         this.constrainX = true;
1037     },
1038
1039     /**
1040      * Clears any constraints applied to this instance.  Also clears ticks
1041      * since they can't exist independent of a constraint at this time.
1042      * @method clearConstraints
1043      */
1044     clearConstraints: function() {
1045         this.constrainX = false;
1046         this.constrainY = false;
1047         this.clearTicks();
1048     },
1049
1050     /**
1051      * Clears any tick interval defined for this instance
1052      * @method clearTicks
1053      */
1054     clearTicks: function() {
1055         this.xTicks = null;
1056         this.yTicks = null;
1057         this.xTickSize = 0;
1058         this.yTickSize = 0;
1059     },
1060
1061     /**
1062      * By default, the element can be dragged any place on the screen.  Set
1063      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1064      * parameters if you want to lock the drag to the x axis.
1065      * @method setYConstraint
1066      * @param {int} iUp the number of pixels the element can move up
1067      * @param {int} iDown the number of pixels the element can move down
1068      * @param {int} iTickSize optional parameter for specifying that the
1069      * element should move iTickSize pixels at a time.
1070      */
1071     setYConstraint: function(iUp, iDown, iTickSize) {
1072         this.topConstraint = iUp;
1073         this.bottomConstraint = iDown;
1074
1075         this.minY = this.initPageY - iUp;
1076         this.maxY = this.initPageY + iDown;
1077         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1078
1079         this.constrainY = true;
1080
1081     },
1082
1083     /**
1084      * resetConstraints must be called if you manually reposition a dd element.
1085      * @method resetConstraints
1086      * @param {boolean} maintainOffset
1087      */
1088     resetConstraints: function() {
1089
1090
1091         // Maintain offsets if necessary
1092         if (this.initPageX || this.initPageX === 0) {
1093             // figure out how much this thing has moved
1094             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1095             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1096
1097             this.setInitPosition(dx, dy);
1098
1099         // This is the first time we have detected the element's position
1100         } else {
1101             this.setInitPosition();
1102         }
1103
1104         if (this.constrainX) {
1105             this.setXConstraint( this.leftConstraint,
1106                                  this.rightConstraint,
1107                                  this.xTickSize        );
1108         }
1109
1110         if (this.constrainY) {
1111             this.setYConstraint( this.topConstraint,
1112                                  this.bottomConstraint,
1113                                  this.yTickSize         );
1114         }
1115     },
1116
1117     /**
1118      * Normally the drag element is moved pixel by pixel, but we can specify
1119      * that it move a number of pixels at a time.  This method resolves the
1120      * location when we have it set up like this.
1121      * @method getTick
1122      * @param {int} val where we want to place the object
1123      * @param {int[]} tickArray sorted array of valid points
1124      * @return {int} the closest tick
1125      * @private
1126      */
1127     getTick: function(val, tickArray) {
1128
1129         if (!tickArray) {
1130             // If tick interval is not defined, it is effectively 1 pixel,
1131             // so we return the value passed to us.
1132             return val;
1133         } else if (tickArray[0] >= val) {
1134             // The value is lower than the first tick, so we return the first
1135             // tick.
1136             return tickArray[0];
1137         } else {
1138             for (var i=0, len=tickArray.length; i<len; ++i) {
1139                 var next = i + 1;
1140                 if (tickArray[next] && tickArray[next] >= val) {
1141                     var diff1 = val - tickArray[i];
1142                     var diff2 = tickArray[next] - val;
1143                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1144                 }
1145             }
1146
1147             // The value is larger than the last tick, so we return the last
1148             // tick.
1149             return tickArray[tickArray.length - 1];
1150         }
1151     },
1152
1153     /**
1154      * toString method
1155      * @method toString
1156      * @return {string} string representation of the dd obj
1157      */
1158     toString: function() {
1159         return ("DragDrop " + this.id);
1160     }
1161
1162 });
1163
1164 })();
1165 /*
1166  * Based on:
1167  * Ext JS Library 1.1.1
1168  * Copyright(c) 2006-2007, Ext JS, LLC.
1169  *
1170  * Originally Released Under LGPL - original licence link has changed is not relivant.
1171  *
1172  * Fork - LGPL
1173  * <script type="text/javascript">
1174  */
1175
1176
1177 /**
1178  * The drag and drop utility provides a framework for building drag and drop
1179  * applications.  In addition to enabling drag and drop for specific elements,
1180  * the drag and drop elements are tracked by the manager class, and the
1181  * interactions between the various elements are tracked during the drag and
1182  * the implementing code is notified about these important moments.
1183  */
1184
1185 // Only load the library once.  Rewriting the manager class would orphan
1186 // existing drag and drop instances.
1187 if (!Roo.dd.DragDropMgr) {
1188
1189 /**
1190  * @class Roo.dd.DragDropMgr
1191  * DragDropMgr is a singleton that tracks the element interaction for
1192  * all DragDrop items in the window.  Generally, you will not call
1193  * this class directly, but it does have helper methods that could
1194  * be useful in your DragDrop implementations.
1195  * @singleton
1196  */
1197 Roo.dd.DragDropMgr = function() {
1198
1199     var Event = Roo.EventManager;
1200
1201     return {
1202
1203         /**
1204          * Two dimensional Array of registered DragDrop objects.  The first
1205          * dimension is the DragDrop item group, the second the DragDrop
1206          * object.
1207          * @property ids
1208          * @type {string: string}
1209          * @private
1210          * @static
1211          */
1212         ids: {},
1213
1214         /**
1215          * Array of element ids defined as drag handles.  Used to determine
1216          * if the element that generated the mousedown event is actually the
1217          * handle and not the html element itself.
1218          * @property handleIds
1219          * @type {string: string}
1220          * @private
1221          * @static
1222          */
1223         handleIds: {},
1224
1225         /**
1226          * the DragDrop object that is currently being dragged
1227          * @property dragCurrent
1228          * @type DragDrop
1229          * @private
1230          * @static
1231          **/
1232         dragCurrent: null,
1233
1234         /**
1235          * the DragDrop object(s) that are being hovered over
1236          * @property dragOvers
1237          * @type Array
1238          * @private
1239          * @static
1240          */
1241         dragOvers: {},
1242
1243         /**
1244          * the X distance between the cursor and the object being dragged
1245          * @property deltaX
1246          * @type int
1247          * @private
1248          * @static
1249          */
1250         deltaX: 0,
1251
1252         /**
1253          * the Y distance between the cursor and the object being dragged
1254          * @property deltaY
1255          * @type int
1256          * @private
1257          * @static
1258          */
1259         deltaY: 0,
1260
1261         /**
1262          * Flag to determine if we should prevent the default behavior of the
1263          * events we define. By default this is true, but this can be set to
1264          * false if you need the default behavior (not recommended)
1265          * @property preventDefault
1266          * @type boolean
1267          * @static
1268          */
1269         preventDefault: true,
1270
1271         /**
1272          * Flag to determine if we should stop the propagation of the events
1273          * we generate. This is true by default but you may want to set it to
1274          * false if the html element contains other features that require the
1275          * mouse click.
1276          * @property stopPropagation
1277          * @type boolean
1278          * @static
1279          */
1280         stopPropagation: true,
1281
1282         /**
1283          * Internal flag that is set to true when drag and drop has been
1284          * intialized
1285          * @property initialized
1286          * @private
1287          * @static
1288          */
1289         initalized: false,
1290
1291         /**
1292          * All drag and drop can be disabled.
1293          * @property locked
1294          * @private
1295          * @static
1296          */
1297         locked: false,
1298
1299         /**
1300          * Called the first time an element is registered.
1301          * @method init
1302          * @private
1303          * @static
1304          */
1305         init: function() {
1306             this.initialized = true;
1307         },
1308
1309         /**
1310          * In point mode, drag and drop interaction is defined by the
1311          * location of the cursor during the drag/drop
1312          * @property POINT
1313          * @type int
1314          * @static
1315          */
1316         POINT: 0,
1317
1318         /**
1319          * In intersect mode, drag and drop interactio nis defined by the
1320          * overlap of two or more drag and drop objects.
1321          * @property INTERSECT
1322          * @type int
1323          * @static
1324          */
1325         INTERSECT: 1,
1326
1327         /**
1328          * The current drag and drop mode.  Default: POINT
1329          * @property mode
1330          * @type int
1331          * @static
1332          */
1333         mode: 0,
1334
1335         /**
1336          * Runs method on all drag and drop objects
1337          * @method _execOnAll
1338          * @private
1339          * @static
1340          */
1341         _execOnAll: function(sMethod, args) {
1342             for (var i in this.ids) {
1343                 for (var j in this.ids[i]) {
1344                     var oDD = this.ids[i][j];
1345                     if (! this.isTypeOfDD(oDD)) {
1346                         continue;
1347                     }
1348                     oDD[sMethod].apply(oDD, args);
1349                 }
1350             }
1351         },
1352
1353         /**
1354          * Drag and drop initialization.  Sets up the global event handlers
1355          * @method _onLoad
1356          * @private
1357          * @static
1358          */
1359         _onLoad: function() {
1360
1361             this.init();
1362
1363
1364             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1365             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1366             Event.on(window,   "unload",    this._onUnload, this, true);
1367             Event.on(window,   "resize",    this._onResize, this, true);
1368             // Event.on(window,   "mouseout",    this._test);
1369
1370         },
1371
1372         /**
1373          * Reset constraints on all drag and drop objs
1374          * @method _onResize
1375          * @private
1376          * @static
1377          */
1378         _onResize: function(e) {
1379             this._execOnAll("resetConstraints", []);
1380         },
1381
1382         /**
1383          * Lock all drag and drop functionality
1384          * @method lock
1385          * @static
1386          */
1387         lock: function() { this.locked = true; },
1388
1389         /**
1390          * Unlock all drag and drop functionality
1391          * @method unlock
1392          * @static
1393          */
1394         unlock: function() { this.locked = false; },
1395
1396         /**
1397          * Is drag and drop locked?
1398          * @method isLocked
1399          * @return {boolean} True if drag and drop is locked, false otherwise.
1400          * @static
1401          */
1402         isLocked: function() { return this.locked; },
1403
1404         /**
1405          * Location cache that is set for all drag drop objects when a drag is
1406          * initiated, cleared when the drag is finished.
1407          * @property locationCache
1408          * @private
1409          * @static
1410          */
1411         locationCache: {},
1412
1413         /**
1414          * Set useCache to false if you want to force object the lookup of each
1415          * drag and drop linked element constantly during a drag.
1416          * @property useCache
1417          * @type boolean
1418          * @static
1419          */
1420         useCache: true,
1421
1422         /**
1423          * The number of pixels that the mouse needs to move after the
1424          * mousedown before the drag is initiated.  Default=3;
1425          * @property clickPixelThresh
1426          * @type int
1427          * @static
1428          */
1429         clickPixelThresh: 3,
1430
1431         /**
1432          * The number of milliseconds after the mousedown event to initiate the
1433          * drag if we don't get a mouseup event. Default=1000
1434          * @property clickTimeThresh
1435          * @type int
1436          * @static
1437          */
1438         clickTimeThresh: 350,
1439
1440         /**
1441          * Flag that indicates that either the drag pixel threshold or the
1442          * mousdown time threshold has been met
1443          * @property dragThreshMet
1444          * @type boolean
1445          * @private
1446          * @static
1447          */
1448         dragThreshMet: false,
1449
1450         /**
1451          * Timeout used for the click time threshold
1452          * @property clickTimeout
1453          * @type Object
1454          * @private
1455          * @static
1456          */
1457         clickTimeout: null,
1458
1459         /**
1460          * The X position of the mousedown event stored for later use when a
1461          * drag threshold is met.
1462          * @property startX
1463          * @type int
1464          * @private
1465          * @static
1466          */
1467         startX: 0,
1468
1469         /**
1470          * The Y position of the mousedown event stored for later use when a
1471          * drag threshold is met.
1472          * @property startY
1473          * @type int
1474          * @private
1475          * @static
1476          */
1477         startY: 0,
1478
1479         /**
1480          * Each DragDrop instance must be registered with the DragDropMgr.
1481          * This is executed in DragDrop.init()
1482          * @method regDragDrop
1483          * @param {DragDrop} oDD the DragDrop object to register
1484          * @param {String} sGroup the name of the group this element belongs to
1485          * @static
1486          */
1487         regDragDrop: function(oDD, sGroup) {
1488             if (!this.initialized) { this.init(); }
1489
1490             if (!this.ids[sGroup]) {
1491                 this.ids[sGroup] = {};
1492             }
1493             this.ids[sGroup][oDD.id] = oDD;
1494         },
1495
1496         /**
1497          * Removes the supplied dd instance from the supplied group. Executed
1498          * by DragDrop.removeFromGroup, so don't call this function directly.
1499          * @method removeDDFromGroup
1500          * @private
1501          * @static
1502          */
1503         removeDDFromGroup: function(oDD, sGroup) {
1504             if (!this.ids[sGroup]) {
1505                 this.ids[sGroup] = {};
1506             }
1507
1508             var obj = this.ids[sGroup];
1509             if (obj && obj[oDD.id]) {
1510                 delete obj[oDD.id];
1511             }
1512         },
1513
1514         /**
1515          * Unregisters a drag and drop item.  This is executed in
1516          * DragDrop.unreg, use that method instead of calling this directly.
1517          * @method _remove
1518          * @private
1519          * @static
1520          */
1521         _remove: function(oDD) {
1522             for (var g in oDD.groups) {
1523                 if (g && this.ids[g][oDD.id]) {
1524                     delete this.ids[g][oDD.id];
1525                 }
1526             }
1527             delete this.handleIds[oDD.id];
1528         },
1529
1530         /**
1531          * Each DragDrop handle element must be registered.  This is done
1532          * automatically when executing DragDrop.setHandleElId()
1533          * @method regHandle
1534          * @param {String} sDDId the DragDrop id this element is a handle for
1535          * @param {String} sHandleId the id of the element that is the drag
1536          * handle
1537          * @static
1538          */
1539         regHandle: function(sDDId, sHandleId) {
1540             if (!this.handleIds[sDDId]) {
1541                 this.handleIds[sDDId] = {};
1542             }
1543             this.handleIds[sDDId][sHandleId] = sHandleId;
1544         },
1545
1546         /**
1547          * Utility function to determine if a given element has been
1548          * registered as a drag drop item.
1549          * @method isDragDrop
1550          * @param {String} id the element id to check
1551          * @return {boolean} true if this element is a DragDrop item,
1552          * false otherwise
1553          * @static
1554          */
1555         isDragDrop: function(id) {
1556             return ( this.getDDById(id) ) ? true : false;
1557         },
1558
1559         /**
1560          * Returns the drag and drop instances that are in all groups the
1561          * passed in instance belongs to.
1562          * @method getRelated
1563          * @param {DragDrop} p_oDD the obj to get related data for
1564          * @param {boolean} bTargetsOnly if true, only return targetable objs
1565          * @return {DragDrop[]} the related instances
1566          * @static
1567          */
1568         getRelated: function(p_oDD, bTargetsOnly) {
1569             var oDDs = [];
1570             for (var i in p_oDD.groups) {
1571                 for (j in this.ids[i]) {
1572                     var dd = this.ids[i][j];
1573                     if (! this.isTypeOfDD(dd)) {
1574                         continue;
1575                     }
1576                     if (!bTargetsOnly || dd.isTarget) {
1577                         oDDs[oDDs.length] = dd;
1578                     }
1579                 }
1580             }
1581
1582             return oDDs;
1583         },
1584
1585         /**
1586          * Returns true if the specified dd target is a legal target for
1587          * the specifice drag obj
1588          * @method isLegalTarget
1589          * @param {DragDrop} the drag obj
1590          * @param {DragDrop} the target
1591          * @return {boolean} true if the target is a legal target for the
1592          * dd obj
1593          * @static
1594          */
1595         isLegalTarget: function (oDD, oTargetDD) {
1596             var targets = this.getRelated(oDD, true);
1597             for (var i=0, len=targets.length;i<len;++i) {
1598                 if (targets[i].id == oTargetDD.id) {
1599                     return true;
1600                 }
1601             }
1602
1603             return false;
1604         },
1605
1606         /**
1607          * My goal is to be able to transparently determine if an object is
1608          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1609          * returns "object", oDD.constructor.toString() always returns
1610          * "DragDrop" and not the name of the subclass.  So for now it just
1611          * evaluates a well-known variable in DragDrop.
1612          * @method isTypeOfDD
1613          * @param {Object} the object to evaluate
1614          * @return {boolean} true if typeof oDD = DragDrop
1615          * @static
1616          */
1617         isTypeOfDD: function (oDD) {
1618             return (oDD && oDD.__ygDragDrop);
1619         },
1620
1621         /**
1622          * Utility function to determine if a given element has been
1623          * registered as a drag drop handle for the given Drag Drop object.
1624          * @method isHandle
1625          * @param {String} id the element id to check
1626          * @return {boolean} true if this element is a DragDrop handle, false
1627          * otherwise
1628          * @static
1629          */
1630         isHandle: function(sDDId, sHandleId) {
1631             return ( this.handleIds[sDDId] &&
1632                             this.handleIds[sDDId][sHandleId] );
1633         },
1634
1635         /**
1636          * Returns the DragDrop instance for a given id
1637          * @method getDDById
1638          * @param {String} id the id of the DragDrop object
1639          * @return {DragDrop} the drag drop object, null if it is not found
1640          * @static
1641          */
1642         getDDById: function(id) {
1643             for (var i in this.ids) {
1644                 if (this.ids[i][id]) {
1645                     return this.ids[i][id];
1646                 }
1647             }
1648             return null;
1649         },
1650
1651         /**
1652          * Fired after a registered DragDrop object gets the mousedown event.
1653          * Sets up the events required to track the object being dragged
1654          * @method handleMouseDown
1655          * @param {Event} e the event
1656          * @param oDD the DragDrop object being dragged
1657          * @private
1658          * @static
1659          */
1660         handleMouseDown: function(e, oDD) {
1661             if(Roo.QuickTips){
1662                 Roo.QuickTips.disable();
1663             }
1664             this.currentTarget = e.getTarget();
1665
1666             this.dragCurrent = oDD;
1667
1668             var el = oDD.getEl();
1669
1670             // track start position
1671             this.startX = e.getPageX();
1672             this.startY = e.getPageY();
1673
1674             this.deltaX = this.startX - el.offsetLeft;
1675             this.deltaY = this.startY - el.offsetTop;
1676
1677             this.dragThreshMet = false;
1678
1679             this.clickTimeout = setTimeout(
1680                     function() {
1681                         var DDM = Roo.dd.DDM;
1682                         DDM.startDrag(DDM.startX, DDM.startY);
1683                     },
1684                     this.clickTimeThresh );
1685         },
1686
1687         /**
1688          * Fired when either the drag pixel threshol or the mousedown hold
1689          * time threshold has been met.
1690          * @method startDrag
1691          * @param x {int} the X position of the original mousedown
1692          * @param y {int} the Y position of the original mousedown
1693          * @static
1694          */
1695         startDrag: function(x, y) {
1696             clearTimeout(this.clickTimeout);
1697             if (this.dragCurrent) {
1698                 this.dragCurrent.b4StartDrag(x, y);
1699                 this.dragCurrent.startDrag(x, y);
1700             }
1701             this.dragThreshMet = true;
1702         },
1703
1704         /**
1705          * Internal function to handle the mouseup event.  Will be invoked
1706          * from the context of the document.
1707          * @method handleMouseUp
1708          * @param {Event} e the event
1709          * @private
1710          * @static
1711          */
1712         handleMouseUp: function(e) {
1713
1714             if(Roo.QuickTips){
1715                 Roo.QuickTips.enable();
1716             }
1717             if (! this.dragCurrent) {
1718                 return;
1719             }
1720
1721             clearTimeout(this.clickTimeout);
1722
1723             if (this.dragThreshMet) {
1724                 this.fireEvents(e, true);
1725             } else {
1726             }
1727
1728             this.stopDrag(e);
1729
1730             this.stopEvent(e);
1731         },
1732
1733         /**
1734          * Utility to stop event propagation and event default, if these
1735          * features are turned on.
1736          * @method stopEvent
1737          * @param {Event} e the event as returned by this.getEvent()
1738          * @static
1739          */
1740         stopEvent: function(e){
1741             if(this.stopPropagation) {
1742                 e.stopPropagation();
1743             }
1744
1745             if (this.preventDefault) {
1746                 e.preventDefault();
1747             }
1748         },
1749
1750         /**
1751          * Internal function to clean up event handlers after the drag
1752          * operation is complete
1753          * @method stopDrag
1754          * @param {Event} e the event
1755          * @private
1756          * @static
1757          */
1758         stopDrag: function(e) {
1759             // Fire the drag end event for the item that was dragged
1760             if (this.dragCurrent) {
1761                 if (this.dragThreshMet) {
1762                     this.dragCurrent.b4EndDrag(e);
1763                     this.dragCurrent.endDrag(e);
1764                 }
1765
1766                 this.dragCurrent.onMouseUp(e);
1767             }
1768
1769             this.dragCurrent = null;
1770             this.dragOvers = {};
1771         },
1772
1773         /**
1774          * Internal function to handle the mousemove event.  Will be invoked
1775          * from the context of the html element.
1776          *
1777          * @TODO figure out what we can do about mouse events lost when the
1778          * user drags objects beyond the window boundary.  Currently we can
1779          * detect this in internet explorer by verifying that the mouse is
1780          * down during the mousemove event.  Firefox doesn't give us the
1781          * button state on the mousemove event.
1782          * @method handleMouseMove
1783          * @param {Event} e the event
1784          * @private
1785          * @static
1786          */
1787         handleMouseMove: function(e) {
1788             if (! this.dragCurrent) {
1789                 return true;
1790             }
1791
1792             // var button = e.which || e.button;
1793
1794             // check for IE mouseup outside of page boundary
1795             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1796                 this.stopEvent(e);
1797                 return this.handleMouseUp(e);
1798             }
1799
1800             if (!this.dragThreshMet) {
1801                 var diffX = Math.abs(this.startX - e.getPageX());
1802                 var diffY = Math.abs(this.startY - e.getPageY());
1803                 if (diffX > this.clickPixelThresh ||
1804                             diffY > this.clickPixelThresh) {
1805                     this.startDrag(this.startX, this.startY);
1806                 }
1807             }
1808
1809             if (this.dragThreshMet) {
1810                 this.dragCurrent.b4Drag(e);
1811                 this.dragCurrent.onDrag(e);
1812                 if(!this.dragCurrent.moveOnly){
1813                     this.fireEvents(e, false);
1814                 }
1815             }
1816
1817             this.stopEvent(e);
1818
1819             return true;
1820         },
1821
1822         /**
1823          * Iterates over all of the DragDrop elements to find ones we are
1824          * hovering over or dropping on
1825          * @method fireEvents
1826          * @param {Event} e the event
1827          * @param {boolean} isDrop is this a drop op or a mouseover op?
1828          * @private
1829          * @static
1830          */
1831         fireEvents: function(e, isDrop) {
1832             var dc = this.dragCurrent;
1833
1834             // If the user did the mouse up outside of the window, we could
1835             // get here even though we have ended the drag.
1836             if (!dc || dc.isLocked()) {
1837                 return;
1838             }
1839
1840             var pt = e.getPoint();
1841
1842             // cache the previous dragOver array
1843             var oldOvers = [];
1844
1845             var outEvts   = [];
1846             var overEvts  = [];
1847             var dropEvts  = [];
1848             var enterEvts = [];
1849
1850             // Check to see if the object(s) we were hovering over is no longer
1851             // being hovered over so we can fire the onDragOut event
1852             for (var i in this.dragOvers) {
1853
1854                 var ddo = this.dragOvers[i];
1855
1856                 if (! this.isTypeOfDD(ddo)) {
1857                     continue;
1858                 }
1859
1860                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1861                     outEvts.push( ddo );
1862                 }
1863
1864                 oldOvers[i] = true;
1865                 delete this.dragOvers[i];
1866             }
1867
1868             for (var sGroup in dc.groups) {
1869
1870                 if ("string" != typeof sGroup) {
1871                     continue;
1872                 }
1873
1874                 for (i in this.ids[sGroup]) {
1875                     var oDD = this.ids[sGroup][i];
1876                     if (! this.isTypeOfDD(oDD)) {
1877                         continue;
1878                     }
1879
1880                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1881                         if (this.isOverTarget(pt, oDD, this.mode)) {
1882                             // look for drop interactions
1883                             if (isDrop) {
1884                                 dropEvts.push( oDD );
1885                             // look for drag enter and drag over interactions
1886                             } else {
1887
1888                                 // initial drag over: dragEnter fires
1889                                 if (!oldOvers[oDD.id]) {
1890                                     enterEvts.push( oDD );
1891                                 // subsequent drag overs: dragOver fires
1892                                 } else {
1893                                     overEvts.push( oDD );
1894                                 }
1895
1896                                 this.dragOvers[oDD.id] = oDD;
1897                             }
1898                         }
1899                     }
1900                 }
1901             }
1902
1903             if (this.mode) {
1904                 if (outEvts.length) {
1905                     dc.b4DragOut(e, outEvts);
1906                     dc.onDragOut(e, outEvts);
1907                 }
1908
1909                 if (enterEvts.length) {
1910                     dc.onDragEnter(e, enterEvts);
1911                 }
1912
1913                 if (overEvts.length) {
1914                     dc.b4DragOver(e, overEvts);
1915                     dc.onDragOver(e, overEvts);
1916                 }
1917
1918                 if (dropEvts.length) {
1919                     dc.b4DragDrop(e, dropEvts);
1920                     dc.onDragDrop(e, dropEvts);
1921                 }
1922
1923             } else {
1924                 // fire dragout events
1925                 var len = 0;
1926                 for (i=0, len=outEvts.length; i<len; ++i) {
1927                     dc.b4DragOut(e, outEvts[i].id);
1928                     dc.onDragOut(e, outEvts[i].id);
1929                 }
1930
1931                 // fire enter events
1932                 for (i=0,len=enterEvts.length; i<len; ++i) {
1933                     // dc.b4DragEnter(e, oDD.id);
1934                     dc.onDragEnter(e, enterEvts[i].id);
1935                 }
1936
1937                 // fire over events
1938                 for (i=0,len=overEvts.length; i<len; ++i) {
1939                     dc.b4DragOver(e, overEvts[i].id);
1940                     dc.onDragOver(e, overEvts[i].id);
1941                 }
1942
1943                 // fire drop events
1944                 for (i=0, len=dropEvts.length; i<len; ++i) {
1945                     dc.b4DragDrop(e, dropEvts[i].id);
1946                     dc.onDragDrop(e, dropEvts[i].id);
1947                 }
1948
1949             }
1950
1951             // notify about a drop that did not find a target
1952             if (isDrop && !dropEvts.length) {
1953                 dc.onInvalidDrop(e);
1954             }
1955
1956         },
1957
1958         /**
1959          * Helper function for getting the best match from the list of drag
1960          * and drop objects returned by the drag and drop events when we are
1961          * in INTERSECT mode.  It returns either the first object that the
1962          * cursor is over, or the object that has the greatest overlap with
1963          * the dragged element.
1964          * @method getBestMatch
1965          * @param  {DragDrop[]} dds The array of drag and drop objects
1966          * targeted
1967          * @return {DragDrop}       The best single match
1968          * @static
1969          */
1970         getBestMatch: function(dds) {
1971             var winner = null;
1972             // Return null if the input is not what we expect
1973             //if (!dds || !dds.length || dds.length == 0) {
1974                // winner = null;
1975             // If there is only one item, it wins
1976             //} else if (dds.length == 1) {
1977
1978             var len = dds.length;
1979
1980             if (len == 1) {
1981                 winner = dds[0];
1982             } else {
1983                 // Loop through the targeted items
1984                 for (var i=0; i<len; ++i) {
1985                     var dd = dds[i];
1986                     // If the cursor is over the object, it wins.  If the
1987                     // cursor is over multiple matches, the first one we come
1988                     // to wins.
1989                     if (dd.cursorIsOver) {
1990                         winner = dd;
1991                         break;
1992                     // Otherwise the object with the most overlap wins
1993                     } else {
1994                         if (!winner ||
1995                             winner.overlap.getArea() < dd.overlap.getArea()) {
1996                             winner = dd;
1997                         }
1998                     }
1999                 }
2000             }
2001
2002             return winner;
2003         },
2004
2005         /**
2006          * Refreshes the cache of the top-left and bottom-right points of the
2007          * drag and drop objects in the specified group(s).  This is in the
2008          * format that is stored in the drag and drop instance, so typical
2009          * usage is:
2010          * <code>
2011          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2012          * </code>
2013          * Alternatively:
2014          * <code>
2015          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2016          * </code>
2017          * @TODO this really should be an indexed array.  Alternatively this
2018          * method could accept both.
2019          * @method refreshCache
2020          * @param {Object} groups an associative array of groups to refresh
2021          * @static
2022          */
2023         refreshCache: function(groups) {
2024             for (var sGroup in groups) {
2025                 if ("string" != typeof sGroup) {
2026                     continue;
2027                 }
2028                 for (var i in this.ids[sGroup]) {
2029                     var oDD = this.ids[sGroup][i];
2030
2031                     if (this.isTypeOfDD(oDD)) {
2032                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2033                         var loc = this.getLocation(oDD);
2034                         if (loc) {
2035                             this.locationCache[oDD.id] = loc;
2036                         } else {
2037                             delete this.locationCache[oDD.id];
2038                             // this will unregister the drag and drop object if
2039                             // the element is not in a usable state
2040                             // oDD.unreg();
2041                         }
2042                     }
2043                 }
2044             }
2045         },
2046
2047         /**
2048          * This checks to make sure an element exists and is in the DOM.  The
2049          * main purpose is to handle cases where innerHTML is used to remove
2050          * drag and drop objects from the DOM.  IE provides an 'unspecified
2051          * error' when trying to access the offsetParent of such an element
2052          * @method verifyEl
2053          * @param {HTMLElement} el the element to check
2054          * @return {boolean} true if the element looks usable
2055          * @static
2056          */
2057         verifyEl: function(el) {
2058             if (el) {
2059                 var parent;
2060                 if(Roo.isIE){
2061                     try{
2062                         parent = el.offsetParent;
2063                     }catch(e){}
2064                 }else{
2065                     parent = el.offsetParent;
2066                 }
2067                 if (parent) {
2068                     return true;
2069                 }
2070             }
2071
2072             return false;
2073         },
2074
2075         /**
2076          * Returns a Region object containing the drag and drop element's position
2077          * and size, including the padding configured for it
2078          * @method getLocation
2079          * @param {DragDrop} oDD the drag and drop object to get the
2080          *                       location for
2081          * @return {Roo.lib.Region} a Region object representing the total area
2082          *                             the element occupies, including any padding
2083          *                             the instance is configured for.
2084          * @static
2085          */
2086         getLocation: function(oDD) {
2087             if (! this.isTypeOfDD(oDD)) {
2088                 return null;
2089             }
2090
2091             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2092
2093             try {
2094                 pos= Roo.lib.Dom.getXY(el);
2095             } catch (e) { }
2096
2097             if (!pos) {
2098                 return null;
2099             }
2100
2101             x1 = pos[0];
2102             x2 = x1 + el.offsetWidth;
2103             y1 = pos[1];
2104             y2 = y1 + el.offsetHeight;
2105
2106             t = y1 - oDD.padding[0];
2107             r = x2 + oDD.padding[1];
2108             b = y2 + oDD.padding[2];
2109             l = x1 - oDD.padding[3];
2110
2111             return new Roo.lib.Region( t, r, b, l );
2112         },
2113
2114         /**
2115          * Checks the cursor location to see if it over the target
2116          * @method isOverTarget
2117          * @param {Roo.lib.Point} pt The point to evaluate
2118          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2119          * @return {boolean} true if the mouse is over the target
2120          * @private
2121          * @static
2122          */
2123         isOverTarget: function(pt, oTarget, intersect) {
2124             // use cache if available
2125             var loc = this.locationCache[oTarget.id];
2126             if (!loc || !this.useCache) {
2127                 loc = this.getLocation(oTarget);
2128                 this.locationCache[oTarget.id] = loc;
2129
2130             }
2131
2132             if (!loc) {
2133                 return false;
2134             }
2135
2136             oTarget.cursorIsOver = loc.contains( pt );
2137
2138             // DragDrop is using this as a sanity check for the initial mousedown
2139             // in this case we are done.  In POINT mode, if the drag obj has no
2140             // contraints, we are also done. Otherwise we need to evaluate the
2141             // location of the target as related to the actual location of the
2142             // dragged element.
2143             var dc = this.dragCurrent;
2144             if (!dc || !dc.getTargetCoord ||
2145                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2146                 return oTarget.cursorIsOver;
2147             }
2148
2149             oTarget.overlap = null;
2150
2151             // Get the current location of the drag element, this is the
2152             // location of the mouse event less the delta that represents
2153             // where the original mousedown happened on the element.  We
2154             // need to consider constraints and ticks as well.
2155             var pos = dc.getTargetCoord(pt.x, pt.y);
2156
2157             var el = dc.getDragEl();
2158             var curRegion = new Roo.lib.Region( pos.y,
2159                                                    pos.x + el.offsetWidth,
2160                                                    pos.y + el.offsetHeight,
2161                                                    pos.x );
2162
2163             var overlap = curRegion.intersect(loc);
2164
2165             if (overlap) {
2166                 oTarget.overlap = overlap;
2167                 return (intersect) ? true : oTarget.cursorIsOver;
2168             } else {
2169                 return false;
2170             }
2171         },
2172
2173         /**
2174          * unload event handler
2175          * @method _onUnload
2176          * @private
2177          * @static
2178          */
2179         _onUnload: function(e, me) {
2180             Roo.dd.DragDropMgr.unregAll();
2181         },
2182
2183         /**
2184          * Cleans up the drag and drop events and objects.
2185          * @method unregAll
2186          * @private
2187          * @static
2188          */
2189         unregAll: function() {
2190
2191             if (this.dragCurrent) {
2192                 this.stopDrag();
2193                 this.dragCurrent = null;
2194             }
2195
2196             this._execOnAll("unreg", []);
2197
2198             for (i in this.elementCache) {
2199                 delete this.elementCache[i];
2200             }
2201
2202             this.elementCache = {};
2203             this.ids = {};
2204         },
2205
2206         /**
2207          * A cache of DOM elements
2208          * @property elementCache
2209          * @private
2210          * @static
2211          */
2212         elementCache: {},
2213
2214         /**
2215          * Get the wrapper for the DOM element specified
2216          * @method getElWrapper
2217          * @param {String} id the id of the element to get
2218          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2219          * @private
2220          * @deprecated This wrapper isn't that useful
2221          * @static
2222          */
2223         getElWrapper: function(id) {
2224             var oWrapper = this.elementCache[id];
2225             if (!oWrapper || !oWrapper.el) {
2226                 oWrapper = this.elementCache[id] =
2227                     new this.ElementWrapper(Roo.getDom(id));
2228             }
2229             return oWrapper;
2230         },
2231
2232         /**
2233          * Returns the actual DOM element
2234          * @method getElement
2235          * @param {String} id the id of the elment to get
2236          * @return {Object} The element
2237          * @deprecated use Roo.getDom instead
2238          * @static
2239          */
2240         getElement: function(id) {
2241             return Roo.getDom(id);
2242         },
2243
2244         /**
2245          * Returns the style property for the DOM element (i.e.,
2246          * document.getElById(id).style)
2247          * @method getCss
2248          * @param {String} id the id of the elment to get
2249          * @return {Object} The style property of the element
2250          * @deprecated use Roo.getDom instead
2251          * @static
2252          */
2253         getCss: function(id) {
2254             var el = Roo.getDom(id);
2255             return (el) ? el.style : null;
2256         },
2257
2258         /**
2259          * Inner class for cached elements
2260          * @class DragDropMgr.ElementWrapper
2261          * @for DragDropMgr
2262          * @private
2263          * @deprecated
2264          */
2265         ElementWrapper: function(el) {
2266                 /**
2267                  * The element
2268                  * @property el
2269                  */
2270                 this.el = el || null;
2271                 /**
2272                  * The element id
2273                  * @property id
2274                  */
2275                 this.id = this.el && el.id;
2276                 /**
2277                  * A reference to the style property
2278                  * @property css
2279                  */
2280                 this.css = this.el && el.style;
2281             },
2282
2283         /**
2284          * Returns the X position of an html element
2285          * @method getPosX
2286          * @param el the element for which to get the position
2287          * @return {int} the X coordinate
2288          * @for DragDropMgr
2289          * @deprecated use Roo.lib.Dom.getX instead
2290          * @static
2291          */
2292         getPosX: function(el) {
2293             return Roo.lib.Dom.getX(el);
2294         },
2295
2296         /**
2297          * Returns the Y position of an html element
2298          * @method getPosY
2299          * @param el the element for which to get the position
2300          * @return {int} the Y coordinate
2301          * @deprecated use Roo.lib.Dom.getY instead
2302          * @static
2303          */
2304         getPosY: function(el) {
2305             return Roo.lib.Dom.getY(el);
2306         },
2307
2308         /**
2309          * Swap two nodes.  In IE, we use the native method, for others we
2310          * emulate the IE behavior
2311          * @method swapNode
2312          * @param n1 the first node to swap
2313          * @param n2 the other node to swap
2314          * @static
2315          */
2316         swapNode: function(n1, n2) {
2317             if (n1.swapNode) {
2318                 n1.swapNode(n2);
2319             } else {
2320                 var p = n2.parentNode;
2321                 var s = n2.nextSibling;
2322
2323                 if (s == n1) {
2324                     p.insertBefore(n1, n2);
2325                 } else if (n2 == n1.nextSibling) {
2326                     p.insertBefore(n2, n1);
2327                 } else {
2328                     n1.parentNode.replaceChild(n2, n1);
2329                     p.insertBefore(n1, s);
2330                 }
2331             }
2332         },
2333
2334         /**
2335          * Returns the current scroll position
2336          * @method getScroll
2337          * @private
2338          * @static
2339          */
2340         getScroll: function () {
2341             var t, l, dde=document.documentElement, db=document.body;
2342             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2343                 t = dde.scrollTop;
2344                 l = dde.scrollLeft;
2345             } else if (db) {
2346                 t = db.scrollTop;
2347                 l = db.scrollLeft;
2348             } else {
2349
2350             }
2351             return { top: t, left: l };
2352         },
2353
2354         /**
2355          * Returns the specified element style property
2356          * @method getStyle
2357          * @param {HTMLElement} el          the element
2358          * @param {string}      styleProp   the style property
2359          * @return {string} The value of the style property
2360          * @deprecated use Roo.lib.Dom.getStyle
2361          * @static
2362          */
2363         getStyle: function(el, styleProp) {
2364             return Roo.fly(el).getStyle(styleProp);
2365         },
2366
2367         /**
2368          * Gets the scrollTop
2369          * @method getScrollTop
2370          * @return {int} the document's scrollTop
2371          * @static
2372          */
2373         getScrollTop: function () { return this.getScroll().top; },
2374
2375         /**
2376          * Gets the scrollLeft
2377          * @method getScrollLeft
2378          * @return {int} the document's scrollTop
2379          * @static
2380          */
2381         getScrollLeft: function () { return this.getScroll().left; },
2382
2383         /**
2384          * Sets the x/y position of an element to the location of the
2385          * target element.
2386          * @method moveToEl
2387          * @param {HTMLElement} moveEl      The element to move
2388          * @param {HTMLElement} targetEl    The position reference element
2389          * @static
2390          */
2391         moveToEl: function (moveEl, targetEl) {
2392             var aCoord = Roo.lib.Dom.getXY(targetEl);
2393             Roo.lib.Dom.setXY(moveEl, aCoord);
2394         },
2395
2396         /**
2397          * Numeric array sort function
2398          * @method numericSort
2399          * @static
2400          */
2401         numericSort: function(a, b) { return (a - b); },
2402
2403         /**
2404          * Internal counter
2405          * @property _timeoutCount
2406          * @private
2407          * @static
2408          */
2409         _timeoutCount: 0,
2410
2411         /**
2412          * Trying to make the load order less important.  Without this we get
2413          * an error if this file is loaded before the Event Utility.
2414          * @method _addListeners
2415          * @private
2416          * @static
2417          */
2418         _addListeners: function() {
2419             var DDM = Roo.dd.DDM;
2420             if ( Roo.lib.Event && document ) {
2421                 DDM._onLoad();
2422             } else {
2423                 if (DDM._timeoutCount > 2000) {
2424                 } else {
2425                     setTimeout(DDM._addListeners, 10);
2426                     if (document && document.body) {
2427                         DDM._timeoutCount += 1;
2428                     }
2429                 }
2430             }
2431         },
2432
2433         /**
2434          * Recursively searches the immediate parent and all child nodes for
2435          * the handle element in order to determine wheter or not it was
2436          * clicked.
2437          * @method handleWasClicked
2438          * @param node the html element to inspect
2439          * @static
2440          */
2441         handleWasClicked: function(node, id) {
2442             if (this.isHandle(id, node.id)) {
2443                 return true;
2444             } else {
2445                 // check to see if this is a text node child of the one we want
2446                 var p = node.parentNode;
2447
2448                 while (p) {
2449                     if (this.isHandle(id, p.id)) {
2450                         return true;
2451                     } else {
2452                         p = p.parentNode;
2453                     }
2454                 }
2455             }
2456
2457             return false;
2458         }
2459
2460     };
2461
2462 }();
2463
2464 // shorter alias, save a few bytes
2465 Roo.dd.DDM = Roo.dd.DragDropMgr;
2466 Roo.dd.DDM._addListeners();
2467
2468 }/*
2469  * Based on:
2470  * Ext JS Library 1.1.1
2471  * Copyright(c) 2006-2007, Ext JS, LLC.
2472  *
2473  * Originally Released Under LGPL - original licence link has changed is not relivant.
2474  *
2475  * Fork - LGPL
2476  * <script type="text/javascript">
2477  */
2478
2479 /**
2480  * @class Roo.dd.DD
2481  * A DragDrop implementation where the linked element follows the
2482  * mouse cursor during a drag.
2483  * @extends Roo.dd.DragDrop
2484  * @constructor
2485  * @param {String} id the id of the linked element
2486  * @param {String} sGroup the group of related DragDrop items
2487  * @param {object} config an object containing configurable attributes
2488  *                Valid properties for DD:
2489  *                    scroll
2490  */
2491 Roo.dd.DD = function(id, sGroup, config) {
2492     if (id) {
2493         this.init(id, sGroup, config);
2494     }
2495 };
2496
2497 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2498
2499     /**
2500      * When set to true, the utility automatically tries to scroll the browser
2501      * window wehn a drag and drop element is dragged near the viewport boundary.
2502      * Defaults to true.
2503      * @property scroll
2504      * @type boolean
2505      */
2506     scroll: true,
2507
2508     /**
2509      * Sets the pointer offset to the distance between the linked element's top
2510      * left corner and the location the element was clicked
2511      * @method autoOffset
2512      * @param {int} iPageX the X coordinate of the click
2513      * @param {int} iPageY the Y coordinate of the click
2514      */
2515     autoOffset: function(iPageX, iPageY) {
2516         var x = iPageX - this.startPageX;
2517         var y = iPageY - this.startPageY;
2518         this.setDelta(x, y);
2519     },
2520
2521     /**
2522      * Sets the pointer offset.  You can call this directly to force the
2523      * offset to be in a particular location (e.g., pass in 0,0 to set it
2524      * to the center of the object)
2525      * @method setDelta
2526      * @param {int} iDeltaX the distance from the left
2527      * @param {int} iDeltaY the distance from the top
2528      */
2529     setDelta: function(iDeltaX, iDeltaY) {
2530         this.deltaX = iDeltaX;
2531         this.deltaY = iDeltaY;
2532     },
2533
2534     /**
2535      * Sets the drag element to the location of the mousedown or click event,
2536      * maintaining the cursor location relative to the location on the element
2537      * that was clicked.  Override this if you want to place the element in a
2538      * location other than where the cursor is.
2539      * @method setDragElPos
2540      * @param {int} iPageX the X coordinate of the mousedown or drag event
2541      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2542      */
2543     setDragElPos: function(iPageX, iPageY) {
2544         // the first time we do this, we are going to check to make sure
2545         // the element has css positioning
2546
2547         var el = this.getDragEl();
2548         this.alignElWithMouse(el, iPageX, iPageY);
2549     },
2550
2551     /**
2552      * Sets the element to the location of the mousedown or click event,
2553      * maintaining the cursor location relative to the location on the element
2554      * that was clicked.  Override this if you want to place the element in a
2555      * location other than where the cursor is.
2556      * @method alignElWithMouse
2557      * @param {HTMLElement} el the element to move
2558      * @param {int} iPageX the X coordinate of the mousedown or drag event
2559      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2560      */
2561     alignElWithMouse: function(el, iPageX, iPageY) {
2562         var oCoord = this.getTargetCoord(iPageX, iPageY);
2563         var fly = el.dom ? el : Roo.fly(el);
2564         if (!this.deltaSetXY) {
2565             var aCoord = [oCoord.x, oCoord.y];
2566             fly.setXY(aCoord);
2567             var newLeft = fly.getLeft(true);
2568             var newTop  = fly.getTop(true);
2569             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2570         } else {
2571             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2572         }
2573
2574         this.cachePosition(oCoord.x, oCoord.y);
2575         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2576         return oCoord;
2577     },
2578
2579     /**
2580      * Saves the most recent position so that we can reset the constraints and
2581      * tick marks on-demand.  We need to know this so that we can calculate the
2582      * number of pixels the element is offset from its original position.
2583      * @method cachePosition
2584      * @param iPageX the current x position (optional, this just makes it so we
2585      * don't have to look it up again)
2586      * @param iPageY the current y position (optional, this just makes it so we
2587      * don't have to look it up again)
2588      */
2589     cachePosition: function(iPageX, iPageY) {
2590         if (iPageX) {
2591             this.lastPageX = iPageX;
2592             this.lastPageY = iPageY;
2593         } else {
2594             var aCoord = Roo.lib.Dom.getXY(this.getEl());
2595             this.lastPageX = aCoord[0];
2596             this.lastPageY = aCoord[1];
2597         }
2598     },
2599
2600     /**
2601      * Auto-scroll the window if the dragged object has been moved beyond the
2602      * visible window boundary.
2603      * @method autoScroll
2604      * @param {int} x the drag element's x position
2605      * @param {int} y the drag element's y position
2606      * @param {int} h the height of the drag element
2607      * @param {int} w the width of the drag element
2608      * @private
2609      */
2610     autoScroll: function(x, y, h, w) {
2611
2612         if (this.scroll) {
2613             // The client height
2614             var clientH = Roo.lib.Dom.getViewWidth();
2615
2616             // The client width
2617             var clientW = Roo.lib.Dom.getViewHeight();
2618
2619             // The amt scrolled down
2620             var st = this.DDM.getScrollTop();
2621
2622             // The amt scrolled right
2623             var sl = this.DDM.getScrollLeft();
2624
2625             // Location of the bottom of the element
2626             var bot = h + y;
2627
2628             // Location of the right of the element
2629             var right = w + x;
2630
2631             // The distance from the cursor to the bottom of the visible area,
2632             // adjusted so that we don't scroll if the cursor is beyond the
2633             // element drag constraints
2634             var toBot = (clientH + st - y - this.deltaY);
2635
2636             // The distance from the cursor to the right of the visible area
2637             var toRight = (clientW + sl - x - this.deltaX);
2638
2639
2640             // How close to the edge the cursor must be before we scroll
2641             // var thresh = (document.all) ? 100 : 40;
2642             var thresh = 40;
2643
2644             // How many pixels to scroll per autoscroll op.  This helps to reduce
2645             // clunky scrolling. IE is more sensitive about this ... it needs this
2646             // value to be higher.
2647             var scrAmt = (document.all) ? 80 : 30;
2648
2649             // Scroll down if we are near the bottom of the visible page and the
2650             // obj extends below the crease
2651             if ( bot > clientH && toBot < thresh ) {
2652                 window.scrollTo(sl, st + scrAmt);
2653             }
2654
2655             // Scroll up if the window is scrolled down and the top of the object
2656             // goes above the top border
2657             if ( y < st && st > 0 && y - st < thresh ) {
2658                 window.scrollTo(sl, st - scrAmt);
2659             }
2660
2661             // Scroll right if the obj is beyond the right border and the cursor is
2662             // near the border.
2663             if ( right > clientW && toRight < thresh ) {
2664                 window.scrollTo(sl + scrAmt, st);
2665             }
2666
2667             // Scroll left if the window has been scrolled to the right and the obj
2668             // extends past the left border
2669             if ( x < sl && sl > 0 && x - sl < thresh ) {
2670                 window.scrollTo(sl - scrAmt, st);
2671             }
2672         }
2673     },
2674
2675     /**
2676      * Finds the location the element should be placed if we want to move
2677      * it to where the mouse location less the click offset would place us.
2678      * @method getTargetCoord
2679      * @param {int} iPageX the X coordinate of the click
2680      * @param {int} iPageY the Y coordinate of the click
2681      * @return an object that contains the coordinates (Object.x and Object.y)
2682      * @private
2683      */
2684     getTargetCoord: function(iPageX, iPageY) {
2685
2686
2687         var x = iPageX - this.deltaX;
2688         var y = iPageY - this.deltaY;
2689
2690         if (this.constrainX) {
2691             if (x < this.minX) { x = this.minX; }
2692             if (x > this.maxX) { x = this.maxX; }
2693         }
2694
2695         if (this.constrainY) {
2696             if (y < this.minY) { y = this.minY; }
2697             if (y > this.maxY) { y = this.maxY; }
2698         }
2699
2700         x = this.getTick(x, this.xTicks);
2701         y = this.getTick(y, this.yTicks);
2702
2703
2704         return {x:x, y:y};
2705     },
2706
2707     /*
2708      * Sets up config options specific to this class. Overrides
2709      * Roo.dd.DragDrop, but all versions of this method through the
2710      * inheritance chain are called
2711      */
2712     applyConfig: function() {
2713         Roo.dd.DD.superclass.applyConfig.call(this);
2714         this.scroll = (this.config.scroll !== false);
2715     },
2716
2717     /*
2718      * Event that fires prior to the onMouseDown event.  Overrides
2719      * Roo.dd.DragDrop.
2720      */
2721     b4MouseDown: function(e) {
2722         // this.resetConstraints();
2723         this.autoOffset(e.getPageX(),
2724                             e.getPageY());
2725     },
2726
2727     /*
2728      * Event that fires prior to the onDrag event.  Overrides
2729      * Roo.dd.DragDrop.
2730      */
2731     b4Drag: function(e) {
2732         this.setDragElPos(e.getPageX(),
2733                             e.getPageY());
2734     },
2735
2736     toString: function() {
2737         return ("DD " + this.id);
2738     }
2739
2740     //////////////////////////////////////////////////////////////////////////
2741     // Debugging ygDragDrop events that can be overridden
2742     //////////////////////////////////////////////////////////////////////////
2743     /*
2744     startDrag: function(x, y) {
2745     },
2746
2747     onDrag: function(e) {
2748     },
2749
2750     onDragEnter: function(e, id) {
2751     },
2752
2753     onDragOver: function(e, id) {
2754     },
2755
2756     onDragOut: function(e, id) {
2757     },
2758
2759     onDragDrop: function(e, id) {
2760     },
2761
2762     endDrag: function(e) {
2763     }
2764
2765     */
2766
2767 });/*
2768  * Based on:
2769  * Ext JS Library 1.1.1
2770  * Copyright(c) 2006-2007, Ext JS, LLC.
2771  *
2772  * Originally Released Under LGPL - original licence link has changed is not relivant.
2773  *
2774  * Fork - LGPL
2775  * <script type="text/javascript">
2776  */
2777
2778 /**
2779  * @class Roo.dd.DDProxy
2780  * A DragDrop implementation that inserts an empty, bordered div into
2781  * the document that follows the cursor during drag operations.  At the time of
2782  * the click, the frame div is resized to the dimensions of the linked html
2783  * element, and moved to the exact location of the linked element.
2784  *
2785  * References to the "frame" element refer to the single proxy element that
2786  * was created to be dragged in place of all DDProxy elements on the
2787  * page.
2788  *
2789  * @extends Roo.dd.DD
2790  * @constructor
2791  * @param {String} id the id of the linked html element
2792  * @param {String} sGroup the group of related DragDrop objects
2793  * @param {object} config an object containing configurable attributes
2794  *                Valid properties for DDProxy in addition to those in DragDrop:
2795  *                   resizeFrame, centerFrame, dragElId
2796  */
2797 Roo.dd.DDProxy = function(id, sGroup, config) {
2798     if (id) {
2799         this.init(id, sGroup, config);
2800         this.initFrame();
2801     }
2802 };
2803
2804 /**
2805  * The default drag frame div id
2806  * @property Roo.dd.DDProxy.dragElId
2807  * @type String
2808  * @static
2809  */
2810 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2811
2812 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2813
2814     /**
2815      * By default we resize the drag frame to be the same size as the element
2816      * we want to drag (this is to get the frame effect).  We can turn it off
2817      * if we want a different behavior.
2818      * @property resizeFrame
2819      * @type boolean
2820      */
2821     resizeFrame: true,
2822
2823     /**
2824      * By default the frame is positioned exactly where the drag element is, so
2825      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
2826      * you do not have constraints on the obj is to have the drag frame centered
2827      * around the cursor.  Set centerFrame to true for this effect.
2828      * @property centerFrame
2829      * @type boolean
2830      */
2831     centerFrame: false,
2832
2833     /**
2834      * Creates the proxy element if it does not yet exist
2835      * @method createFrame
2836      */
2837     createFrame: function() {
2838         var self = this;
2839         var body = document.body;
2840
2841         if (!body || !body.firstChild) {
2842             setTimeout( function() { self.createFrame(); }, 50 );
2843             return;
2844         }
2845
2846         var div = this.getDragEl();
2847
2848         if (!div) {
2849             div    = document.createElement("div");
2850             div.id = this.dragElId;
2851             var s  = div.style;
2852
2853             s.position   = "absolute";
2854             s.visibility = "hidden";
2855             s.cursor     = "move";
2856             s.border     = "2px solid #aaa";
2857             s.zIndex     = 999;
2858
2859             // appendChild can blow up IE if invoked prior to the window load event
2860             // while rendering a table.  It is possible there are other scenarios
2861             // that would cause this to happen as well.
2862             body.insertBefore(div, body.firstChild);
2863         }
2864     },
2865
2866     /**
2867      * Initialization for the drag frame element.  Must be called in the
2868      * constructor of all subclasses
2869      * @method initFrame
2870      */
2871     initFrame: function() {
2872         this.createFrame();
2873     },
2874
2875     applyConfig: function() {
2876         Roo.dd.DDProxy.superclass.applyConfig.call(this);
2877
2878         this.resizeFrame = (this.config.resizeFrame !== false);
2879         this.centerFrame = (this.config.centerFrame);
2880         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2881     },
2882
2883     /**
2884      * Resizes the drag frame to the dimensions of the clicked object, positions
2885      * it over the object, and finally displays it
2886      * @method showFrame
2887      * @param {int} iPageX X click position
2888      * @param {int} iPageY Y click position
2889      * @private
2890      */
2891     showFrame: function(iPageX, iPageY) {
2892         var el = this.getEl();
2893         var dragEl = this.getDragEl();
2894         var s = dragEl.style;
2895
2896         this._resizeProxy();
2897
2898         if (this.centerFrame) {
2899             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2900                            Math.round(parseInt(s.height, 10)/2) );
2901         }
2902
2903         this.setDragElPos(iPageX, iPageY);
2904
2905         Roo.fly(dragEl).show();
2906     },
2907
2908     /**
2909      * The proxy is automatically resized to the dimensions of the linked
2910      * element when a drag is initiated, unless resizeFrame is set to false
2911      * @method _resizeProxy
2912      * @private
2913      */
2914     _resizeProxy: function() {
2915         if (this.resizeFrame) {
2916             var el = this.getEl();
2917             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2918         }
2919     },
2920
2921     // overrides Roo.dd.DragDrop
2922     b4MouseDown: function(e) {
2923         var x = e.getPageX();
2924         var y = e.getPageY();
2925         this.autoOffset(x, y);
2926         this.setDragElPos(x, y);
2927     },
2928
2929     // overrides Roo.dd.DragDrop
2930     b4StartDrag: function(x, y) {
2931         // show the drag frame
2932         this.showFrame(x, y);
2933     },
2934
2935     // overrides Roo.dd.DragDrop
2936     b4EndDrag: function(e) {
2937         Roo.fly(this.getDragEl()).hide();
2938     },
2939
2940     // overrides Roo.dd.DragDrop
2941     // By default we try to move the element to the last location of the frame.
2942     // This is so that the default behavior mirrors that of Roo.dd.DD.
2943     endDrag: function(e) {
2944
2945         var lel = this.getEl();
2946         var del = this.getDragEl();
2947
2948         // Show the drag frame briefly so we can get its position
2949         del.style.visibility = "";
2950
2951         this.beforeMove();
2952         // Hide the linked element before the move to get around a Safari
2953         // rendering bug.
2954         lel.style.visibility = "hidden";
2955         Roo.dd.DDM.moveToEl(lel, del);
2956         del.style.visibility = "hidden";
2957         lel.style.visibility = "";
2958
2959         this.afterDrag();
2960     },
2961
2962     beforeMove : function(){
2963
2964     },
2965
2966     afterDrag : function(){
2967
2968     },
2969
2970     toString: function() {
2971         return ("DDProxy " + this.id);
2972     }
2973
2974 });
2975 /*
2976  * Based on:
2977  * Ext JS Library 1.1.1
2978  * Copyright(c) 2006-2007, Ext JS, LLC.
2979  *
2980  * Originally Released Under LGPL - original licence link has changed is not relivant.
2981  *
2982  * Fork - LGPL
2983  * <script type="text/javascript">
2984  */
2985
2986  /**
2987  * @class Roo.dd.DDTarget
2988  * A DragDrop implementation that does not move, but can be a drop
2989  * target.  You would get the same result by simply omitting implementation
2990  * for the event callbacks, but this way we reduce the processing cost of the
2991  * event listener and the callbacks.
2992  * @extends Roo.dd.DragDrop
2993  * @constructor
2994  * @param {String} id the id of the element that is a drop target
2995  * @param {String} sGroup the group of related DragDrop objects
2996  * @param {object} config an object containing configurable attributes
2997  *                 Valid properties for DDTarget in addition to those in
2998  *                 DragDrop:
2999  *                    none
3000  */
3001 Roo.dd.DDTarget = function(id, sGroup, config) {
3002     if (id) {
3003         this.initTarget(id, sGroup, config);
3004     }
3005     if (config.listeners || config.events) { 
3006        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
3007             listeners : config.listeners || {}, 
3008             events : config.events || {} 
3009         });    
3010     }
3011 };
3012
3013 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3014 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3015     toString: function() {
3016         return ("DDTarget " + this.id);
3017     }
3018 });
3019 /*
3020  * Based on:
3021  * Ext JS Library 1.1.1
3022  * Copyright(c) 2006-2007, Ext JS, LLC.
3023  *
3024  * Originally Released Under LGPL - original licence link has changed is not relivant.
3025  *
3026  * Fork - LGPL
3027  * <script type="text/javascript">
3028  */
3029  
3030
3031 /**
3032  * @class Roo.dd.ScrollManager
3033  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3034  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035  * @singleton
3036  */
3037 Roo.dd.ScrollManager = function(){
3038     var ddm = Roo.dd.DragDropMgr;
3039     var els = {};
3040     var dragEl = null;
3041     var proc = {};
3042     
3043     var onStop = function(e){
3044         dragEl = null;
3045         clearProc();
3046     };
3047     
3048     var triggerRefresh = function(){
3049         if(ddm.dragCurrent){
3050              ddm.refreshCache(ddm.dragCurrent.groups);
3051         }
3052     };
3053     
3054     var doScroll = function(){
3055         if(ddm.dragCurrent){
3056             var dds = Roo.dd.ScrollManager;
3057             if(!dds.animate){
3058                 if(proc.el.scroll(proc.dir, dds.increment)){
3059                     triggerRefresh();
3060                 }
3061             }else{
3062                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3063             }
3064         }
3065     };
3066     
3067     var clearProc = function(){
3068         if(proc.id){
3069             clearInterval(proc.id);
3070         }
3071         proc.id = 0;
3072         proc.el = null;
3073         proc.dir = "";
3074     };
3075     
3076     var startProc = function(el, dir){
3077         clearProc();
3078         proc.el = el;
3079         proc.dir = dir;
3080         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081     };
3082     
3083     var onFire = function(e, isDrop){
3084         if(isDrop || !ddm.dragCurrent){ return; }
3085         var dds = Roo.dd.ScrollManager;
3086         if(!dragEl || dragEl != ddm.dragCurrent){
3087             dragEl = ddm.dragCurrent;
3088             // refresh regions on drag start
3089             dds.refreshCache();
3090         }
3091         
3092         var xy = Roo.lib.Event.getXY(e);
3093         var pt = new Roo.lib.Point(xy[0], xy[1]);
3094         for(var id in els){
3095             var el = els[id], r = el._region;
3096             if(r && r.contains(pt) && el.isScrollable()){
3097                 if(r.bottom - pt.y <= dds.thresh){
3098                     if(proc.el != el){
3099                         startProc(el, "down");
3100                     }
3101                     return;
3102                 }else if(r.right - pt.x <= dds.thresh){
3103                     if(proc.el != el){
3104                         startProc(el, "left");
3105                     }
3106                     return;
3107                 }else if(pt.y - r.top <= dds.thresh){
3108                     if(proc.el != el){
3109                         startProc(el, "up");
3110                     }
3111                     return;
3112                 }else if(pt.x - r.left <= dds.thresh){
3113                     if(proc.el != el){
3114                         startProc(el, "right");
3115                     }
3116                     return;
3117                 }
3118             }
3119         }
3120         clearProc();
3121     };
3122     
3123     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3124     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3125     
3126     return {
3127         /**
3128          * Registers new overflow element(s) to auto scroll
3129          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3130          */
3131         register : function(el){
3132             if(el instanceof Array){
3133                 for(var i = 0, len = el.length; i < len; i++) {
3134                         this.register(el[i]);
3135                 }
3136             }else{
3137                 el = Roo.get(el);
3138                 els[el.id] = el;
3139             }
3140         },
3141         
3142         /**
3143          * Unregisters overflow element(s) so they are no longer scrolled
3144          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3145          */
3146         unregister : function(el){
3147             if(el instanceof Array){
3148                 for(var i = 0, len = el.length; i < len; i++) {
3149                         this.unregister(el[i]);
3150                 }
3151             }else{
3152                 el = Roo.get(el);
3153                 delete els[el.id];
3154             }
3155         },
3156         
3157         /**
3158          * The number of pixels from the edge of a container the pointer needs to be to 
3159          * trigger scrolling (defaults to 25)
3160          * @type Number
3161          */
3162         thresh : 25,
3163         
3164         /**
3165          * The number of pixels to scroll in each scroll increment (defaults to 50)
3166          * @type Number
3167          */
3168         increment : 100,
3169         
3170         /**
3171          * The frequency of scrolls in milliseconds (defaults to 500)
3172          * @type Number
3173          */
3174         frequency : 500,
3175         
3176         /**
3177          * True to animate the scroll (defaults to true)
3178          * @type Boolean
3179          */
3180         animate: true,
3181         
3182         /**
3183          * The animation duration in seconds - 
3184          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3185          * @type Number
3186          */
3187         animDuration: .4,
3188         
3189         /**
3190          * Manually trigger a cache refresh.
3191          */
3192         refreshCache : function(){
3193             for(var id in els){
3194                 if(typeof els[id] == 'object'){ // for people extending the object prototype
3195                     els[id]._region = els[id].getRegion();
3196                 }
3197             }
3198         }
3199     };
3200 }();/*
3201  * Based on:
3202  * Ext JS Library 1.1.1
3203  * Copyright(c) 2006-2007, Ext JS, LLC.
3204  *
3205  * Originally Released Under LGPL - original licence link has changed is not relivant.
3206  *
3207  * Fork - LGPL
3208  * <script type="text/javascript">
3209  */
3210  
3211
3212 /**
3213  * @class Roo.dd.Registry
3214  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
3215  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216  * @singleton
3217  */
3218 Roo.dd.Registry = function(){
3219     var elements = {}; 
3220     var handles = {}; 
3221     var autoIdSeed = 0;
3222
3223     var getId = function(el, autogen){
3224         if(typeof el == "string"){
3225             return el;
3226         }
3227         var id = el.id;
3228         if(!id && autogen !== false){
3229             id = "roodd-" + (++autoIdSeed);
3230             el.id = id;
3231         }
3232         return id;
3233     };
3234     
3235     return {
3236     /**
3237      * Register a drag drop element
3238      * @param {String|HTMLElement} element The id or DOM node to register
3239      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3240      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
3241      * knows how to interpret, plus there are some specific properties known to the Registry that should be
3242      * populated in the data object (if applicable):
3243      * <pre>
3244 Value      Description<br />
3245 ---------  ------------------------------------------<br />
3246 handles    Array of DOM nodes that trigger dragging<br />
3247            for the element being registered<br />
3248 isHandle   True if the element passed in triggers<br />
3249            dragging itself, else false
3250 </pre>
3251      */
3252         register : function(el, data){
3253             data = data || {};
3254             if(typeof el == "string"){
3255                 el = document.getElementById(el);
3256             }
3257             data.ddel = el;
3258             elements[getId(el)] = data;
3259             if(data.isHandle !== false){
3260                 handles[data.ddel.id] = data;
3261             }
3262             if(data.handles){
3263                 var hs = data.handles;
3264                 for(var i = 0, len = hs.length; i < len; i++){
3265                         handles[getId(hs[i])] = data;
3266                 }
3267             }
3268         },
3269
3270     /**
3271      * Unregister a drag drop element
3272      * @param {String|HTMLElement}  element The id or DOM node to unregister
3273      */
3274         unregister : function(el){
3275             var id = getId(el, false);
3276             var data = elements[id];
3277             if(data){
3278                 delete elements[id];
3279                 if(data.handles){
3280                     var hs = data.handles;
3281                     for(var i = 0, len = hs.length; i < len; i++){
3282                         delete handles[getId(hs[i], false)];
3283                     }
3284                 }
3285             }
3286         },
3287
3288     /**
3289      * Returns the handle registered for a DOM Node by id
3290      * @param {String|HTMLElement} id The DOM node or id to look up
3291      * @return {Object} handle The custom handle data
3292      */
3293         getHandle : function(id){
3294             if(typeof id != "string"){ // must be element?
3295                 id = id.id;
3296             }
3297             return handles[id];
3298         },
3299
3300     /**
3301      * Returns the handle that is registered for the DOM node that is the target of the event
3302      * @param {Event} e The event
3303      * @return {Object} handle The custom handle data
3304      */
3305         getHandleFromEvent : function(e){
3306             var t = Roo.lib.Event.getTarget(e);
3307             return t ? handles[t.id] : null;
3308         },
3309
3310     /**
3311      * Returns a custom data object that is registered for a DOM node by id
3312      * @param {String|HTMLElement} id The DOM node or id to look up
3313      * @return {Object} data The custom data
3314      */
3315         getTarget : function(id){
3316             if(typeof id != "string"){ // must be element?
3317                 id = id.id;
3318             }
3319             return elements[id];
3320         },
3321
3322     /**
3323      * Returns a custom data object that is registered for the DOM node that is the target of the event
3324      * @param {Event} e The event
3325      * @return {Object} data The custom data
3326      */
3327         getTargetFromEvent : function(e){
3328             var t = Roo.lib.Event.getTarget(e);
3329             return t ? elements[t.id] || handles[t.id] : null;
3330         }
3331     };
3332 }();/*
3333  * Based on:
3334  * Ext JS Library 1.1.1
3335  * Copyright(c) 2006-2007, Ext JS, LLC.
3336  *
3337  * Originally Released Under LGPL - original licence link has changed is not relivant.
3338  *
3339  * Fork - LGPL
3340  * <script type="text/javascript">
3341  */
3342  
3343
3344 /**
3345  * @class Roo.dd.StatusProxy
3346  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
3347  * default drag proxy used by all Roo.dd components.
3348  * @constructor
3349  * @param {Object} config
3350  */
3351 Roo.dd.StatusProxy = function(config){
3352     Roo.apply(this, config);
3353     this.id = this.id || Roo.id();
3354     this.el = new Roo.Layer({
3355         dh: {
3356             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3357                 {tag: "div", cls: "x-dd-drop-icon"},
3358                 {tag: "div", cls: "x-dd-drag-ghost"}
3359             ]
3360         }, 
3361         shadow: !config || config.shadow !== false
3362     });
3363     this.ghost = Roo.get(this.el.dom.childNodes[1]);
3364     this.dropStatus = this.dropNotAllowed;
3365 };
3366
3367 Roo.dd.StatusProxy.prototype = {
3368     /**
3369      * @cfg {String} dropAllowed
3370      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3371      */
3372     dropAllowed : "x-dd-drop-ok",
3373     /**
3374      * @cfg {String} dropNotAllowed
3375      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3376      */
3377     dropNotAllowed : "x-dd-drop-nodrop",
3378
3379     /**
3380      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3381      * over the current target element.
3382      * @param {String} cssClass The css class for the new drop status indicator image
3383      */
3384     setStatus : function(cssClass){
3385         cssClass = cssClass || this.dropNotAllowed;
3386         if(this.dropStatus != cssClass){
3387             this.el.replaceClass(this.dropStatus, cssClass);
3388             this.dropStatus = cssClass;
3389         }
3390     },
3391
3392     /**
3393      * Resets the status indicator to the default dropNotAllowed value
3394      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3395      */
3396     reset : function(clearGhost){
3397         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3398         this.dropStatus = this.dropNotAllowed;
3399         if(clearGhost){
3400             this.ghost.update("");
3401         }
3402     },
3403
3404     /**
3405      * Updates the contents of the ghost element
3406      * @param {String} html The html that will replace the current innerHTML of the ghost element
3407      */
3408     update : function(html){
3409         if(typeof html == "string"){
3410             this.ghost.update(html);
3411         }else{
3412             this.ghost.update("");
3413             html.style.margin = "0";
3414             this.ghost.dom.appendChild(html);
3415         }
3416         // ensure float = none set?? cant remember why though.
3417         var el = this.ghost.dom.firstChild;
3418                 if(el){
3419                         Roo.fly(el).setStyle('float', 'none');
3420                 }
3421     },
3422     
3423     /**
3424      * Returns the underlying proxy {@link Roo.Layer}
3425      * @return {Roo.Layer} el
3426     */
3427     getEl : function(){
3428         return this.el;
3429     },
3430
3431     /**
3432      * Returns the ghost element
3433      * @return {Roo.Element} el
3434      */
3435     getGhost : function(){
3436         return this.ghost;
3437     },
3438
3439     /**
3440      * Hides the proxy
3441      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3442      */
3443     hide : function(clear){
3444         this.el.hide();
3445         if(clear){
3446             this.reset(true);
3447         }
3448     },
3449
3450     /**
3451      * Stops the repair animation if it's currently running
3452      */
3453     stop : function(){
3454         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3455             this.anim.stop();
3456         }
3457     },
3458
3459     /**
3460      * Displays this proxy
3461      */
3462     show : function(){
3463         this.el.show();
3464     },
3465
3466     /**
3467      * Force the Layer to sync its shadow and shim positions to the element
3468      */
3469     sync : function(){
3470         this.el.sync();
3471     },
3472
3473     /**
3474      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
3475      * invalid drop operation by the item being dragged.
3476      * @param {Array} xy The XY position of the element ([x, y])
3477      * @param {Function} callback The function to call after the repair is complete
3478      * @param {Object} scope The scope in which to execute the callback
3479      */
3480     repair : function(xy, callback, scope){
3481         this.callback = callback;
3482         this.scope = scope;
3483         if(xy && this.animRepair !== false){
3484             this.el.addClass("x-dd-drag-repair");
3485             this.el.hideUnders(true);
3486             this.anim = this.el.shift({
3487                 duration: this.repairDuration || .5,
3488                 easing: 'easeOut',
3489                 xy: xy,
3490                 stopFx: true,
3491                 callback: this.afterRepair,
3492                 scope: this
3493             });
3494         }else{
3495             this.afterRepair();
3496         }
3497     },
3498
3499     // private
3500     afterRepair : function(){
3501         this.hide(true);
3502         if(typeof this.callback == "function"){
3503             this.callback.call(this.scope || this);
3504         }
3505         this.callback = null;
3506         this.scope = null;
3507     }
3508 };/*
3509  * Based on:
3510  * Ext JS Library 1.1.1
3511  * Copyright(c) 2006-2007, Ext JS, LLC.
3512  *
3513  * Originally Released Under LGPL - original licence link has changed is not relivant.
3514  *
3515  * Fork - LGPL
3516  * <script type="text/javascript">
3517  */
3518
3519 /**
3520  * @class Roo.dd.DragSource
3521  * @extends Roo.dd.DDProxy
3522  * A simple class that provides the basic implementation needed to make any element draggable.
3523  * @constructor
3524  * @param {String/HTMLElement/Element} el The container element
3525  * @param {Object} config
3526  */
3527 Roo.dd.DragSource = function(el, config){
3528     this.el = Roo.get(el);
3529     this.dragData = {};
3530     
3531     Roo.apply(this, config);
3532     
3533     if(!this.proxy){
3534         this.proxy = new Roo.dd.StatusProxy();
3535     }
3536
3537     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3538           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3539     
3540     this.dragging = false;
3541 };
3542
3543 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3544     /**
3545      * @cfg {String} dropAllowed
3546      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3547      */
3548     dropAllowed : "x-dd-drop-ok",
3549     /**
3550      * @cfg {String} dropNotAllowed
3551      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3552      */
3553     dropNotAllowed : "x-dd-drop-nodrop",
3554
3555     /**
3556      * Returns the data object associated with this drag source
3557      * @return {Object} data An object containing arbitrary data
3558      */
3559     getDragData : function(e){
3560         return this.dragData;
3561     },
3562
3563     // private
3564     onDragEnter : function(e, id){
3565         var target = Roo.dd.DragDropMgr.getDDById(id);
3566         this.cachedTarget = target;
3567         if(this.beforeDragEnter(target, e, id) !== false){
3568             if(target.isNotifyTarget){
3569                 var status = target.notifyEnter(this, e, this.dragData);
3570                 this.proxy.setStatus(status);
3571             }else{
3572                 this.proxy.setStatus(this.dropAllowed);
3573             }
3574             
3575             if(this.afterDragEnter){
3576                 /**
3577                  * An empty function by default, but provided so that you can perform a custom action
3578                  * when the dragged item enters the drop target by providing an implementation.
3579                  * @param {Roo.dd.DragDrop} target The drop target
3580                  * @param {Event} e The event object
3581                  * @param {String} id The id of the dragged element
3582                  * @method afterDragEnter
3583                  */
3584                 this.afterDragEnter(target, e, id);
3585             }
3586         }
3587     },
3588
3589     /**
3590      * An empty function by default, but provided so that you can perform a custom action
3591      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3592      * @param {Roo.dd.DragDrop} target The drop target
3593      * @param {Event} e The event object
3594      * @param {String} id The id of the dragged element
3595      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3596      */
3597     beforeDragEnter : function(target, e, id){
3598         return true;
3599     },
3600
3601     // private
3602     alignElWithMouse: function() {
3603         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3604         this.proxy.sync();
3605     },
3606
3607     // private
3608     onDragOver : function(e, id){
3609         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3610         if(this.beforeDragOver(target, e, id) !== false){
3611             if(target.isNotifyTarget){
3612                 var status = target.notifyOver(this, e, this.dragData);
3613                 this.proxy.setStatus(status);
3614             }
3615
3616             if(this.afterDragOver){
3617                 /**
3618                  * An empty function by default, but provided so that you can perform a custom action
3619                  * while the dragged item is over the drop target by providing an implementation.
3620                  * @param {Roo.dd.DragDrop} target The drop target
3621                  * @param {Event} e The event object
3622                  * @param {String} id The id of the dragged element
3623                  * @method afterDragOver
3624                  */
3625                 this.afterDragOver(target, e, id);
3626             }
3627         }
3628     },
3629
3630     /**
3631      * An empty function by default, but provided so that you can perform a custom action
3632      * while the dragged item is over the drop target and optionally cancel the onDragOver.
3633      * @param {Roo.dd.DragDrop} target The drop target
3634      * @param {Event} e The event object
3635      * @param {String} id The id of the dragged element
3636      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3637      */
3638     beforeDragOver : function(target, e, id){
3639         return true;
3640     },
3641
3642     // private
3643     onDragOut : function(e, id){
3644         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3645         if(this.beforeDragOut(target, e, id) !== false){
3646             if(target.isNotifyTarget){
3647                 target.notifyOut(this, e, this.dragData);
3648             }
3649             this.proxy.reset();
3650             if(this.afterDragOut){
3651                 /**
3652                  * An empty function by default, but provided so that you can perform a custom action
3653                  * after the dragged item is dragged out of the target without dropping.
3654                  * @param {Roo.dd.DragDrop} target The drop target
3655                  * @param {Event} e The event object
3656                  * @param {String} id The id of the dragged element
3657                  * @method afterDragOut
3658                  */
3659                 this.afterDragOut(target, e, id);
3660             }
3661         }
3662         this.cachedTarget = null;
3663     },
3664
3665     /**
3666      * An empty function by default, but provided so that you can perform a custom action before the dragged
3667      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3668      * @param {Roo.dd.DragDrop} target The drop target
3669      * @param {Event} e The event object
3670      * @param {String} id The id of the dragged element
3671      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3672      */
3673     beforeDragOut : function(target, e, id){
3674         return true;
3675     },
3676     
3677     // private
3678     onDragDrop : function(e, id){
3679         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3680         if(this.beforeDragDrop(target, e, id) !== false){
3681             if(target.isNotifyTarget){
3682                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3683                     this.onValidDrop(target, e, id);
3684                 }else{
3685                     this.onInvalidDrop(target, e, id);
3686                 }
3687             }else{
3688                 this.onValidDrop(target, e, id);
3689             }
3690             
3691             if(this.afterDragDrop){
3692                 /**
3693                  * An empty function by default, but provided so that you can perform a custom action
3694                  * after a valid drag drop has occurred by providing an implementation.
3695                  * @param {Roo.dd.DragDrop} target The drop target
3696                  * @param {Event} e The event object
3697                  * @param {String} id The id of the dropped element
3698                  * @method afterDragDrop
3699                  */
3700                 this.afterDragDrop(target, e, id);
3701             }
3702         }
3703         delete this.cachedTarget;
3704     },
3705
3706     /**
3707      * An empty function by default, but provided so that you can perform a custom action before the dragged
3708      * item is dropped onto the target and optionally cancel the onDragDrop.
3709      * @param {Roo.dd.DragDrop} target The drop target
3710      * @param {Event} e The event object
3711      * @param {String} id The id of the dragged element
3712      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3713      */
3714     beforeDragDrop : function(target, e, id){
3715         return true;
3716     },
3717
3718     // private
3719     onValidDrop : function(target, e, id){
3720         this.hideProxy();
3721         if(this.afterValidDrop){
3722             /**
3723              * An empty function by default, but provided so that you can perform a custom action
3724              * after a valid drop has occurred by providing an implementation.
3725              * @param {Object} target The target DD 
3726              * @param {Event} e The event object
3727              * @param {String} id The id of the dropped element
3728              * @method afterInvalidDrop
3729              */
3730             this.afterValidDrop(target, e, id);
3731         }
3732     },
3733
3734     // private
3735     getRepairXY : function(e, data){
3736         return this.el.getXY();  
3737     },
3738
3739     // private
3740     onInvalidDrop : function(target, e, id){
3741         this.beforeInvalidDrop(target, e, id);
3742         if(this.cachedTarget){
3743             if(this.cachedTarget.isNotifyTarget){
3744                 this.cachedTarget.notifyOut(this, e, this.dragData);
3745             }
3746             this.cacheTarget = null;
3747         }
3748         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3749
3750         if(this.afterInvalidDrop){
3751             /**
3752              * An empty function by default, but provided so that you can perform a custom action
3753              * after an invalid drop has occurred by providing an implementation.
3754              * @param {Event} e The event object
3755              * @param {String} id The id of the dropped element
3756              * @method afterInvalidDrop
3757              */
3758             this.afterInvalidDrop(e, id);
3759         }
3760     },
3761
3762     // private
3763     afterRepair : function(){
3764         if(Roo.enableFx){
3765             this.el.highlight(this.hlColor || "c3daf9");
3766         }
3767         this.dragging = false;
3768     },
3769
3770     /**
3771      * An empty function by default, but provided so that you can perform a custom action after an invalid
3772      * drop has occurred.
3773      * @param {Roo.dd.DragDrop} target The drop target
3774      * @param {Event} e The event object
3775      * @param {String} id The id of the dragged element
3776      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3777      */
3778     beforeInvalidDrop : function(target, e, id){
3779         return true;
3780     },
3781
3782     // private
3783     handleMouseDown : function(e){
3784         if(this.dragging) {
3785             return;
3786         }
3787         var data = this.getDragData(e);
3788         if(data && this.onBeforeDrag(data, e) !== false){
3789             this.dragData = data;
3790             this.proxy.stop();
3791             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3792         } 
3793     },
3794
3795     /**
3796      * An empty function by default, but provided so that you can perform a custom action before the initial
3797      * drag event begins and optionally cancel it.
3798      * @param {Object} data An object containing arbitrary data to be shared with drop targets
3799      * @param {Event} e The event object
3800      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3801      */
3802     onBeforeDrag : function(data, e){
3803         return true;
3804     },
3805
3806     /**
3807      * An empty function by default, but provided so that you can perform a custom action once the initial
3808      * drag event has begun.  The drag cannot be canceled from this function.
3809      * @param {Number} x The x position of the click on the dragged object
3810      * @param {Number} y The y position of the click on the dragged object
3811      */
3812     onStartDrag : Roo.emptyFn,
3813
3814     // private - YUI override
3815     startDrag : function(x, y){
3816         this.proxy.reset();
3817         this.dragging = true;
3818         this.proxy.update("");
3819         this.onInitDrag(x, y);
3820         this.proxy.show();
3821     },
3822
3823     // private
3824     onInitDrag : function(x, y){
3825         var clone = this.el.dom.cloneNode(true);
3826         clone.id = Roo.id(); // prevent duplicate ids
3827         this.proxy.update(clone);
3828         this.onStartDrag(x, y);
3829         return true;
3830     },
3831
3832     /**
3833      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3834      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3835      */
3836     getProxy : function(){
3837         return this.proxy;  
3838     },
3839
3840     /**
3841      * Hides the drag source's {@link Roo.dd.StatusProxy}
3842      */
3843     hideProxy : function(){
3844         this.proxy.hide();  
3845         this.proxy.reset(true);
3846         this.dragging = false;
3847     },
3848
3849     // private
3850     triggerCacheRefresh : function(){
3851         Roo.dd.DDM.refreshCache(this.groups);
3852     },
3853
3854     // private - override to prevent hiding
3855     b4EndDrag: function(e) {
3856     },
3857
3858     // private - override to prevent moving
3859     endDrag : function(e){
3860         this.onEndDrag(this.dragData, e);
3861     },
3862
3863     // private
3864     onEndDrag : function(data, e){
3865     },
3866     
3867     // private - pin to cursor
3868     autoOffset : function(x, y) {
3869         this.setDelta(-12, -20);
3870     }    
3871 });/*
3872  * Based on:
3873  * Ext JS Library 1.1.1
3874  * Copyright(c) 2006-2007, Ext JS, LLC.
3875  *
3876  * Originally Released Under LGPL - original licence link has changed is not relivant.
3877  *
3878  * Fork - LGPL
3879  * <script type="text/javascript">
3880  */
3881
3882
3883 /**
3884  * @class Roo.dd.DropTarget
3885  * @extends Roo.dd.DDTarget
3886  * A simple class that provides the basic implementation needed to make any element a drop target that can have
3887  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
3888  * @constructor
3889  * @param {String/HTMLElement/Element} el The container element
3890  * @param {Object} config
3891  */
3892 Roo.dd.DropTarget = function(el, config){
3893     this.el = Roo.get(el);
3894     
3895     var listeners = false; ;
3896     if (config && config.listeners) {
3897         listeners= config.listeners;
3898         delete config.listeners;
3899     }
3900     Roo.apply(this, config);
3901     
3902     if(this.containerScroll){
3903         Roo.dd.ScrollManager.register(this.el);
3904     }
3905     this.addEvents( {
3906          /**
3907          * @scope Roo.dd.DropTarget
3908          */
3909          
3910          /**
3911          * @event enter
3912          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
3915          * 
3916          * IMPORTANT : it should set this.overClass and this.dropAllowed
3917          * 
3918          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919          * @param {Event} e The event
3920          * @param {Object} data An object containing arbitrary data supplied by the drag source
3921          */
3922         "enter" : true,
3923         
3924          /**
3925          * @event over
3926          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927          * This method will be called on every mouse movement while the drag source is over the drop target.
3928          * This default implementation simply returns the dropAllowed config value.
3929          * 
3930          * IMPORTANT : it should set this.dropAllowed
3931          * 
3932          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933          * @param {Event} e The event
3934          * @param {Object} data An object containing arbitrary data supplied by the drag source
3935          
3936          */
3937         "over" : true,
3938         /**
3939          * @event out
3940          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
3942          * overClass (if any) from the drop element.
3943          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944          * @param {Event} e The event
3945          * @param {Object} data An object containing arbitrary data supplied by the drag source
3946          */
3947          "out" : true,
3948          
3949         /**
3950          * @event drop
3951          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
3953          * implementation that does something to process the drop event and returns true so that the drag source's
3954          * repair action does not run.
3955          * 
3956          * IMPORTANT : it should set this.success
3957          * 
3958          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959          * @param {Event} e The event
3960          * @param {Object} data An object containing arbitrary data supplied by the drag source
3961         */
3962          "drop" : true
3963     });
3964             
3965      
3966     Roo.dd.DropTarget.superclass.constructor.call(  this, 
3967         this.el.dom, 
3968         this.ddGroup || this.group,
3969         {
3970             isTarget: true,
3971             listeners : listeners || {} 
3972            
3973         
3974         }
3975     );
3976
3977 };
3978
3979 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3980     /**
3981      * @cfg {String} overClass
3982      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3983      */
3984      /**
3985      * @cfg {String} ddGroup
3986      * The drag drop group to handle drop events for
3987      */
3988      
3989     /**
3990      * @cfg {String} dropAllowed
3991      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3992      */
3993     dropAllowed : "x-dd-drop-ok",
3994     /**
3995      * @cfg {String} dropNotAllowed
3996      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3997      */
3998     dropNotAllowed : "x-dd-drop-nodrop",
3999     /**
4000      * @cfg {boolean} success
4001      * set this after drop listener.. 
4002      */
4003     success : false,
4004     /**
4005      * @cfg {boolean|String} valid true/false or string (add/sub/ok/nodrop)
4006      * if the drop point is valid for over/enter..
4007      */
4008     valid : false,
4009     // private
4010     isTarget : true,
4011
4012     // private
4013     isNotifyTarget : true,
4014     
4015     /**
4016      * @hide
4017      */
4018     notifyEnter : function(dd, e, data){
4019         this.valid = true;
4020         this.fireEvent('enter', dd, e, data);
4021         if(this.overClass){
4022             this.el.addClass(this.overClass);
4023         }
4024         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4025             this.valid ? this.dropAllowed : this.dropNotAllowed
4026         );
4027     },
4028
4029     /**
4030      * @hide
4031      */
4032     notifyOver : function(dd, e, data){
4033         this.valid = true;
4034         this.fireEvent('over', dd, e, data);
4035         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4036             this.valid ? this.dropAllowed : this.dropNotAllowed
4037         );
4038     },
4039
4040     /**
4041      * @hide
4042      */
4043     notifyOut : function(dd, e, data){
4044         this.fireEvent('out', dd, e, data);
4045         if(this.overClass){
4046             this.el.removeClass(this.overClass);
4047         }
4048     },
4049
4050     /**
4051      * @hide
4052      */
4053     notifyDrop : function(dd, e, data){
4054         this.success = false;
4055         this.fireEvent('drop', dd, e, data);
4056         return this.success;
4057     }
4058 });/*
4059  * Based on:
4060  * Ext JS Library 1.1.1
4061  * Copyright(c) 2006-2007, Ext JS, LLC.
4062  *
4063  * Originally Released Under LGPL - original licence link has changed is not relivant.
4064  *
4065  * Fork - LGPL
4066  * <script type="text/javascript">
4067  */
4068
4069
4070 /**
4071  * @class Roo.dd.DragZone
4072  * @extends Roo.dd.DragSource
4073  * This class provides a container DD instance that proxies for multiple child node sources.<br />
4074  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4075  * @constructor
4076  * @param {String/HTMLElement/Element} el The container element
4077  * @param {Object} config
4078  */
4079 Roo.dd.DragZone = function(el, config){
4080     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4081     if(this.containerScroll){
4082         Roo.dd.ScrollManager.register(this.el);
4083     }
4084 };
4085
4086 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4087     /**
4088      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4089      * for auto scrolling during drag operations.
4090      */
4091     /**
4092      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4093      * method after a failed drop (defaults to "c3daf9" - light blue)
4094      */
4095
4096     /**
4097      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4098      * for a valid target to drag based on the mouse down. Override this method
4099      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4100      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4101      * @param {EventObject} e The mouse down event
4102      * @return {Object} The dragData
4103      */
4104     getDragData : function(e){
4105         return Roo.dd.Registry.getHandleFromEvent(e);
4106     },
4107     
4108     /**
4109      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4110      * this.dragData.ddel
4111      * @param {Number} x The x position of the click on the dragged object
4112      * @param {Number} y The y position of the click on the dragged object
4113      * @return {Boolean} true to continue the drag, false to cancel
4114      */
4115     onInitDrag : function(x, y){
4116         this.proxy.update(this.dragData.ddel.cloneNode(true));
4117         this.onStartDrag(x, y);
4118         return true;
4119     },
4120     
4121     /**
4122      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4123      */
4124     afterRepair : function(){
4125         if(Roo.enableFx){
4126             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4127         }
4128         this.dragging = false;
4129     },
4130
4131     /**
4132      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4133      * the XY of this.dragData.ddel
4134      * @param {EventObject} e The mouse up event
4135      * @return {Array} The xy location (e.g. [100, 200])
4136      */
4137     getRepairXY : function(e){
4138         return Roo.Element.fly(this.dragData.ddel).getXY();  
4139     }
4140 });/*
4141  * Based on:
4142  * Ext JS Library 1.1.1
4143  * Copyright(c) 2006-2007, Ext JS, LLC.
4144  *
4145  * Originally Released Under LGPL - original licence link has changed is not relivant.
4146  *
4147  * Fork - LGPL
4148  * <script type="text/javascript">
4149  */
4150 /**
4151  * @class Roo.dd.DropZone
4152  * @extends Roo.dd.DropTarget
4153  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4154  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4155  * @constructor
4156  * @param {String/HTMLElement/Element} el The container element
4157  * @param {Object} config
4158  */
4159 Roo.dd.DropZone = function(el, config){
4160     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4161 };
4162
4163 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4164     /**
4165      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4166      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4167      * provide your own custom lookup.
4168      * @param {Event} e The event
4169      * @return {Object} data The custom data
4170      */
4171     getTargetFromEvent : function(e){
4172         return Roo.dd.Registry.getTargetFromEvent(e);
4173     },
4174
4175     /**
4176      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4177      * that it has registered.  This method has no default implementation and should be overridden to provide
4178      * node-specific processing if necessary.
4179      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4180      * {@link #getTargetFromEvent} for this node)
4181      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4182      * @param {Event} e The event
4183      * @param {Object} data An object containing arbitrary data supplied by the drag source
4184      */
4185     onNodeEnter : function(n, dd, e, data){
4186         
4187     },
4188
4189     /**
4190      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4191      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4192      * overridden to provide the proper feedback.
4193      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4194      * {@link #getTargetFromEvent} for this node)
4195      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4196      * @param {Event} e The event
4197      * @param {Object} data An object containing arbitrary data supplied by the drag source
4198      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4199      * underlying {@link Roo.dd.StatusProxy} can be updated
4200      */
4201     onNodeOver : function(n, dd, e, data){
4202         return this.dropAllowed;
4203     },
4204
4205     /**
4206      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4207      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4208      * node-specific processing if necessary.
4209      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4210      * {@link #getTargetFromEvent} for this node)
4211      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4212      * @param {Event} e The event
4213      * @param {Object} data An object containing arbitrary data supplied by the drag source
4214      */
4215     onNodeOut : function(n, dd, e, data){
4216         
4217     },
4218
4219     /**
4220      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4221      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4222      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4223      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4224      * {@link #getTargetFromEvent} for this node)
4225      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4226      * @param {Event} e The event
4227      * @param {Object} data An object containing arbitrary data supplied by the drag source
4228      * @return {Boolean} True if the drop was valid, else false
4229      */
4230     onNodeDrop : function(n, dd, e, data){
4231         return false;
4232     },
4233
4234     /**
4235      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4236      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4237      * it should be overridden to provide the proper feedback if necessary.
4238      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4239      * @param {Event} e The event
4240      * @param {Object} data An object containing arbitrary data supplied by the drag source
4241      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4242      * underlying {@link Roo.dd.StatusProxy} can be updated
4243      */
4244     onContainerOver : function(dd, e, data){
4245         return this.dropNotAllowed;
4246     },
4247
4248     /**
4249      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4250      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4251      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4252      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4253      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4254      * @param {Event} e The event
4255      * @param {Object} data An object containing arbitrary data supplied by the drag source
4256      * @return {Boolean} True if the drop was valid, else false
4257      */
4258     onContainerDrop : function(dd, e, data){
4259         return false;
4260     },
4261
4262     /**
4263      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4264      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4265      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4266      * you should override this method and provide a custom implementation.
4267      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4268      * @param {Event} e The event
4269      * @param {Object} data An object containing arbitrary data supplied by the drag source
4270      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4271      * underlying {@link Roo.dd.StatusProxy} can be updated
4272      */
4273     notifyEnter : function(dd, e, data){
4274         return this.dropNotAllowed;
4275     },
4276
4277     /**
4278      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4279      * This method will be called on every mouse movement while the drag source is over the drop zone.
4280      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4281      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4282      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4283      * registered node, it will call {@link #onContainerOver}.
4284      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4285      * @param {Event} e The event
4286      * @param {Object} data An object containing arbitrary data supplied by the drag source
4287      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4288      * underlying {@link Roo.dd.StatusProxy} can be updated
4289      */
4290     notifyOver : function(dd, e, data){
4291         var n = this.getTargetFromEvent(e);
4292         if(!n){ // not over valid drop target
4293             if(this.lastOverNode){
4294                 this.onNodeOut(this.lastOverNode, dd, e, data);
4295                 this.lastOverNode = null;
4296             }
4297             return this.onContainerOver(dd, e, data);
4298         }
4299         if(this.lastOverNode != n){
4300             if(this.lastOverNode){
4301                 this.onNodeOut(this.lastOverNode, dd, e, data);
4302             }
4303             this.onNodeEnter(n, dd, e, data);
4304             this.lastOverNode = n;
4305         }
4306         return this.onNodeOver(n, dd, e, data);
4307     },
4308
4309     /**
4310      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4311      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4312      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4313      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4314      * @param {Event} e The event
4315      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4316      */
4317     notifyOut : function(dd, e, data){
4318         if(this.lastOverNode){
4319             this.onNodeOut(this.lastOverNode, dd, e, data);
4320             this.lastOverNode = null;
4321         }
4322     },
4323
4324     /**
4325      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4326      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4327      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4328      * otherwise it will call {@link #onContainerDrop}.
4329      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4330      * @param {Event} e The event
4331      * @param {Object} data An object containing arbitrary data supplied by the drag source
4332      * @return {Boolean} True if the drop was valid, else false
4333      */
4334     notifyDrop : function(dd, e, data){
4335         if(this.lastOverNode){
4336             this.onNodeOut(this.lastOverNode, dd, e, data);
4337             this.lastOverNode = null;
4338         }
4339         var n = this.getTargetFromEvent(e);
4340         return n ?
4341             this.onNodeDrop(n, dd, e, data) :
4342             this.onContainerDrop(dd, e, data);
4343     },
4344
4345     // private
4346     triggerCacheRefresh : function(){
4347         Roo.dd.DDM.refreshCache(this.groups);
4348     }  
4349 });/*
4350  * Based on:
4351  * Ext JS Library 1.1.1
4352  * Copyright(c) 2006-2007, Ext JS, LLC.
4353  *
4354  * Originally Released Under LGPL - original licence link has changed is not relivant.
4355  *
4356  * Fork - LGPL
4357  * <script type="text/javascript">
4358  */
4359
4360
4361 /**
4362  * @class Roo.data.SortTypes
4363  * @singleton
4364  * Defines the default sorting (casting?) comparison functions used when sorting data.
4365  */
4366 Roo.data.SortTypes = {
4367     /**
4368      * Default sort that does nothing
4369      * @param {Mixed} s The value being converted
4370      * @return {Mixed} The comparison value
4371      */
4372     none : function(s){
4373         return s;
4374     },
4375     
4376     /**
4377      * The regular expression used to strip tags
4378      * @type {RegExp}
4379      * @property
4380      */
4381     stripTagsRE : /<\/?[^>]+>/gi,
4382     
4383     /**
4384      * Strips all HTML tags to sort on text only
4385      * @param {Mixed} s The value being converted
4386      * @return {String} The comparison value
4387      */
4388     asText : function(s){
4389         return String(s).replace(this.stripTagsRE, "");
4390     },
4391     
4392     /**
4393      * Strips all HTML tags to sort on text only - Case insensitive
4394      * @param {Mixed} s The value being converted
4395      * @return {String} The comparison value
4396      */
4397     asUCText : function(s){
4398         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4399     },
4400     
4401     /**
4402      * Case insensitive string
4403      * @param {Mixed} s The value being converted
4404      * @return {String} The comparison value
4405      */
4406     asUCString : function(s) {
4407         return String(s).toUpperCase();
4408     },
4409     
4410     /**
4411      * Date sorting
4412      * @param {Mixed} s The value being converted
4413      * @return {Number} The comparison value
4414      */
4415     asDate : function(s) {
4416         if(!s){
4417             return 0;
4418         }
4419         if(s instanceof Date){
4420             return s.getTime();
4421         }
4422         return Date.parse(String(s));
4423     },
4424     
4425     /**
4426      * Float sorting
4427      * @param {Mixed} s The value being converted
4428      * @return {Float} The comparison value
4429      */
4430     asFloat : function(s) {
4431         var val = parseFloat(String(s).replace(/,/g, ""));
4432         if(isNaN(val)) val = 0;
4433         return val;
4434     },
4435     
4436     /**
4437      * Integer sorting
4438      * @param {Mixed} s The value being converted
4439      * @return {Number} The comparison value
4440      */
4441     asInt : function(s) {
4442         var val = parseInt(String(s).replace(/,/g, ""));
4443         if(isNaN(val)) val = 0;
4444         return val;
4445     }
4446 };/*
4447  * Based on:
4448  * Ext JS Library 1.1.1
4449  * Copyright(c) 2006-2007, Ext JS, LLC.
4450  *
4451  * Originally Released Under LGPL - original licence link has changed is not relivant.
4452  *
4453  * Fork - LGPL
4454  * <script type="text/javascript">
4455  */
4456
4457 /**
4458 * @class Roo.data.Record
4459  * Instances of this class encapsulate both record <em>definition</em> information, and record
4460  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4461  * to access Records cached in an {@link Roo.data.Store} object.<br>
4462  * <p>
4463  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4464  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4465  * objects.<br>
4466  * <p>
4467  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4468  * @constructor
4469  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4470  * {@link #create}. The parameters are the same.
4471  * @param {Array} data An associative Array of data values keyed by the field name.
4472  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4473  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4474  * not specified an integer id is generated.
4475  */
4476 Roo.data.Record = function(data, id){
4477     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4478     this.data = data;
4479 };
4480
4481 /**
4482  * Generate a constructor for a specific record layout.
4483  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4484  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4485  * Each field definition object may contain the following properties: <ul>
4486  * <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,
4487  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4488  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4489  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4490  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4491  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4492  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4493  * this may be omitted.</p></li>
4494  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4495  * <ul><li>auto (Default, implies no conversion)</li>
4496  * <li>string</li>
4497  * <li>int</li>
4498  * <li>float</li>
4499  * <li>boolean</li>
4500  * <li>date</li></ul></p></li>
4501  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4502  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4503  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4504  * by the Reader into an object that will be stored in the Record. It is passed the
4505  * following parameters:<ul>
4506  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4507  * </ul></p></li>
4508  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4509  * </ul>
4510  * <br>usage:<br><pre><code>
4511 var TopicRecord = Roo.data.Record.create(
4512     {name: 'title', mapping: 'topic_title'},
4513     {name: 'author', mapping: 'username'},
4514     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4515     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4516     {name: 'lastPoster', mapping: 'user2'},
4517     {name: 'excerpt', mapping: 'post_text'}
4518 );
4519
4520 var myNewRecord = new TopicRecord({
4521     title: 'Do my job please',
4522     author: 'noobie',
4523     totalPosts: 1,
4524     lastPost: new Date(),
4525     lastPoster: 'Animal',
4526     excerpt: 'No way dude!'
4527 });
4528 myStore.add(myNewRecord);
4529 </code></pre>
4530  * @method create
4531  * @static
4532  */
4533 Roo.data.Record.create = function(o){
4534     var f = function(){
4535         f.superclass.constructor.apply(this, arguments);
4536     };
4537     Roo.extend(f, Roo.data.Record);
4538     var p = f.prototype;
4539     p.fields = new Roo.util.MixedCollection(false, function(field){
4540         return field.name;
4541     });
4542     for(var i = 0, len = o.length; i < len; i++){
4543         p.fields.add(new Roo.data.Field(o[i]));
4544     }
4545     f.getField = function(name){
4546         return p.fields.get(name);  
4547     };
4548     return f;
4549 };
4550
4551 Roo.data.Record.AUTO_ID = 1000;
4552 Roo.data.Record.EDIT = 'edit';
4553 Roo.data.Record.REJECT = 'reject';
4554 Roo.data.Record.COMMIT = 'commit';
4555
4556 Roo.data.Record.prototype = {
4557     /**
4558      * Readonly flag - true if this record has been modified.
4559      * @type Boolean
4560      */
4561     dirty : false,
4562     editing : false,
4563     error: null,
4564     modified: null,
4565
4566     // private
4567     join : function(store){
4568         this.store = store;
4569     },
4570
4571     /**
4572      * Set the named field to the specified value.
4573      * @param {String} name The name of the field to set.
4574      * @param {Object} value The value to set the field to.
4575      */
4576     set : function(name, value){
4577         if(this.data[name] == value){
4578             return;
4579         }
4580         this.dirty = true;
4581         if(!this.modified){
4582             this.modified = {};
4583         }
4584         if(typeof this.modified[name] == 'undefined'){
4585             this.modified[name] = this.data[name];
4586         }
4587         this.data[name] = value;
4588         if(!this.editing){
4589             this.store.afterEdit(this);
4590         }       
4591     },
4592
4593     /**
4594      * Get the value of the named field.
4595      * @param {String} name The name of the field to get the value of.
4596      * @return {Object} The value of the field.
4597      */
4598     get : function(name){
4599         return this.data[name]; 
4600     },
4601
4602     // private
4603     beginEdit : function(){
4604         this.editing = true;
4605         this.modified = {}; 
4606     },
4607
4608     // private
4609     cancelEdit : function(){
4610         this.editing = false;
4611         delete this.modified;
4612     },
4613
4614     // private
4615     endEdit : function(){
4616         this.editing = false;
4617         if(this.dirty && this.store){
4618             this.store.afterEdit(this);
4619         }
4620     },
4621
4622     /**
4623      * Usually called by the {@link Roo.data.Store} which owns the Record.
4624      * Rejects all changes made to the Record since either creation, or the last commit operation.
4625      * Modified fields are reverted to their original values.
4626      * <p>
4627      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4628      * of reject operations.
4629      */
4630     reject : function(){
4631         var m = this.modified;
4632         for(var n in m){
4633             if(typeof m[n] != "function"){
4634                 this.data[n] = m[n];
4635             }
4636         }
4637         this.dirty = false;
4638         delete this.modified;
4639         this.editing = false;
4640         if(this.store){
4641             this.store.afterReject(this);
4642         }
4643     },
4644
4645     /**
4646      * Usually called by the {@link Roo.data.Store} which owns the Record.
4647      * Commits all changes made to the Record since either creation, or the last commit operation.
4648      * <p>
4649      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4650      * of commit operations.
4651      */
4652     commit : function(){
4653         this.dirty = false;
4654         delete this.modified;
4655         this.editing = false;
4656         if(this.store){
4657             this.store.afterCommit(this);
4658         }
4659     },
4660
4661     // private
4662     hasError : function(){
4663         return this.error != null;
4664     },
4665
4666     // private
4667     clearError : function(){
4668         this.error = null;
4669     },
4670
4671     /**
4672      * Creates a copy of this record.
4673      * @param {String} id (optional) A new record id if you don't want to use this record's id
4674      * @return {Record}
4675      */
4676     copy : function(newId) {
4677         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4678     }
4679 };/*
4680  * Based on:
4681  * Ext JS Library 1.1.1
4682  * Copyright(c) 2006-2007, Ext JS, LLC.
4683  *
4684  * Originally Released Under LGPL - original licence link has changed is not relivant.
4685  *
4686  * Fork - LGPL
4687  * <script type="text/javascript">
4688  */
4689
4690
4691
4692 /**
4693  * @class Roo.data.Store
4694  * @extends Roo.util.Observable
4695  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4696  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4697  * <p>
4698  * 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
4699  * has no knowledge of the format of the data returned by the Proxy.<br>
4700  * <p>
4701  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4702  * instances from the data object. These records are cached and made available through accessor functions.
4703  * @constructor
4704  * Creates a new Store.
4705  * @param {Object} config A config object containing the objects needed for the Store to access data,
4706  * and read the data into Records.
4707  */
4708 Roo.data.Store = function(config){
4709     this.data = new Roo.util.MixedCollection(false);
4710     this.data.getKey = function(o){
4711         return o.id;
4712     };
4713     this.baseParams = {};
4714     // private
4715     this.paramNames = {
4716         "start" : "start",
4717         "limit" : "limit",
4718         "sort" : "sort",
4719         "dir" : "dir"
4720     };
4721
4722     if(config && config.data){
4723         this.inlineData = config.data;
4724         delete config.data;
4725     }
4726
4727     Roo.apply(this, config);
4728     
4729     if(this.reader){ // reader passed
4730         this.reader = Roo.factory(this.reader, Roo.data);
4731         this.reader.xmodule = this.xmodule || false;
4732         if(!this.recordType){
4733             this.recordType = this.reader.recordType;
4734         }
4735         if(this.reader.onMetaChange){
4736             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4737         }
4738     }
4739
4740     if(this.recordType){
4741         this.fields = this.recordType.prototype.fields;
4742     }
4743     this.modified = [];
4744
4745     this.addEvents({
4746         /**
4747          * @event datachanged
4748          * Fires when the data cache has changed, and a widget which is using this Store
4749          * as a Record cache should refresh its view.
4750          * @param {Store} this
4751          */
4752         datachanged : true,
4753         /**
4754          * @event metachange
4755          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4756          * @param {Store} this
4757          * @param {Object} meta The JSON metadata
4758          */
4759         metachange : true,
4760         /**
4761          * @event add
4762          * Fires when Records have been added to the Store
4763          * @param {Store} this
4764          * @param {Roo.data.Record[]} records The array of Records added
4765          * @param {Number} index The index at which the record(s) were added
4766          */
4767         add : true,
4768         /**
4769          * @event remove
4770          * Fires when a Record has been removed from the Store
4771          * @param {Store} this
4772          * @param {Roo.data.Record} record The Record that was removed
4773          * @param {Number} index The index at which the record was removed
4774          */
4775         remove : true,
4776         /**
4777          * @event update
4778          * Fires when a Record has been updated
4779          * @param {Store} this
4780          * @param {Roo.data.Record} record The Record that was updated
4781          * @param {String} operation The update operation being performed.  Value may be one of:
4782          * <pre><code>
4783  Roo.data.Record.EDIT
4784  Roo.data.Record.REJECT
4785  Roo.data.Record.COMMIT
4786          * </code></pre>
4787          */
4788         update : true,
4789         /**
4790          * @event clear
4791          * Fires when the data cache has been cleared.
4792          * @param {Store} this
4793          */
4794         clear : true,
4795         /**
4796          * @event beforeload
4797          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4798          * the load action will be canceled.
4799          * @param {Store} this
4800          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4801          */
4802         beforeload : true,
4803         /**
4804          * @event load
4805          * Fires after a new set of Records has been loaded.
4806          * @param {Store} this
4807          * @param {Roo.data.Record[]} records The Records that were loaded
4808          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4809          */
4810         load : true,
4811         /**
4812          * @event loadexception
4813          * Fires if an exception occurs in the Proxy during loading.
4814          * Called with the signature of the Proxy's "loadexception" event.
4815          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4816          * 
4817          * @param {Proxy} 
4818          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4819          * @param {Object} load options 
4820          * @param {Object} jsonData from your request (normally this contains the Exception)
4821          */
4822         loadexception : true
4823     });
4824     
4825     if(this.proxy){
4826         this.proxy = Roo.factory(this.proxy, Roo.data);
4827         this.proxy.xmodule = this.xmodule || false;
4828         this.relayEvents(this.proxy,  ["loadexception"]);
4829     }
4830     this.sortToggle = {};
4831
4832     Roo.data.Store.superclass.constructor.call(this);
4833
4834     if(this.inlineData){
4835         this.loadData(this.inlineData);
4836         delete this.inlineData;
4837     }
4838 };
4839 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4840      /**
4841     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4842     * without a remote query - used by combo/forms at present.
4843     */
4844     
4845     /**
4846     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4847     */
4848     /**
4849     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4850     */
4851     /**
4852     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4853     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4854     */
4855     /**
4856     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4857     * on any HTTP request
4858     */
4859     /**
4860     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4861     */
4862     /**
4863     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4864     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4865     */
4866     remoteSort : false,
4867
4868     /**
4869     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4870      * loaded or when a record is removed. (defaults to false).
4871     */
4872     pruneModifiedRecords : false,
4873
4874     // private
4875     lastOptions : null,
4876
4877     /**
4878      * Add Records to the Store and fires the add event.
4879      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4880      */
4881     add : function(records){
4882         records = [].concat(records);
4883         for(var i = 0, len = records.length; i < len; i++){
4884             records[i].join(this);
4885         }
4886         var index = this.data.length;
4887         this.data.addAll(records);
4888         this.fireEvent("add", this, records, index);
4889     },
4890
4891     /**
4892      * Remove a Record from the Store and fires the remove event.
4893      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4894      */
4895     remove : function(record){
4896         var index = this.data.indexOf(record);
4897         this.data.removeAt(index);
4898         if(this.pruneModifiedRecords){
4899             this.modified.remove(record);
4900         }
4901         this.fireEvent("remove", this, record, index);
4902     },
4903
4904     /**
4905      * Remove all Records from the Store and fires the clear event.
4906      */
4907     removeAll : function(){
4908         this.data.clear();
4909         if(this.pruneModifiedRecords){
4910             this.modified = [];
4911         }
4912         this.fireEvent("clear", this);
4913     },
4914
4915     /**
4916      * Inserts Records to the Store at the given index and fires the add event.
4917      * @param {Number} index The start index at which to insert the passed Records.
4918      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4919      */
4920     insert : function(index, records){
4921         records = [].concat(records);
4922         for(var i = 0, len = records.length; i < len; i++){
4923             this.data.insert(index, records[i]);
4924             records[i].join(this);
4925         }
4926         this.fireEvent("add", this, records, index);
4927     },
4928
4929     /**
4930      * Get the index within the cache of the passed Record.
4931      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4932      * @return {Number} The index of the passed Record. Returns -1 if not found.
4933      */
4934     indexOf : function(record){
4935         return this.data.indexOf(record);
4936     },
4937
4938     /**
4939      * Get the index within the cache of the Record with the passed id.
4940      * @param {String} id The id of the Record to find.
4941      * @return {Number} The index of the Record. Returns -1 if not found.
4942      */
4943     indexOfId : function(id){
4944         return this.data.indexOfKey(id);
4945     },
4946
4947     /**
4948      * Get the Record with the specified id.
4949      * @param {String} id The id of the Record to find.
4950      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4951      */
4952     getById : function(id){
4953         return this.data.key(id);
4954     },
4955
4956     /**
4957      * Get the Record at the specified index.
4958      * @param {Number} index The index of the Record to find.
4959      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4960      */
4961     getAt : function(index){
4962         return this.data.itemAt(index);
4963     },
4964
4965     /**
4966      * Returns a range of Records between specified indices.
4967      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4968      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4969      * @return {Roo.data.Record[]} An array of Records
4970      */
4971     getRange : function(start, end){
4972         return this.data.getRange(start, end);
4973     },
4974
4975     // private
4976     storeOptions : function(o){
4977         o = Roo.apply({}, o);
4978         delete o.callback;
4979         delete o.scope;
4980         this.lastOptions = o;
4981     },
4982
4983     /**
4984      * Loads the Record cache from the configured Proxy using the configured Reader.
4985      * <p>
4986      * If using remote paging, then the first load call must specify the <em>start</em>
4987      * and <em>limit</em> properties in the options.params property to establish the initial
4988      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4989      * <p>
4990      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4991      * and this call will return before the new data has been loaded. Perform any post-processing
4992      * in a callback function, or in a "load" event handler.</strong>
4993      * <p>
4994      * @param {Object} options An object containing properties which control loading options:<ul>
4995      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4996      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4997      * passed the following arguments:<ul>
4998      * <li>r : Roo.data.Record[]</li>
4999      * <li>options: Options object from the load call</li>
5000      * <li>success: Boolean success indicator</li></ul></li>
5001      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5002      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5003      * </ul>
5004      */
5005     load : function(options){
5006         options = options || {};
5007         if(this.fireEvent("beforeload", this, options) !== false){
5008             this.storeOptions(options);
5009             var p = Roo.apply(options.params || {}, this.baseParams);
5010             // if meta was not loaded from remote source.. try requesting it.
5011             if (!this.reader.metaFromRemote) {
5012                 p._requestMeta = 1;
5013             }
5014             if(this.sortInfo && this.remoteSort){
5015                 var pn = this.paramNames;
5016                 p[pn["sort"]] = this.sortInfo.field;
5017                 p[pn["dir"]] = this.sortInfo.direction;
5018             }
5019             this.proxy.load(p, this.reader, this.loadRecords, this, options);
5020         }
5021     },
5022
5023     /**
5024      * Reloads the Record cache from the configured Proxy using the configured Reader and
5025      * the options from the last load operation performed.
5026      * @param {Object} options (optional) An object containing properties which may override the options
5027      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5028      * the most recently used options are reused).
5029      */
5030     reload : function(options){
5031         this.load(Roo.applyIf(options||{}, this.lastOptions));
5032     },
5033
5034     // private
5035     // Called as a callback by the Reader during a load operation.
5036     loadRecords : function(o, options, success){
5037         if(!o || success === false){
5038             if(success !== false){
5039                 this.fireEvent("load", this, [], options);
5040             }
5041             if(options.callback){
5042                 options.callback.call(options.scope || this, [], options, false);
5043             }
5044             return;
5045         }
5046         // if data returned failure - throw an exception.
5047         if (o.success === false) {
5048             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5049             return;
5050         }
5051         var r = o.records, t = o.totalRecords || r.length;
5052         if(!options || options.add !== true){
5053             if(this.pruneModifiedRecords){
5054                 this.modified = [];
5055             }
5056             for(var i = 0, len = r.length; i < len; i++){
5057                 r[i].join(this);
5058             }
5059             if(this.snapshot){
5060                 this.data = this.snapshot;
5061                 delete this.snapshot;
5062             }
5063             this.data.clear();
5064             this.data.addAll(r);
5065             this.totalLength = t;
5066             this.applySort();
5067             this.fireEvent("datachanged", this);
5068         }else{
5069             this.totalLength = Math.max(t, this.data.length+r.length);
5070             this.add(r);
5071         }
5072         this.fireEvent("load", this, r, options);
5073         if(options.callback){
5074             options.callback.call(options.scope || this, r, options, true);
5075         }
5076     },
5077
5078     /**
5079      * Loads data from a passed data block. A Reader which understands the format of the data
5080      * must have been configured in the constructor.
5081      * @param {Object} data The data block from which to read the Records.  The format of the data expected
5082      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5083      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5084      */
5085     loadData : function(o, append){
5086         var r = this.reader.readRecords(o);
5087         this.loadRecords(r, {add: append}, true);
5088     },
5089
5090     /**
5091      * Gets the number of cached records.
5092      * <p>
5093      * <em>If using paging, this may not be the total size of the dataset. If the data object
5094      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5095      * the data set size</em>
5096      */
5097     getCount : function(){
5098         return this.data.length || 0;
5099     },
5100
5101     /**
5102      * Gets the total number of records in the dataset as returned by the server.
5103      * <p>
5104      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5105      * the dataset size</em>
5106      */
5107     getTotalCount : function(){
5108         return this.totalLength || 0;
5109     },
5110
5111     /**
5112      * Returns the sort state of the Store as an object with two properties:
5113      * <pre><code>
5114  field {String} The name of the field by which the Records are sorted
5115  direction {String} The sort order, "ASC" or "DESC"
5116      * </code></pre>
5117      */
5118     getSortState : function(){
5119         return this.sortInfo;
5120     },
5121
5122     // private
5123     applySort : function(){
5124         if(this.sortInfo && !this.remoteSort){
5125             var s = this.sortInfo, f = s.field;
5126             var st = this.fields.get(f).sortType;
5127             var fn = function(r1, r2){
5128                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5129                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5130             };
5131             this.data.sort(s.direction, fn);
5132             if(this.snapshot && this.snapshot != this.data){
5133                 this.snapshot.sort(s.direction, fn);
5134             }
5135         }
5136     },
5137
5138     /**
5139      * Sets the default sort column and order to be used by the next load operation.
5140      * @param {String} fieldName The name of the field to sort by.
5141      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5142      */
5143     setDefaultSort : function(field, dir){
5144         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5145     },
5146
5147     /**
5148      * Sort the Records.
5149      * If remote sorting is used, the sort is performed on the server, and the cache is
5150      * reloaded. If local sorting is used, the cache is sorted internally.
5151      * @param {String} fieldName The name of the field to sort by.
5152      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5153      */
5154     sort : function(fieldName, dir){
5155         var f = this.fields.get(fieldName);
5156         if(!dir){
5157             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5158                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5159             }else{
5160                 dir = f.sortDir;
5161             }
5162         }
5163         this.sortToggle[f.name] = dir;
5164         this.sortInfo = {field: f.name, direction: dir};
5165         if(!this.remoteSort){
5166             this.applySort();
5167             this.fireEvent("datachanged", this);
5168         }else{
5169             this.load(this.lastOptions);
5170         }
5171     },
5172
5173     /**
5174      * Calls the specified function for each of the Records in the cache.
5175      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5176      * Returning <em>false</em> aborts and exits the iteration.
5177      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5178      */
5179     each : function(fn, scope){
5180         this.data.each(fn, scope);
5181     },
5182
5183     /**
5184      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5185      * (e.g., during paging).
5186      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5187      */
5188     getModifiedRecords : function(){
5189         return this.modified;
5190     },
5191
5192     // private
5193     createFilterFn : function(property, value, anyMatch){
5194         if(!value.exec){ // not a regex
5195             value = String(value);
5196             if(value.length == 0){
5197                 return false;
5198             }
5199             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5200         }
5201         return function(r){
5202             return value.test(r.data[property]);
5203         };
5204     },
5205
5206     /**
5207      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5208      * @param {String} property A field on your records
5209      * @param {Number} start The record index to start at (defaults to 0)
5210      * @param {Number} end The last record index to include (defaults to length - 1)
5211      * @return {Number} The sum
5212      */
5213     sum : function(property, start, end){
5214         var rs = this.data.items, v = 0;
5215         start = start || 0;
5216         end = (end || end === 0) ? end : rs.length-1;
5217
5218         for(var i = start; i <= end; i++){
5219             v += (rs[i].data[property] || 0);
5220         }
5221         return v;
5222     },
5223
5224     /**
5225      * Filter the records by a specified property.
5226      * @param {String} field A field on your records
5227      * @param {String/RegExp} value Either a string that the field
5228      * should start with or a RegExp to test against the field
5229      * @param {Boolean} anyMatch True to match any part not just the beginning
5230      */
5231     filter : function(property, value, anyMatch){
5232         var fn = this.createFilterFn(property, value, anyMatch);
5233         return fn ? this.filterBy(fn) : this.clearFilter();
5234     },
5235
5236     /**
5237      * Filter by a function. The specified function will be called with each
5238      * record in this data source. If the function returns true the record is included,
5239      * otherwise it is filtered.
5240      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5241      * @param {Object} scope (optional) The scope of the function (defaults to this)
5242      */
5243     filterBy : function(fn, scope){
5244         this.snapshot = this.snapshot || this.data;
5245         this.data = this.queryBy(fn, scope||this);
5246         this.fireEvent("datachanged", this);
5247     },
5248
5249     /**
5250      * Query the records by a specified property.
5251      * @param {String} field A field on your records
5252      * @param {String/RegExp} value Either a string that the field
5253      * should start with or a RegExp to test against the field
5254      * @param {Boolean} anyMatch True to match any part not just the beginning
5255      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5256      */
5257     query : function(property, value, anyMatch){
5258         var fn = this.createFilterFn(property, value, anyMatch);
5259         return fn ? this.queryBy(fn) : this.data.clone();
5260     },
5261
5262     /**
5263      * Query by a function. The specified function will be called with each
5264      * record in this data source. If the function returns true the record is included
5265      * in the results.
5266      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5267      * @param {Object} scope (optional) The scope of the function (defaults to this)
5268       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5269      **/
5270     queryBy : function(fn, scope){
5271         var data = this.snapshot || this.data;
5272         return data.filterBy(fn, scope||this);
5273     },
5274
5275     /**
5276      * Collects unique values for a particular dataIndex from this store.
5277      * @param {String} dataIndex The property to collect
5278      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5279      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5280      * @return {Array} An array of the unique values
5281      **/
5282     collect : function(dataIndex, allowNull, bypassFilter){
5283         var d = (bypassFilter === true && this.snapshot) ?
5284                 this.snapshot.items : this.data.items;
5285         var v, sv, r = [], l = {};
5286         for(var i = 0, len = d.length; i < len; i++){
5287             v = d[i].data[dataIndex];
5288             sv = String(v);
5289             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5290                 l[sv] = true;
5291                 r[r.length] = v;
5292             }
5293         }
5294         return r;
5295     },
5296
5297     /**
5298      * Revert to a view of the Record cache with no filtering applied.
5299      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5300      */
5301     clearFilter : function(suppressEvent){
5302         if(this.snapshot && this.snapshot != this.data){
5303             this.data = this.snapshot;
5304             delete this.snapshot;
5305             if(suppressEvent !== true){
5306                 this.fireEvent("datachanged", this);
5307             }
5308         }
5309     },
5310
5311     // private
5312     afterEdit : function(record){
5313         if(this.modified.indexOf(record) == -1){
5314             this.modified.push(record);
5315         }
5316         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5317     },
5318
5319     // private
5320     afterReject : function(record){
5321         this.modified.remove(record);
5322         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5323     },
5324
5325     // private
5326     afterCommit : function(record){
5327         this.modified.remove(record);
5328         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5329     },
5330
5331     /**
5332      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5333      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5334      */
5335     commitChanges : function(){
5336         var m = this.modified.slice(0);
5337         this.modified = [];
5338         for(var i = 0, len = m.length; i < len; i++){
5339             m[i].commit();
5340         }
5341     },
5342
5343     /**
5344      * Cancel outstanding changes on all changed records.
5345      */
5346     rejectChanges : function(){
5347         var m = this.modified.slice(0);
5348         this.modified = [];
5349         for(var i = 0, len = m.length; i < len; i++){
5350             m[i].reject();
5351         }
5352     },
5353
5354     onMetaChange : function(meta, rtype, o){
5355         this.recordType = rtype;
5356         this.fields = rtype.prototype.fields;
5357         delete this.snapshot;
5358         this.sortInfo = meta.sortInfo || this.sortInfo;
5359         this.modified = [];
5360         this.fireEvent('metachange', this, this.reader.meta);
5361     }
5362 });/*
5363  * Based on:
5364  * Ext JS Library 1.1.1
5365  * Copyright(c) 2006-2007, Ext JS, LLC.
5366  *
5367  * Originally Released Under LGPL - original licence link has changed is not relivant.
5368  *
5369  * Fork - LGPL
5370  * <script type="text/javascript">
5371  */
5372
5373 /**
5374  * @class Roo.data.SimpleStore
5375  * @extends Roo.data.Store
5376  * Small helper class to make creating Stores from Array data easier.
5377  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5378  * @cfg {Array} fields An array of field definition objects, or field name strings.
5379  * @cfg {Array} data The multi-dimensional array of data
5380  * @constructor
5381  * @param {Object} config
5382  */
5383 Roo.data.SimpleStore = function(config){
5384     Roo.data.SimpleStore.superclass.constructor.call(this, {
5385         isLocal : true,
5386         reader: new Roo.data.ArrayReader({
5387                 id: config.id
5388             },
5389             Roo.data.Record.create(config.fields)
5390         ),
5391         proxy : new Roo.data.MemoryProxy(config.data)
5392     });
5393     this.load();
5394 };
5395 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5396  * Based on:
5397  * Ext JS Library 1.1.1
5398  * Copyright(c) 2006-2007, Ext JS, LLC.
5399  *
5400  * Originally Released Under LGPL - original licence link has changed is not relivant.
5401  *
5402  * Fork - LGPL
5403  * <script type="text/javascript">
5404  */
5405
5406 /**
5407 /**
5408  * @extends Roo.data.Store
5409  * @class Roo.data.JsonStore
5410  * Small helper class to make creating Stores for JSON data easier. <br/>
5411 <pre><code>
5412 var store = new Roo.data.JsonStore({
5413     url: 'get-images.php',
5414     root: 'images',
5415     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5416 });
5417 </code></pre>
5418  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5419  * JsonReader and HttpProxy (unless inline data is provided).</b>
5420  * @cfg {Array} fields An array of field definition objects, or field name strings.
5421  * @constructor
5422  * @param {Object} config
5423  */
5424 Roo.data.JsonStore = function(c){
5425     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5426         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5427         reader: new Roo.data.JsonReader(c, c.fields)
5428     }));
5429 };
5430 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5431  * Based on:
5432  * Ext JS Library 1.1.1
5433  * Copyright(c) 2006-2007, Ext JS, LLC.
5434  *
5435  * Originally Released Under LGPL - original licence link has changed is not relivant.
5436  *
5437  * Fork - LGPL
5438  * <script type="text/javascript">
5439  */
5440
5441  
5442 Roo.data.Field = function(config){
5443     if(typeof config == "string"){
5444         config = {name: config};
5445     }
5446     Roo.apply(this, config);
5447     
5448     if(!this.type){
5449         this.type = "auto";
5450     }
5451     
5452     var st = Roo.data.SortTypes;
5453     // named sortTypes are supported, here we look them up
5454     if(typeof this.sortType == "string"){
5455         this.sortType = st[this.sortType];
5456     }
5457     
5458     // set default sortType for strings and dates
5459     if(!this.sortType){
5460         switch(this.type){
5461             case "string":
5462                 this.sortType = st.asUCString;
5463                 break;
5464             case "date":
5465                 this.sortType = st.asDate;
5466                 break;
5467             default:
5468                 this.sortType = st.none;
5469         }
5470     }
5471
5472     // define once
5473     var stripRe = /[\$,%]/g;
5474
5475     // prebuilt conversion function for this field, instead of
5476     // switching every time we're reading a value
5477     if(!this.convert){
5478         var cv, dateFormat = this.dateFormat;
5479         switch(this.type){
5480             case "":
5481             case "auto":
5482             case undefined:
5483                 cv = function(v){ return v; };
5484                 break;
5485             case "string":
5486                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5487                 break;
5488             case "int":
5489                 cv = function(v){
5490                     return v !== undefined && v !== null && v !== '' ?
5491                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5492                     };
5493                 break;
5494             case "float":
5495                 cv = function(v){
5496                     return v !== undefined && v !== null && v !== '' ?
5497                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5498                     };
5499                 break;
5500             case "bool":
5501             case "boolean":
5502                 cv = function(v){ return v === true || v === "true" || v == 1; };
5503                 break;
5504             case "date":
5505                 cv = function(v){
5506                     if(!v){
5507                         return '';
5508                     }
5509                     if(v instanceof Date){
5510                         return v;
5511                     }
5512                     if(dateFormat){
5513                         if(dateFormat == "timestamp"){
5514                             return new Date(v*1000);
5515                         }
5516                         return Date.parseDate(v, dateFormat);
5517                     }
5518                     var parsed = Date.parse(v);
5519                     return parsed ? new Date(parsed) : null;
5520                 };
5521              break;
5522             
5523         }
5524         this.convert = cv;
5525     }
5526 };
5527
5528 Roo.data.Field.prototype = {
5529     dateFormat: null,
5530     defaultValue: "",
5531     mapping: null,
5532     sortType : null,
5533     sortDir : "ASC"
5534 };/*
5535  * Based on:
5536  * Ext JS Library 1.1.1
5537  * Copyright(c) 2006-2007, Ext JS, LLC.
5538  *
5539  * Originally Released Under LGPL - original licence link has changed is not relivant.
5540  *
5541  * Fork - LGPL
5542  * <script type="text/javascript">
5543  */
5544  
5545 // Base class for reading structured data from a data source.  This class is intended to be
5546 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5547
5548 /**
5549  * @class Roo.data.DataReader
5550  * Base class for reading structured data from a data source.  This class is intended to be
5551  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5552  */
5553
5554 Roo.data.DataReader = function(meta, recordType){
5555     
5556     this.meta = meta;
5557     
5558     this.recordType = recordType instanceof Array ? 
5559         Roo.data.Record.create(recordType) : recordType;
5560 };
5561
5562 Roo.data.DataReader.prototype = {
5563      /**
5564      * Create an empty record
5565      * @param {Object} data (optional) - overlay some values
5566      * @return {Roo.data.Record} record created.
5567      */
5568     newRow :  function(d) {
5569         var da =  {};
5570         this.recordType.prototype.fields.each(function(c) {
5571             switch( c.type) {
5572                 case 'int' : da[c.name] = 0; break;
5573                 case 'date' : da[c.name] = new Date(); break;
5574                 case 'float' : da[c.name] = 0.0; break;
5575                 case 'boolean' : da[c.name] = false; break;
5576                 default : da[c.name] = ""; break;
5577             }
5578             
5579         });
5580         return new this.recordType(Roo.apply(da, d));
5581     }
5582     
5583 };/*
5584  * Based on:
5585  * Ext JS Library 1.1.1
5586  * Copyright(c) 2006-2007, Ext JS, LLC.
5587  *
5588  * Originally Released Under LGPL - original licence link has changed is not relivant.
5589  *
5590  * Fork - LGPL
5591  * <script type="text/javascript">
5592  */
5593
5594 /**
5595  * @class Roo.data.DataProxy
5596  * @extends Roo.data.Observable
5597  * This class is an abstract base class for implementations which provide retrieval of
5598  * unformatted data objects.<br>
5599  * <p>
5600  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5601  * (of the appropriate type which knows how to parse the data object) to provide a block of
5602  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5603  * <p>
5604  * Custom implementations must implement the load method as described in
5605  * {@link Roo.data.HttpProxy#load}.
5606  */
5607 Roo.data.DataProxy = function(){
5608     this.addEvents({
5609         /**
5610          * @event beforeload
5611          * Fires before a network request is made to retrieve a data object.
5612          * @param {Object} This DataProxy object.
5613          * @param {Object} params The params parameter to the load function.
5614          */
5615         beforeload : true,
5616         /**
5617          * @event load
5618          * Fires before the load method's callback is called.
5619          * @param {Object} This DataProxy object.
5620          * @param {Object} o The data object.
5621          * @param {Object} arg The callback argument object passed to the load function.
5622          */
5623         load : true,
5624         /**
5625          * @event loadexception
5626          * Fires if an Exception occurs during data retrieval.
5627          * @param {Object} This DataProxy object.
5628          * @param {Object} o The data object.
5629          * @param {Object} arg The callback argument object passed to the load function.
5630          * @param {Object} e The Exception.
5631          */
5632         loadexception : true
5633     });
5634     Roo.data.DataProxy.superclass.constructor.call(this);
5635 };
5636
5637 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5638
5639     /**
5640      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5641      */
5642 /*
5643  * Based on:
5644  * Ext JS Library 1.1.1
5645  * Copyright(c) 2006-2007, Ext JS, LLC.
5646  *
5647  * Originally Released Under LGPL - original licence link has changed is not relivant.
5648  *
5649  * Fork - LGPL
5650  * <script type="text/javascript">
5651  */
5652 /**
5653  * @class Roo.data.MemoryProxy
5654  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5655  * to the Reader when its load method is called.
5656  * @constructor
5657  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5658  */
5659 Roo.data.MemoryProxy = function(data){
5660     if (data.data) {
5661         data = data.data;
5662     }
5663     Roo.data.MemoryProxy.superclass.constructor.call(this);
5664     this.data = data;
5665 };
5666
5667 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5668     /**
5669      * Load data from the requested source (in this case an in-memory
5670      * data object passed to the constructor), read the data object into
5671      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5672      * process that block using the passed callback.
5673      * @param {Object} params This parameter is not used by the MemoryProxy class.
5674      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5675      * object into a block of Roo.data.Records.
5676      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5677      * The function must be passed <ul>
5678      * <li>The Record block object</li>
5679      * <li>The "arg" argument from the load function</li>
5680      * <li>A boolean success indicator</li>
5681      * </ul>
5682      * @param {Object} scope The scope in which to call the callback
5683      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5684      */
5685     load : function(params, reader, callback, scope, arg){
5686         params = params || {};
5687         var result;
5688         try {
5689             result = reader.readRecords(this.data);
5690         }catch(e){
5691             this.fireEvent("loadexception", this, arg, null, e);
5692             callback.call(scope, null, arg, false);
5693             return;
5694         }
5695         callback.call(scope, result, arg, true);
5696     },
5697     
5698     // private
5699     update : function(params, records){
5700         
5701     }
5702 });/*
5703  * Based on:
5704  * Ext JS Library 1.1.1
5705  * Copyright(c) 2006-2007, Ext JS, LLC.
5706  *
5707  * Originally Released Under LGPL - original licence link has changed is not relivant.
5708  *
5709  * Fork - LGPL
5710  * <script type="text/javascript">
5711  */
5712 /**
5713  * @class Roo.data.HttpProxy
5714  * @extends Roo.data.DataProxy
5715  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5716  * configured to reference a certain URL.<br><br>
5717  * <p>
5718  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5719  * from which the running page was served.<br><br>
5720  * <p>
5721  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5722  * <p>
5723  * Be aware that to enable the browser to parse an XML document, the server must set
5724  * the Content-Type header in the HTTP response to "text/xml".
5725  * @constructor
5726  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5727  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5728  * will be used to make the request.
5729  */
5730 Roo.data.HttpProxy = function(conn){
5731     Roo.data.HttpProxy.superclass.constructor.call(this);
5732     // is conn a conn config or a real conn?
5733     this.conn = conn;
5734     this.useAjax = !conn || !conn.events;
5735   
5736 };
5737
5738 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5739     // thse are take from connection...
5740     
5741     /**
5742      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5743      */
5744     /**
5745      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5746      * extra parameters to each request made by this object. (defaults to undefined)
5747      */
5748     /**
5749      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5750      *  to each request made by this object. (defaults to undefined)
5751      */
5752     /**
5753      * @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)
5754      */
5755     /**
5756      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5757      */
5758      /**
5759      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5760      * @type Boolean
5761      */
5762   
5763
5764     /**
5765      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5766      * @type Boolean
5767      */
5768     /**
5769      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5770      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5771      * a finer-grained basis than the DataProxy events.
5772      */
5773     getConnection : function(){
5774         return this.useAjax ? Roo.Ajax : this.conn;
5775     },
5776
5777     /**
5778      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5779      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5780      * process that block using the passed callback.
5781      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5782      * for the request to the remote server.
5783      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5784      * object into a block of Roo.data.Records.
5785      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5786      * The function must be passed <ul>
5787      * <li>The Record block object</li>
5788      * <li>The "arg" argument from the load function</li>
5789      * <li>A boolean success indicator</li>
5790      * </ul>
5791      * @param {Object} scope The scope in which to call the callback
5792      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5793      */
5794     load : function(params, reader, callback, scope, arg){
5795         if(this.fireEvent("beforeload", this, params) !== false){
5796             var  o = {
5797                 params : params || {},
5798                 request: {
5799                     callback : callback,
5800                     scope : scope,
5801                     arg : arg
5802                 },
5803                 reader: reader,
5804                 callback : this.loadResponse,
5805                 scope: this
5806             };
5807             if(this.useAjax){
5808                 Roo.applyIf(o, this.conn);
5809                 if(this.activeRequest){
5810                     Roo.Ajax.abort(this.activeRequest);
5811                 }
5812                 this.activeRequest = Roo.Ajax.request(o);
5813             }else{
5814                 this.conn.request(o);
5815             }
5816         }else{
5817             callback.call(scope||this, null, arg, false);
5818         }
5819     },
5820
5821     // private
5822     loadResponse : function(o, success, response){
5823         delete this.activeRequest;
5824         if(!success){
5825             this.fireEvent("loadexception", this, o, response);
5826             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5827             return;
5828         }
5829         var result;
5830         try {
5831             result = o.reader.read(response);
5832         }catch(e){
5833             this.fireEvent("loadexception", this, o, response, e);
5834             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5835             return;
5836         }
5837         
5838         this.fireEvent("load", this, o, o.request.arg);
5839         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5840     },
5841
5842     // private
5843     update : function(dataSet){
5844
5845     },
5846
5847     // private
5848     updateResponse : function(dataSet){
5849
5850     }
5851 });/*
5852  * Based on:
5853  * Ext JS Library 1.1.1
5854  * Copyright(c) 2006-2007, Ext JS, LLC.
5855  *
5856  * Originally Released Under LGPL - original licence link has changed is not relivant.
5857  *
5858  * Fork - LGPL
5859  * <script type="text/javascript">
5860  */
5861
5862 /**
5863  * @class Roo.data.ScriptTagProxy
5864  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5865  * other than the originating domain of the running page.<br><br>
5866  * <p>
5867  * <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
5868  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5869  * <p>
5870  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5871  * source code that is used as the source inside a &lt;script> tag.<br><br>
5872  * <p>
5873  * In order for the browser to process the returned data, the server must wrap the data object
5874  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5875  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5876  * depending on whether the callback name was passed:
5877  * <p>
5878  * <pre><code>
5879 boolean scriptTag = false;
5880 String cb = request.getParameter("callback");
5881 if (cb != null) {
5882     scriptTag = true;
5883     response.setContentType("text/javascript");
5884 } else {
5885     response.setContentType("application/x-json");
5886 }
5887 Writer out = response.getWriter();
5888 if (scriptTag) {
5889     out.write(cb + "(");
5890 }
5891 out.print(dataBlock.toJsonString());
5892 if (scriptTag) {
5893     out.write(");");
5894 }
5895 </pre></code>
5896  *
5897  * @constructor
5898  * @param {Object} config A configuration object.
5899  */
5900 Roo.data.ScriptTagProxy = function(config){
5901     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5902     Roo.apply(this, config);
5903     this.head = document.getElementsByTagName("head")[0];
5904 };
5905
5906 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5907
5908 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5909     /**
5910      * @cfg {String} url The URL from which to request the data object.
5911      */
5912     /**
5913      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5914      */
5915     timeout : 30000,
5916     /**
5917      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5918      * the server the name of the callback function set up by the load call to process the returned data object.
5919      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5920      * javascript output which calls this named function passing the data object as its only parameter.
5921      */
5922     callbackParam : "callback",
5923     /**
5924      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5925      * name to the request.
5926      */
5927     nocache : true,
5928
5929     /**
5930      * Load data from the configured URL, read the data object into
5931      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5932      * process that block using the passed callback.
5933      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5934      * for the request to the remote server.
5935      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5936      * object into a block of Roo.data.Records.
5937      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5938      * The function must be passed <ul>
5939      * <li>The Record block object</li>
5940      * <li>The "arg" argument from the load function</li>
5941      * <li>A boolean success indicator</li>
5942      * </ul>
5943      * @param {Object} scope The scope in which to call the callback
5944      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5945      */
5946     load : function(params, reader, callback, scope, arg){
5947         if(this.fireEvent("beforeload", this, params) !== false){
5948
5949             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5950
5951             var url = this.url;
5952             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5953             if(this.nocache){
5954                 url += "&_dc=" + (new Date().getTime());
5955             }
5956             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5957             var trans = {
5958                 id : transId,
5959                 cb : "stcCallback"+transId,
5960                 scriptId : "stcScript"+transId,
5961                 params : params,
5962                 arg : arg,
5963                 url : url,
5964                 callback : callback,
5965                 scope : scope,
5966                 reader : reader
5967             };
5968             var conn = this;
5969
5970             window[trans.cb] = function(o){
5971                 conn.handleResponse(o, trans);
5972             };
5973
5974             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5975
5976             if(this.autoAbort !== false){
5977                 this.abort();
5978             }
5979
5980             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5981
5982             var script = document.createElement("script");
5983             script.setAttribute("src", url);
5984             script.setAttribute("type", "text/javascript");
5985             script.setAttribute("id", trans.scriptId);
5986             this.head.appendChild(script);
5987
5988             this.trans = trans;
5989         }else{
5990             callback.call(scope||this, null, arg, false);
5991         }
5992     },
5993
5994     // private
5995     isLoading : function(){
5996         return this.trans ? true : false;
5997     },
5998
5999     /**
6000      * Abort the current server request.
6001      */
6002     abort : function(){
6003         if(this.isLoading()){
6004             this.destroyTrans(this.trans);
6005         }
6006     },
6007
6008     // private
6009     destroyTrans : function(trans, isLoaded){
6010         this.head.removeChild(document.getElementById(trans.scriptId));
6011         clearTimeout(trans.timeoutId);
6012         if(isLoaded){
6013             window[trans.cb] = undefined;
6014             try{
6015                 delete window[trans.cb];
6016             }catch(e){}
6017         }else{
6018             // if hasn't been loaded, wait for load to remove it to prevent script error
6019             window[trans.cb] = function(){
6020                 window[trans.cb] = undefined;
6021                 try{
6022                     delete window[trans.cb];
6023                 }catch(e){}
6024             };
6025         }
6026     },
6027
6028     // private
6029     handleResponse : function(o, trans){
6030         this.trans = false;
6031         this.destroyTrans(trans, true);
6032         var result;
6033         try {
6034             result = trans.reader.readRecords(o);
6035         }catch(e){
6036             this.fireEvent("loadexception", this, o, trans.arg, e);
6037             trans.callback.call(trans.scope||window, null, trans.arg, false);
6038             return;
6039         }
6040         this.fireEvent("load", this, o, trans.arg);
6041         trans.callback.call(trans.scope||window, result, trans.arg, true);
6042     },
6043
6044     // private
6045     handleFailure : function(trans){
6046         this.trans = false;
6047         this.destroyTrans(trans, false);
6048         this.fireEvent("loadexception", this, null, trans.arg);
6049         trans.callback.call(trans.scope||window, null, trans.arg, false);
6050     }
6051 });/*
6052  * Based on:
6053  * Ext JS Library 1.1.1
6054  * Copyright(c) 2006-2007, Ext JS, LLC.
6055  *
6056  * Originally Released Under LGPL - original licence link has changed is not relivant.
6057  *
6058  * Fork - LGPL
6059  * <script type="text/javascript">
6060  */
6061
6062 /**
6063  * @class Roo.data.JsonReader
6064  * @extends Roo.data.DataReader
6065  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6066  * based on mappings in a provided Roo.data.Record constructor.
6067  * 
6068  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6069  * in the reply previously. 
6070  * 
6071  * <p>
6072  * Example code:
6073  * <pre><code>
6074 var RecordDef = Roo.data.Record.create([
6075     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6076     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6077 ]);
6078 var myReader = new Roo.data.JsonReader({
6079     totalProperty: "results",    // The property which contains the total dataset size (optional)
6080     root: "rows",                // The property which contains an Array of row objects
6081     id: "id"                     // The property within each row object that provides an ID for the record (optional)
6082 }, RecordDef);
6083 </code></pre>
6084  * <p>
6085  * This would consume a JSON file like this:
6086  * <pre><code>
6087 { 'results': 2, 'rows': [
6088     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6089     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6090 }
6091 </code></pre>
6092  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6093  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6094  * paged from the remote server.
6095  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6096  * @cfg {String} root name of the property which contains the Array of row objects.
6097  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6098  * @constructor
6099  * Create a new JsonReader
6100  * @param {Object} meta Metadata configuration options
6101  * @param {Object} recordType Either an Array of field definition objects,
6102  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6103  */
6104 Roo.data.JsonReader = function(meta, recordType){
6105     
6106     meta = meta || {};
6107     // set some defaults:
6108     Roo.applyIf(meta, {
6109         totalProperty: 'total',
6110         successProperty : 'success',
6111         root : 'data',
6112         id : 'id'
6113     });
6114     
6115     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6116 };
6117 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6118     
6119     /**
6120      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
6121      * Used by Store query builder to append _requestMeta to params.
6122      * 
6123      */
6124     metaFromRemote : false,
6125     /**
6126      * This method is only used by a DataProxy which has retrieved data from a remote server.
6127      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6128      * @return {Object} data A data block which is used by an Roo.data.Store object as
6129      * a cache of Roo.data.Records.
6130      */
6131     read : function(response){
6132         var json = response.responseText;
6133        
6134         var o = /* eval:var:o */ eval("("+json+")");
6135         if(!o) {
6136             throw {message: "JsonReader.read: Json object not found"};
6137         }
6138         
6139         if(o.metaData){
6140             
6141             delete this.ef;
6142             this.metaFromRemote = true;
6143             this.meta = o.metaData;
6144             this.recordType = Roo.data.Record.create(o.metaData.fields);
6145             this.onMetaChange(this.meta, this.recordType, o);
6146         }
6147         return this.readRecords(o);
6148     },
6149
6150     // private function a store will implement
6151     onMetaChange : function(meta, recordType, o){
6152
6153     },
6154
6155     /**
6156          * @ignore
6157          */
6158     simpleAccess: function(obj, subsc) {
6159         return obj[subsc];
6160     },
6161
6162         /**
6163          * @ignore
6164          */
6165     getJsonAccessor: function(){
6166         var re = /[\[\.]/;
6167         return function(expr) {
6168             try {
6169                 return(re.test(expr))
6170                     ? new Function("obj", "return obj." + expr)
6171                     : function(obj){
6172                         return obj[expr];
6173                     };
6174             } catch(e){}
6175             return Roo.emptyFn;
6176         };
6177     }(),
6178
6179     /**
6180      * Create a data block containing Roo.data.Records from an XML document.
6181      * @param {Object} o An object which contains an Array of row objects in the property specified
6182      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6183      * which contains the total size of the dataset.
6184      * @return {Object} data A data block which is used by an Roo.data.Store object as
6185      * a cache of Roo.data.Records.
6186      */
6187     readRecords : function(o){
6188         /**
6189          * After any data loads, the raw JSON data is available for further custom processing.
6190          * @type Object
6191          */
6192         this.jsonData = o;
6193         var s = this.meta, Record = this.recordType,
6194             f = Record.prototype.fields, fi = f.items, fl = f.length;
6195
6196 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6197         if (!this.ef) {
6198             if(s.totalProperty) {
6199                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6200                 }
6201                 if(s.successProperty) {
6202                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6203                 }
6204                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6205                 if (s.id) {
6206                         var g = this.getJsonAccessor(s.id);
6207                         this.getId = function(rec) {
6208                                 var r = g(rec);
6209                                 return (r === undefined || r === "") ? null : r;
6210                         };
6211                 } else {
6212                         this.getId = function(){return null;};
6213                 }
6214             this.ef = [];
6215             for(var jj = 0; jj < fl; jj++){
6216                 f = fi[jj];
6217                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6218                 this.ef[jj] = this.getJsonAccessor(map);
6219             }
6220         }
6221
6222         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6223         if(s.totalProperty){
6224             var vt = parseInt(this.getTotal(o), 10);
6225             if(!isNaN(vt)){
6226                 totalRecords = vt;
6227             }
6228         }
6229         if(s.successProperty){
6230             var vs = this.getSuccess(o);
6231             if(vs === false || vs === 'false'){
6232                 success = false;
6233             }
6234         }
6235         var records = [];
6236             for(var i = 0; i < c; i++){
6237                     var n = root[i];
6238                 var values = {};
6239                 var id = this.getId(n);
6240                 for(var j = 0; j < fl; j++){
6241                     f = fi[j];
6242                 var v = this.ef[j](n);
6243                 if (!f.convert) {
6244                     Roo.log('missing convert for ' + f.name);
6245                     Roo.log(f);
6246                     continue;
6247                 }
6248                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6249                 }
6250                 var record = new Record(values, id);
6251                 record.json = n;
6252                 records[i] = record;
6253             }
6254             return {
6255                 success : success,
6256                 records : records,
6257                 totalRecords : totalRecords
6258             };
6259     }
6260 });/*
6261  * Based on:
6262  * Ext JS Library 1.1.1
6263  * Copyright(c) 2006-2007, Ext JS, LLC.
6264  *
6265  * Originally Released Under LGPL - original licence link has changed is not relivant.
6266  *
6267  * Fork - LGPL
6268  * <script type="text/javascript">
6269  */
6270
6271 /**
6272  * @class Roo.data.XmlReader
6273  * @extends Roo.data.DataReader
6274  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6275  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6276  * <p>
6277  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6278  * header in the HTTP response must be set to "text/xml".</em>
6279  * <p>
6280  * Example code:
6281  * <pre><code>
6282 var RecordDef = Roo.data.Record.create([
6283    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6284    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6285 ]);
6286 var myReader = new Roo.data.XmlReader({
6287    totalRecords: "results", // The element which contains the total dataset size (optional)
6288    record: "row",           // The repeated element which contains row information
6289    id: "id"                 // The element within the row that provides an ID for the record (optional)
6290 }, RecordDef);
6291 </code></pre>
6292  * <p>
6293  * This would consume an XML file like this:
6294  * <pre><code>
6295 &lt;?xml?>
6296 &lt;dataset>
6297  &lt;results>2&lt;/results>
6298  &lt;row>
6299    &lt;id>1&lt;/id>
6300    &lt;name>Bill&lt;/name>
6301    &lt;occupation>Gardener&lt;/occupation>
6302  &lt;/row>
6303  &lt;row>
6304    &lt;id>2&lt;/id>
6305    &lt;name>Ben&lt;/name>
6306    &lt;occupation>Horticulturalist&lt;/occupation>
6307  &lt;/row>
6308 &lt;/dataset>
6309 </code></pre>
6310  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6311  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6312  * paged from the remote server.
6313  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6314  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6315  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6316  * a record identifier value.
6317  * @constructor
6318  * Create a new XmlReader
6319  * @param {Object} meta Metadata configuration options
6320  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6321  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6322  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6323  */
6324 Roo.data.XmlReader = function(meta, recordType){
6325     meta = meta || {};
6326     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6327 };
6328 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6329     /**
6330      * This method is only used by a DataProxy which has retrieved data from a remote server.
6331          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6332          * to contain a method called 'responseXML' that returns an XML document object.
6333      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6334      * a cache of Roo.data.Records.
6335      */
6336     read : function(response){
6337         var doc = response.responseXML;
6338         if(!doc) {
6339             throw {message: "XmlReader.read: XML Document not available"};
6340         }
6341         return this.readRecords(doc);
6342     },
6343
6344     /**
6345      * Create a data block containing Roo.data.Records from an XML document.
6346          * @param {Object} doc A parsed XML document.
6347      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6348      * a cache of Roo.data.Records.
6349      */
6350     readRecords : function(doc){
6351         /**
6352          * After any data loads/reads, the raw XML Document is available for further custom processing.
6353          * @type XMLDocument
6354          */
6355         this.xmlData = doc;
6356         var root = doc.documentElement || doc;
6357         var q = Roo.DomQuery;
6358         var recordType = this.recordType, fields = recordType.prototype.fields;
6359         var sid = this.meta.id;
6360         var totalRecords = 0, success = true;
6361         if(this.meta.totalRecords){
6362             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6363         }
6364         
6365         if(this.meta.success){
6366             var sv = q.selectValue(this.meta.success, root, true);
6367             success = sv !== false && sv !== 'false';
6368         }
6369         var records = [];
6370         var ns = q.select(this.meta.record, root);
6371         for(var i = 0, len = ns.length; i < len; i++) {
6372                 var n = ns[i];
6373                 var values = {};
6374                 var id = sid ? q.selectValue(sid, n) : undefined;
6375                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6376                     var f = fields.items[j];
6377                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6378                     v = f.convert(v);
6379                     values[f.name] = v;
6380                 }
6381                 var record = new recordType(values, id);
6382                 record.node = n;
6383                 records[records.length] = record;
6384             }
6385
6386             return {
6387                 success : success,
6388                 records : records,
6389                 totalRecords : totalRecords || records.length
6390             };
6391     }
6392 });/*
6393  * Based on:
6394  * Ext JS Library 1.1.1
6395  * Copyright(c) 2006-2007, Ext JS, LLC.
6396  *
6397  * Originally Released Under LGPL - original licence link has changed is not relivant.
6398  *
6399  * Fork - LGPL
6400  * <script type="text/javascript">
6401  */
6402
6403 /**
6404  * @class Roo.data.ArrayReader
6405  * @extends Roo.data.DataReader
6406  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6407  * Each element of that Array represents a row of data fields. The
6408  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6409  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6410  * <p>
6411  * Example code:.
6412  * <pre><code>
6413 var RecordDef = Roo.data.Record.create([
6414     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6415     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6416 ]);
6417 var myReader = new Roo.data.ArrayReader({
6418     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6419 }, RecordDef);
6420 </code></pre>
6421  * <p>
6422  * This would consume an Array like this:
6423  * <pre><code>
6424 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6425   </code></pre>
6426  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6427  * @constructor
6428  * Create a new JsonReader
6429  * @param {Object} meta Metadata configuration options.
6430  * @param {Object} recordType Either an Array of field definition objects
6431  * as specified to {@link Roo.data.Record#create},
6432  * or an {@link Roo.data.Record} object
6433  * created using {@link Roo.data.Record#create}.
6434  */
6435 Roo.data.ArrayReader = function(meta, recordType){
6436     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6437 };
6438
6439 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6440     /**
6441      * Create a data block containing Roo.data.Records from an XML document.
6442      * @param {Object} o An Array of row objects which represents the dataset.
6443      * @return {Object} data A data block which is used by an Roo.data.Store object as
6444      * a cache of Roo.data.Records.
6445      */
6446     readRecords : function(o){
6447         var sid = this.meta ? this.meta.id : null;
6448         var recordType = this.recordType, fields = recordType.prototype.fields;
6449         var records = [];
6450         var root = o;
6451             for(var i = 0; i < root.length; i++){
6452                     var n = root[i];
6453                 var values = {};
6454                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6455                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6456                 var f = fields.items[j];
6457                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6458                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6459                 v = f.convert(v);
6460                 values[f.name] = v;
6461             }
6462                 var record = new recordType(values, id);
6463                 record.json = n;
6464                 records[records.length] = record;
6465             }
6466             return {
6467                 records : records,
6468                 totalRecords : records.length
6469             };
6470     }
6471 });/*
6472  * Based on:
6473  * Ext JS Library 1.1.1
6474  * Copyright(c) 2006-2007, Ext JS, LLC.
6475  *
6476  * Originally Released Under LGPL - original licence link has changed is not relivant.
6477  *
6478  * Fork - LGPL
6479  * <script type="text/javascript">
6480  */
6481
6482
6483 /**
6484  * @class Roo.data.Tree
6485  * @extends Roo.util.Observable
6486  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6487  * in the tree have most standard DOM functionality.
6488  * @constructor
6489  * @param {Node} root (optional) The root node
6490  */
6491 Roo.data.Tree = function(root){
6492    this.nodeHash = {};
6493    /**
6494     * The root node for this tree
6495     * @type Node
6496     */
6497    this.root = null;
6498    if(root){
6499        this.setRootNode(root);
6500    }
6501    this.addEvents({
6502        /**
6503         * @event append
6504         * Fires when a new child node is appended to a node in this tree.
6505         * @param {Tree} tree The owner tree
6506         * @param {Node} parent The parent node
6507         * @param {Node} node The newly appended node
6508         * @param {Number} index The index of the newly appended node
6509         */
6510        "append" : true,
6511        /**
6512         * @event remove
6513         * Fires when a child node is removed from a node in this tree.
6514         * @param {Tree} tree The owner tree
6515         * @param {Node} parent The parent node
6516         * @param {Node} node The child node removed
6517         */
6518        "remove" : true,
6519        /**
6520         * @event move
6521         * Fires when a node is moved to a new location in the tree
6522         * @param {Tree} tree The owner tree
6523         * @param {Node} node The node moved
6524         * @param {Node} oldParent The old parent of this node
6525         * @param {Node} newParent The new parent of this node
6526         * @param {Number} index The index it was moved to
6527         */
6528        "move" : true,
6529        /**
6530         * @event insert
6531         * Fires when a new child node is inserted in a node in this tree.
6532         * @param {Tree} tree The owner tree
6533         * @param {Node} parent The parent node
6534         * @param {Node} node The child node inserted
6535         * @param {Node} refNode The child node the node was inserted before
6536         */
6537        "insert" : true,
6538        /**
6539         * @event beforeappend
6540         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6541         * @param {Tree} tree The owner tree
6542         * @param {Node} parent The parent node
6543         * @param {Node} node The child node to be appended
6544         */
6545        "beforeappend" : true,
6546        /**
6547         * @event beforeremove
6548         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6549         * @param {Tree} tree The owner tree
6550         * @param {Node} parent The parent node
6551         * @param {Node} node The child node to be removed
6552         */
6553        "beforeremove" : true,
6554        /**
6555         * @event beforemove
6556         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6557         * @param {Tree} tree The owner tree
6558         * @param {Node} node The node being moved
6559         * @param {Node} oldParent The parent of the node
6560         * @param {Node} newParent The new parent the node is moving to
6561         * @param {Number} index The index it is being moved to
6562         */
6563        "beforemove" : true,
6564        /**
6565         * @event beforeinsert
6566         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6567         * @param {Tree} tree The owner tree
6568         * @param {Node} parent The parent node
6569         * @param {Node} node The child node to be inserted
6570         * @param {Node} refNode The child node the node is being inserted before
6571         */
6572        "beforeinsert" : true
6573    });
6574
6575     Roo.data.Tree.superclass.constructor.call(this);
6576 };
6577
6578 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6579     pathSeparator: "/",
6580
6581     proxyNodeEvent : function(){
6582         return this.fireEvent.apply(this, arguments);
6583     },
6584
6585     /**
6586      * Returns the root node for this tree.
6587      * @return {Node}
6588      */
6589     getRootNode : function(){
6590         return this.root;
6591     },
6592
6593     /**
6594      * Sets the root node for this tree.
6595      * @param {Node} node
6596      * @return {Node}
6597      */
6598     setRootNode : function(node){
6599         this.root = node;
6600         node.ownerTree = this;
6601         node.isRoot = true;
6602         this.registerNode(node);
6603         return node;
6604     },
6605
6606     /**
6607      * Gets a node in this tree by its id.
6608      * @param {String} id
6609      * @return {Node}
6610      */
6611     getNodeById : function(id){
6612         return this.nodeHash[id];
6613     },
6614
6615     registerNode : function(node){
6616         this.nodeHash[node.id] = node;
6617     },
6618
6619     unregisterNode : function(node){
6620         delete this.nodeHash[node.id];
6621     },
6622
6623     toString : function(){
6624         return "[Tree"+(this.id?" "+this.id:"")+"]";
6625     }
6626 });
6627
6628 /**
6629  * @class Roo.data.Node
6630  * @extends Roo.util.Observable
6631  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6632  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6633  * @constructor
6634  * @param {Object} attributes The attributes/config for the node
6635  */
6636 Roo.data.Node = function(attributes){
6637     /**
6638      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6639      * @type {Object}
6640      */
6641     this.attributes = attributes || {};
6642     this.leaf = this.attributes.leaf;
6643     /**
6644      * The node id. @type String
6645      */
6646     this.id = this.attributes.id;
6647     if(!this.id){
6648         this.id = Roo.id(null, "ynode-");
6649         this.attributes.id = this.id;
6650     }
6651     /**
6652      * All child nodes of this node. @type Array
6653      */
6654     this.childNodes = [];
6655     if(!this.childNodes.indexOf){ // indexOf is a must
6656         this.childNodes.indexOf = function(o){
6657             for(var i = 0, len = this.length; i < len; i++){
6658                 if(this[i] == o) {
6659                     return i;
6660                 }
6661             }
6662             return -1;
6663         };
6664     }
6665     /**
6666      * The parent node for this node. @type Node
6667      */
6668     this.parentNode = null;
6669     /**
6670      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6671      */
6672     this.firstChild = null;
6673     /**
6674      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6675      */
6676     this.lastChild = null;
6677     /**
6678      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6679      */
6680     this.previousSibling = null;
6681     /**
6682      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6683      */
6684     this.nextSibling = null;
6685
6686     this.addEvents({
6687        /**
6688         * @event append
6689         * Fires when a new child node is appended
6690         * @param {Tree} tree The owner tree
6691         * @param {Node} this This node
6692         * @param {Node} node The newly appended node
6693         * @param {Number} index The index of the newly appended node
6694         */
6695        "append" : true,
6696        /**
6697         * @event remove
6698         * Fires when a child node is removed
6699         * @param {Tree} tree The owner tree
6700         * @param {Node} this This node
6701         * @param {Node} node The removed node
6702         */
6703        "remove" : true,
6704        /**
6705         * @event move
6706         * Fires when this node is moved to a new location in the tree
6707         * @param {Tree} tree The owner tree
6708         * @param {Node} this This node
6709         * @param {Node} oldParent The old parent of this node
6710         * @param {Node} newParent The new parent of this node
6711         * @param {Number} index The index it was moved to
6712         */
6713        "move" : true,
6714        /**
6715         * @event insert
6716         * Fires when a new child node is inserted.
6717         * @param {Tree} tree The owner tree
6718         * @param {Node} this This node
6719         * @param {Node} node The child node inserted
6720         * @param {Node} refNode The child node the node was inserted before
6721         */
6722        "insert" : true,
6723        /**
6724         * @event beforeappend
6725         * Fires before a new child is appended, return false to cancel the append.
6726         * @param {Tree} tree The owner tree
6727         * @param {Node} this This node
6728         * @param {Node} node The child node to be appended
6729         */
6730        "beforeappend" : true,
6731        /**
6732         * @event beforeremove
6733         * Fires before a child is removed, return false to cancel the remove.
6734         * @param {Tree} tree The owner tree
6735         * @param {Node} this This node
6736         * @param {Node} node The child node to be removed
6737         */
6738        "beforeremove" : true,
6739        /**
6740         * @event beforemove
6741         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6742         * @param {Tree} tree The owner tree
6743         * @param {Node} this This node
6744         * @param {Node} oldParent The parent of this node
6745         * @param {Node} newParent The new parent this node is moving to
6746         * @param {Number} index The index it is being moved to
6747         */
6748        "beforemove" : true,
6749        /**
6750         * @event beforeinsert
6751         * Fires before a new child is inserted, return false to cancel the insert.
6752         * @param {Tree} tree The owner tree
6753         * @param {Node} this This node
6754         * @param {Node} node The child node to be inserted
6755         * @param {Node} refNode The child node the node is being inserted before
6756         */
6757        "beforeinsert" : true
6758    });
6759     this.listeners = this.attributes.listeners;
6760     Roo.data.Node.superclass.constructor.call(this);
6761 };
6762
6763 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6764     fireEvent : function(evtName){
6765         // first do standard event for this node
6766         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6767             return false;
6768         }
6769         // then bubble it up to the tree if the event wasn't cancelled
6770         var ot = this.getOwnerTree();
6771         if(ot){
6772             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6773                 return false;
6774             }
6775         }
6776         return true;
6777     },
6778
6779     /**
6780      * Returns true if this node is a leaf
6781      * @return {Boolean}
6782      */
6783     isLeaf : function(){
6784         return this.leaf === true;
6785     },
6786
6787     // private
6788     setFirstChild : function(node){
6789         this.firstChild = node;
6790     },
6791
6792     //private
6793     setLastChild : function(node){
6794         this.lastChild = node;
6795     },
6796
6797
6798     /**
6799      * Returns true if this node is the last child of its parent
6800      * @return {Boolean}
6801      */
6802     isLast : function(){
6803        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6804     },
6805
6806     /**
6807      * Returns true if this node is the first child of its parent
6808      * @return {Boolean}
6809      */
6810     isFirst : function(){
6811        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6812     },
6813
6814     hasChildNodes : function(){
6815         return !this.isLeaf() && this.childNodes.length > 0;
6816     },
6817
6818     /**
6819      * Insert node(s) as the last child node of this node.
6820      * @param {Node/Array} node The node or Array of nodes to append
6821      * @return {Node} The appended node if single append, or null if an array was passed
6822      */
6823     appendChild : function(node){
6824         var multi = false;
6825         if(node instanceof Array){
6826             multi = node;
6827         }else if(arguments.length > 1){
6828             multi = arguments;
6829         }
6830         // if passed an array or multiple args do them one by one
6831         if(multi){
6832             for(var i = 0, len = multi.length; i < len; i++) {
6833                 this.appendChild(multi[i]);
6834             }
6835         }else{
6836             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6837                 return false;
6838             }
6839             var index = this.childNodes.length;
6840             var oldParent = node.parentNode;
6841             // it's a move, make sure we move it cleanly
6842             if(oldParent){
6843                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6844                     return false;
6845                 }
6846                 oldParent.removeChild(node);
6847             }
6848             index = this.childNodes.length;
6849             if(index == 0){
6850                 this.setFirstChild(node);
6851             }
6852             this.childNodes.push(node);
6853             node.parentNode = this;
6854             var ps = this.childNodes[index-1];
6855             if(ps){
6856                 node.previousSibling = ps;
6857                 ps.nextSibling = node;
6858             }else{
6859                 node.previousSibling = null;
6860             }
6861             node.nextSibling = null;
6862             this.setLastChild(node);
6863             node.setOwnerTree(this.getOwnerTree());
6864             this.fireEvent("append", this.ownerTree, this, node, index);
6865             if(oldParent){
6866                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6867             }
6868             return node;
6869         }
6870     },
6871
6872     /**
6873      * Removes a child node from this node.
6874      * @param {Node} node The node to remove
6875      * @return {Node} The removed node
6876      */
6877     removeChild : function(node){
6878         var index = this.childNodes.indexOf(node);
6879         if(index == -1){
6880             return false;
6881         }
6882         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6883             return false;
6884         }
6885
6886         // remove it from childNodes collection
6887         this.childNodes.splice(index, 1);
6888
6889         // update siblings
6890         if(node.previousSibling){
6891             node.previousSibling.nextSibling = node.nextSibling;
6892         }
6893         if(node.nextSibling){
6894             node.nextSibling.previousSibling = node.previousSibling;
6895         }
6896
6897         // update child refs
6898         if(this.firstChild == node){
6899             this.setFirstChild(node.nextSibling);
6900         }
6901         if(this.lastChild == node){
6902             this.setLastChild(node.previousSibling);
6903         }
6904
6905         node.setOwnerTree(null);
6906         // clear any references from the node
6907         node.parentNode = null;
6908         node.previousSibling = null;
6909         node.nextSibling = null;
6910         this.fireEvent("remove", this.ownerTree, this, node);
6911         return node;
6912     },
6913
6914     /**
6915      * Inserts the first node before the second node in this nodes childNodes collection.
6916      * @param {Node} node The node to insert
6917      * @param {Node} refNode The node to insert before (if null the node is appended)
6918      * @return {Node} The inserted node
6919      */
6920     insertBefore : function(node, refNode){
6921         if(!refNode){ // like standard Dom, refNode can be null for append
6922             return this.appendChild(node);
6923         }
6924         // nothing to do
6925         if(node == refNode){
6926             return false;
6927         }
6928
6929         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6930             return false;
6931         }
6932         var index = this.childNodes.indexOf(refNode);
6933         var oldParent = node.parentNode;
6934         var refIndex = index;
6935
6936         // when moving internally, indexes will change after remove
6937         if(oldParent == this && this.childNodes.indexOf(node) < index){
6938             refIndex--;
6939         }
6940
6941         // it's a move, make sure we move it cleanly
6942         if(oldParent){
6943             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6944                 return false;
6945             }
6946             oldParent.removeChild(node);
6947         }
6948         if(refIndex == 0){
6949             this.setFirstChild(node);
6950         }
6951         this.childNodes.splice(refIndex, 0, node);
6952         node.parentNode = this;
6953         var ps = this.childNodes[refIndex-1];
6954         if(ps){
6955             node.previousSibling = ps;
6956             ps.nextSibling = node;
6957         }else{
6958             node.previousSibling = null;
6959         }
6960         node.nextSibling = refNode;
6961         refNode.previousSibling = node;
6962         node.setOwnerTree(this.getOwnerTree());
6963         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6964         if(oldParent){
6965             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6966         }
6967         return node;
6968     },
6969
6970     /**
6971      * Returns the child node at the specified index.
6972      * @param {Number} index
6973      * @return {Node}
6974      */
6975     item : function(index){
6976         return this.childNodes[index];
6977     },
6978
6979     /**
6980      * Replaces one child node in this node with another.
6981      * @param {Node} newChild The replacement node
6982      * @param {Node} oldChild The node to replace
6983      * @return {Node} The replaced node
6984      */
6985     replaceChild : function(newChild, oldChild){
6986         this.insertBefore(newChild, oldChild);
6987         this.removeChild(oldChild);
6988         return oldChild;
6989     },
6990
6991     /**
6992      * Returns the index of a child node
6993      * @param {Node} node
6994      * @return {Number} The index of the node or -1 if it was not found
6995      */
6996     indexOf : function(child){
6997         return this.childNodes.indexOf(child);
6998     },
6999
7000     /**
7001      * Returns the tree this node is in.
7002      * @return {Tree}
7003      */
7004     getOwnerTree : function(){
7005         // if it doesn't have one, look for one
7006         if(!this.ownerTree){
7007             var p = this;
7008             while(p){
7009                 if(p.ownerTree){
7010                     this.ownerTree = p.ownerTree;
7011                     break;
7012                 }
7013                 p = p.parentNode;
7014             }
7015         }
7016         return this.ownerTree;
7017     },
7018
7019     /**
7020      * Returns depth of this node (the root node has a depth of 0)
7021      * @return {Number}
7022      */
7023     getDepth : function(){
7024         var depth = 0;
7025         var p = this;
7026         while(p.parentNode){
7027             ++depth;
7028             p = p.parentNode;
7029         }
7030         return depth;
7031     },
7032
7033     // private
7034     setOwnerTree : function(tree){
7035         // if it's move, we need to update everyone
7036         if(tree != this.ownerTree){
7037             if(this.ownerTree){
7038                 this.ownerTree.unregisterNode(this);
7039             }
7040             this.ownerTree = tree;
7041             var cs = this.childNodes;
7042             for(var i = 0, len = cs.length; i < len; i++) {
7043                 cs[i].setOwnerTree(tree);
7044             }
7045             if(tree){
7046                 tree.registerNode(this);
7047             }
7048         }
7049     },
7050
7051     /**
7052      * Returns the path for this node. The path can be used to expand or select this node programmatically.
7053      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7054      * @return {String} The path
7055      */
7056     getPath : function(attr){
7057         attr = attr || "id";
7058         var p = this.parentNode;
7059         var b = [this.attributes[attr]];
7060         while(p){
7061             b.unshift(p.attributes[attr]);
7062             p = p.parentNode;
7063         }
7064         var sep = this.getOwnerTree().pathSeparator;
7065         return sep + b.join(sep);
7066     },
7067
7068     /**
7069      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7070      * function call will be the scope provided or the current node. The arguments to the function
7071      * will be the args provided or the current node. If the function returns false at any point,
7072      * the bubble is stopped.
7073      * @param {Function} fn The function to call
7074      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7075      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7076      */
7077     bubble : function(fn, scope, args){
7078         var p = this;
7079         while(p){
7080             if(fn.call(scope || p, args || p) === false){
7081                 break;
7082             }
7083             p = p.parentNode;
7084         }
7085     },
7086
7087     /**
7088      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7089      * function call will be the scope provided or the current node. The arguments to the function
7090      * will be the args provided or the current node. If the function returns false at any point,
7091      * the cascade is stopped on that branch.
7092      * @param {Function} fn The function to call
7093      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7094      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7095      */
7096     cascade : function(fn, scope, args){
7097         if(fn.call(scope || this, args || this) !== false){
7098             var cs = this.childNodes;
7099             for(var i = 0, len = cs.length; i < len; i++) {
7100                 cs[i].cascade(fn, scope, args);
7101             }
7102         }
7103     },
7104
7105     /**
7106      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7107      * function call will be the scope provided or the current node. The arguments to the function
7108      * will be the args provided or the current node. If the function returns false at any point,
7109      * the iteration stops.
7110      * @param {Function} fn The function to call
7111      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7112      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7113      */
7114     eachChild : function(fn, scope, args){
7115         var cs = this.childNodes;
7116         for(var i = 0, len = cs.length; i < len; i++) {
7117                 if(fn.call(scope || this, args || cs[i]) === false){
7118                     break;
7119                 }
7120         }
7121     },
7122
7123     /**
7124      * Finds the first child that has the attribute with the specified value.
7125      * @param {String} attribute The attribute name
7126      * @param {Mixed} value The value to search for
7127      * @return {Node} The found child or null if none was found
7128      */
7129     findChild : function(attribute, value){
7130         var cs = this.childNodes;
7131         for(var i = 0, len = cs.length; i < len; i++) {
7132                 if(cs[i].attributes[attribute] == value){
7133                     return cs[i];
7134                 }
7135         }
7136         return null;
7137     },
7138
7139     /**
7140      * Finds the first child by a custom function. The child matches if the function passed
7141      * returns true.
7142      * @param {Function} fn
7143      * @param {Object} scope (optional)
7144      * @return {Node} The found child or null if none was found
7145      */
7146     findChildBy : function(fn, scope){
7147         var cs = this.childNodes;
7148         for(var i = 0, len = cs.length; i < len; i++) {
7149                 if(fn.call(scope||cs[i], cs[i]) === true){
7150                     return cs[i];
7151                 }
7152         }
7153         return null;
7154     },
7155
7156     /**
7157      * Sorts this nodes children using the supplied sort function
7158      * @param {Function} fn
7159      * @param {Object} scope (optional)
7160      */
7161     sort : function(fn, scope){
7162         var cs = this.childNodes;
7163         var len = cs.length;
7164         if(len > 0){
7165             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7166             cs.sort(sortFn);
7167             for(var i = 0; i < len; i++){
7168                 var n = cs[i];
7169                 n.previousSibling = cs[i-1];
7170                 n.nextSibling = cs[i+1];
7171                 if(i == 0){
7172                     this.setFirstChild(n);
7173                 }
7174                 if(i == len-1){
7175                     this.setLastChild(n);
7176                 }
7177             }
7178         }
7179     },
7180
7181     /**
7182      * Returns true if this node is an ancestor (at any point) of the passed node.
7183      * @param {Node} node
7184      * @return {Boolean}
7185      */
7186     contains : function(node){
7187         return node.isAncestor(this);
7188     },
7189
7190     /**
7191      * Returns true if the passed node is an ancestor (at any point) of this node.
7192      * @param {Node} node
7193      * @return {Boolean}
7194      */
7195     isAncestor : function(node){
7196         var p = this.parentNode;
7197         while(p){
7198             if(p == node){
7199                 return true;
7200             }
7201             p = p.parentNode;
7202         }
7203         return false;
7204     },
7205
7206     toString : function(){
7207         return "[Node"+(this.id?" "+this.id:"")+"]";
7208     }
7209 });/*
7210  * Based on:
7211  * Ext JS Library 1.1.1
7212  * Copyright(c) 2006-2007, Ext JS, LLC.
7213  *
7214  * Originally Released Under LGPL - original licence link has changed is not relivant.
7215  *
7216  * Fork - LGPL
7217  * <script type="text/javascript">
7218  */
7219  
7220
7221 /**
7222  * @class Roo.ComponentMgr
7223  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7224  * @singleton
7225  */
7226 Roo.ComponentMgr = function(){
7227     var all = new Roo.util.MixedCollection();
7228
7229     return {
7230         /**
7231          * Registers a component.
7232          * @param {Roo.Component} c The component
7233          */
7234         register : function(c){
7235             all.add(c);
7236         },
7237
7238         /**
7239          * Unregisters a component.
7240          * @param {Roo.Component} c The component
7241          */
7242         unregister : function(c){
7243             all.remove(c);
7244         },
7245
7246         /**
7247          * Returns a component by id
7248          * @param {String} id The component id
7249          */
7250         get : function(id){
7251             return all.get(id);
7252         },
7253
7254         /**
7255          * Registers a function that will be called when a specified component is added to ComponentMgr
7256          * @param {String} id The component id
7257          * @param {Funtction} fn The callback function
7258          * @param {Object} scope The scope of the callback
7259          */
7260         onAvailable : function(id, fn, scope){
7261             all.on("add", function(index, o){
7262                 if(o.id == id){
7263                     fn.call(scope || o, o);
7264                     all.un("add", fn, scope);
7265                 }
7266             });
7267         }
7268     };
7269 }();/*
7270  * Based on:
7271  * Ext JS Library 1.1.1
7272  * Copyright(c) 2006-2007, Ext JS, LLC.
7273  *
7274  * Originally Released Under LGPL - original licence link has changed is not relivant.
7275  *
7276  * Fork - LGPL
7277  * <script type="text/javascript">
7278  */
7279  
7280 /**
7281  * @class Roo.Component
7282  * @extends Roo.util.Observable
7283  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7284  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7285  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7286  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7287  * All visual components (widgets) that require rendering into a layout should subclass Component.
7288  * @constructor
7289  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7290  * 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
7291  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7292  */
7293 Roo.Component = function(config){
7294     config = config || {};
7295     if(config.tagName || config.dom || typeof config == "string"){ // element object
7296         config = {el: config, id: config.id || config};
7297     }
7298     this.initialConfig = config;
7299
7300     Roo.apply(this, config);
7301     this.addEvents({
7302         /**
7303          * @event disable
7304          * Fires after the component is disabled.
7305              * @param {Roo.Component} this
7306              */
7307         disable : true,
7308         /**
7309          * @event enable
7310          * Fires after the component is enabled.
7311              * @param {Roo.Component} this
7312              */
7313         enable : true,
7314         /**
7315          * @event beforeshow
7316          * Fires before the component is shown.  Return false to stop the show.
7317              * @param {Roo.Component} this
7318              */
7319         beforeshow : true,
7320         /**
7321          * @event show
7322          * Fires after the component is shown.
7323              * @param {Roo.Component} this
7324              */
7325         show : true,
7326         /**
7327          * @event beforehide
7328          * Fires before the component is hidden. Return false to stop the hide.
7329              * @param {Roo.Component} this
7330              */
7331         beforehide : true,
7332         /**
7333          * @event hide
7334          * Fires after the component is hidden.
7335              * @param {Roo.Component} this
7336              */
7337         hide : true,
7338         /**
7339          * @event beforerender
7340          * Fires before the component is rendered. Return false to stop the render.
7341              * @param {Roo.Component} this
7342              */
7343         beforerender : true,
7344         /**
7345          * @event render
7346          * Fires after the component is rendered.
7347              * @param {Roo.Component} this
7348              */
7349         render : true,
7350         /**
7351          * @event beforedestroy
7352          * Fires before the component is destroyed. Return false to stop the destroy.
7353              * @param {Roo.Component} this
7354              */
7355         beforedestroy : true,
7356         /**
7357          * @event destroy
7358          * Fires after the component is destroyed.
7359              * @param {Roo.Component} this
7360              */
7361         destroy : true
7362     });
7363     if(!this.id){
7364         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7365     }
7366     Roo.ComponentMgr.register(this);
7367     Roo.Component.superclass.constructor.call(this);
7368     this.initComponent();
7369     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7370         this.render(this.renderTo);
7371         delete this.renderTo;
7372     }
7373 };
7374
7375 // private
7376 Roo.Component.AUTO_ID = 1000;
7377
7378 Roo.extend(Roo.Component, Roo.util.Observable, {
7379     /**
7380      * @property {Boolean} hidden
7381      * true if this component is hidden. Read-only.
7382      */
7383     hidden : false,
7384     /**
7385      * true if this component is disabled. Read-only.
7386      */
7387     disabled : false,
7388     /**
7389      * true if this component has been rendered. Read-only.
7390      */
7391     rendered : false,
7392     
7393     /** @cfg {String} disableClass
7394      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7395      */
7396     disabledClass : "x-item-disabled",
7397         /** @cfg {Boolean} allowDomMove
7398          * Whether the component can move the Dom node when rendering (defaults to true).
7399          */
7400     allowDomMove : true,
7401     /** @cfg {String} hideMode
7402      * How this component should hidden. Supported values are
7403      * "visibility" (css visibility), "offsets" (negative offset position) and
7404      * "display" (css display) - defaults to "display".
7405      */
7406     hideMode: 'display',
7407
7408     // private
7409     ctype : "Roo.Component",
7410
7411     /** @cfg {String} actionMode 
7412      * which property holds the element that used for  hide() / show() / disable() / enable()
7413      * default is 'el' 
7414      */
7415     actionMode : "el",
7416
7417     // private
7418     getActionEl : function(){
7419         return this[this.actionMode];
7420     },
7421
7422     initComponent : Roo.emptyFn,
7423     /**
7424      * If this is a lazy rendering component, render it to its container element.
7425      * @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.
7426      */
7427     render : function(container, position){
7428         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7429             if(!container && this.el){
7430                 this.el = Roo.get(this.el);
7431                 container = this.el.dom.parentNode;
7432                 this.allowDomMove = false;
7433             }
7434             this.container = Roo.get(container);
7435             this.rendered = true;
7436             if(position !== undefined){
7437                 if(typeof position == 'number'){
7438                     position = this.container.dom.childNodes[position];
7439                 }else{
7440                     position = Roo.getDom(position);
7441                 }
7442             }
7443             this.onRender(this.container, position || null);
7444             if(this.cls){
7445                 this.el.addClass(this.cls);
7446                 delete this.cls;
7447             }
7448             if(this.style){
7449                 this.el.applyStyles(this.style);
7450                 delete this.style;
7451             }
7452             this.fireEvent("render", this);
7453             this.afterRender(this.container);
7454             if(this.hidden){
7455                 this.hide();
7456             }
7457             if(this.disabled){
7458                 this.disable();
7459             }
7460         }
7461         return this;
7462     },
7463
7464     // private
7465     // default function is not really useful
7466     onRender : function(ct, position){
7467         if(this.el){
7468             this.el = Roo.get(this.el);
7469             if(this.allowDomMove !== false){
7470                 ct.dom.insertBefore(this.el.dom, position);
7471             }
7472         }
7473     },
7474
7475     // private
7476     getAutoCreate : function(){
7477         var cfg = typeof this.autoCreate == "object" ?
7478                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7479         if(this.id && !cfg.id){
7480             cfg.id = this.id;
7481         }
7482         return cfg;
7483     },
7484
7485     // private
7486     afterRender : Roo.emptyFn,
7487
7488     /**
7489      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7490      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7491      */
7492     destroy : function(){
7493         if(this.fireEvent("beforedestroy", this) !== false){
7494             this.purgeListeners();
7495             this.beforeDestroy();
7496             if(this.rendered){
7497                 this.el.removeAllListeners();
7498                 this.el.remove();
7499                 if(this.actionMode == "container"){
7500                     this.container.remove();
7501                 }
7502             }
7503             this.onDestroy();
7504             Roo.ComponentMgr.unregister(this);
7505             this.fireEvent("destroy", this);
7506         }
7507     },
7508
7509         // private
7510     beforeDestroy : function(){
7511
7512     },
7513
7514         // private
7515         onDestroy : function(){
7516
7517     },
7518
7519     /**
7520      * Returns the underlying {@link Roo.Element}.
7521      * @return {Roo.Element} The element
7522      */
7523     getEl : function(){
7524         return this.el;
7525     },
7526
7527     /**
7528      * Returns the id of this component.
7529      * @return {String}
7530      */
7531     getId : function(){
7532         return this.id;
7533     },
7534
7535     /**
7536      * Try to focus this component.
7537      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7538      * @return {Roo.Component} this
7539      */
7540     focus : function(selectText){
7541         if(this.rendered){
7542             this.el.focus();
7543             if(selectText === true){
7544                 this.el.dom.select();
7545             }
7546         }
7547         return this;
7548     },
7549
7550     // private
7551     blur : function(){
7552         if(this.rendered){
7553             this.el.blur();
7554         }
7555         return this;
7556     },
7557
7558     /**
7559      * Disable this component.
7560      * @return {Roo.Component} this
7561      */
7562     disable : function(){
7563         if(this.rendered){
7564             this.onDisable();
7565         }
7566         this.disabled = true;
7567         this.fireEvent("disable", this);
7568         return this;
7569     },
7570
7571         // private
7572     onDisable : function(){
7573         this.getActionEl().addClass(this.disabledClass);
7574         this.el.dom.disabled = true;
7575     },
7576
7577     /**
7578      * Enable this component.
7579      * @return {Roo.Component} this
7580      */
7581     enable : function(){
7582         if(this.rendered){
7583             this.onEnable();
7584         }
7585         this.disabled = false;
7586         this.fireEvent("enable", this);
7587         return this;
7588     },
7589
7590         // private
7591     onEnable : function(){
7592         this.getActionEl().removeClass(this.disabledClass);
7593         this.el.dom.disabled = false;
7594     },
7595
7596     /**
7597      * Convenience function for setting disabled/enabled by boolean.
7598      * @param {Boolean} disabled
7599      */
7600     setDisabled : function(disabled){
7601         this[disabled ? "disable" : "enable"]();
7602     },
7603
7604     /**
7605      * Show this component.
7606      * @return {Roo.Component} this
7607      */
7608     show: function(){
7609         if(this.fireEvent("beforeshow", this) !== false){
7610             this.hidden = false;
7611             if(this.rendered){
7612                 this.onShow();
7613             }
7614             this.fireEvent("show", this);
7615         }
7616         return this;
7617     },
7618
7619     // private
7620     onShow : function(){
7621         var ae = this.getActionEl();
7622         if(this.hideMode == 'visibility'){
7623             ae.dom.style.visibility = "visible";
7624         }else if(this.hideMode == 'offsets'){
7625             ae.removeClass('x-hidden');
7626         }else{
7627             ae.dom.style.display = "";
7628         }
7629     },
7630
7631     /**
7632      * Hide this component.
7633      * @return {Roo.Component} this
7634      */
7635     hide: function(){
7636         if(this.fireEvent("beforehide", this) !== false){
7637             this.hidden = true;
7638             if(this.rendered){
7639                 this.onHide();
7640             }
7641             this.fireEvent("hide", this);
7642         }
7643         return this;
7644     },
7645
7646     // private
7647     onHide : function(){
7648         var ae = this.getActionEl();
7649         if(this.hideMode == 'visibility'){
7650             ae.dom.style.visibility = "hidden";
7651         }else if(this.hideMode == 'offsets'){
7652             ae.addClass('x-hidden');
7653         }else{
7654             ae.dom.style.display = "none";
7655         }
7656     },
7657
7658     /**
7659      * Convenience function to hide or show this component by boolean.
7660      * @param {Boolean} visible True to show, false to hide
7661      * @return {Roo.Component} this
7662      */
7663     setVisible: function(visible){
7664         if(visible) {
7665             this.show();
7666         }else{
7667             this.hide();
7668         }
7669         return this;
7670     },
7671
7672     /**
7673      * Returns true if this component is visible.
7674      */
7675     isVisible : function(){
7676         return this.getActionEl().isVisible();
7677     },
7678
7679     cloneConfig : function(overrides){
7680         overrides = overrides || {};
7681         var id = overrides.id || Roo.id();
7682         var cfg = Roo.applyIf(overrides, this.initialConfig);
7683         cfg.id = id; // prevent dup id
7684         return new this.constructor(cfg);
7685     }
7686 });/*
7687  * Based on:
7688  * Ext JS Library 1.1.1
7689  * Copyright(c) 2006-2007, Ext JS, LLC.
7690  *
7691  * Originally Released Under LGPL - original licence link has changed is not relivant.
7692  *
7693  * Fork - LGPL
7694  * <script type="text/javascript">
7695  */
7696  (function(){ 
7697 /**
7698  * @class Roo.Layer
7699  * @extends Roo.Element
7700  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7701  * automatic maintaining of shadow/shim positions.
7702  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7703  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7704  * you can pass a string with a CSS class name. False turns off the shadow.
7705  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7706  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7707  * @cfg {String} cls CSS class to add to the element
7708  * @cfg {Number} zindex Starting z-index (defaults to 11000)
7709  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7710  * @constructor
7711  * @param {Object} config An object with config options.
7712  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7713  */
7714
7715 Roo.Layer = function(config, existingEl){
7716     config = config || {};
7717     var dh = Roo.DomHelper;
7718     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7719     if(existingEl){
7720         this.dom = Roo.getDom(existingEl);
7721     }
7722     if(!this.dom){
7723         var o = config.dh || {tag: "div", cls: "x-layer"};
7724         this.dom = dh.append(pel, o);
7725     }
7726     if(config.cls){
7727         this.addClass(config.cls);
7728     }
7729     this.constrain = config.constrain !== false;
7730     this.visibilityMode = Roo.Element.VISIBILITY;
7731     if(config.id){
7732         this.id = this.dom.id = config.id;
7733     }else{
7734         this.id = Roo.id(this.dom);
7735     }
7736     this.zindex = config.zindex || this.getZIndex();
7737     this.position("absolute", this.zindex);
7738     if(config.shadow){
7739         this.shadowOffset = config.shadowOffset || 4;
7740         this.shadow = new Roo.Shadow({
7741             offset : this.shadowOffset,
7742             mode : config.shadow
7743         });
7744     }else{
7745         this.shadowOffset = 0;
7746     }
7747     this.useShim = config.shim !== false && Roo.useShims;
7748     this.useDisplay = config.useDisplay;
7749     this.hide();
7750 };
7751
7752 var supr = Roo.Element.prototype;
7753
7754 // shims are shared among layer to keep from having 100 iframes
7755 var shims = [];
7756
7757 Roo.extend(Roo.Layer, Roo.Element, {
7758
7759     getZIndex : function(){
7760         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7761     },
7762
7763     getShim : function(){
7764         if(!this.useShim){
7765             return null;
7766         }
7767         if(this.shim){
7768             return this.shim;
7769         }
7770         var shim = shims.shift();
7771         if(!shim){
7772             shim = this.createShim();
7773             shim.enableDisplayMode('block');
7774             shim.dom.style.display = 'none';
7775             shim.dom.style.visibility = 'visible';
7776         }
7777         var pn = this.dom.parentNode;
7778         if(shim.dom.parentNode != pn){
7779             pn.insertBefore(shim.dom, this.dom);
7780         }
7781         shim.setStyle('z-index', this.getZIndex()-2);
7782         this.shim = shim;
7783         return shim;
7784     },
7785
7786     hideShim : function(){
7787         if(this.shim){
7788             this.shim.setDisplayed(false);
7789             shims.push(this.shim);
7790             delete this.shim;
7791         }
7792     },
7793
7794     disableShadow : function(){
7795         if(this.shadow){
7796             this.shadowDisabled = true;
7797             this.shadow.hide();
7798             this.lastShadowOffset = this.shadowOffset;
7799             this.shadowOffset = 0;
7800         }
7801     },
7802
7803     enableShadow : function(show){
7804         if(this.shadow){
7805             this.shadowDisabled = false;
7806             this.shadowOffset = this.lastShadowOffset;
7807             delete this.lastShadowOffset;
7808             if(show){
7809                 this.sync(true);
7810             }
7811         }
7812     },
7813
7814     // private
7815     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7816     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7817     sync : function(doShow){
7818         var sw = this.shadow;
7819         if(!this.updating && this.isVisible() && (sw || this.useShim)){
7820             var sh = this.getShim();
7821
7822             var w = this.getWidth(),
7823                 h = this.getHeight();
7824
7825             var l = this.getLeft(true),
7826                 t = this.getTop(true);
7827
7828             if(sw && !this.shadowDisabled){
7829                 if(doShow && !sw.isVisible()){
7830                     sw.show(this);
7831                 }else{
7832                     sw.realign(l, t, w, h);
7833                 }
7834                 if(sh){
7835                     if(doShow){
7836                        sh.show();
7837                     }
7838                     // fit the shim behind the shadow, so it is shimmed too
7839                     var a = sw.adjusts, s = sh.dom.style;
7840                     s.left = (Math.min(l, l+a.l))+"px";
7841                     s.top = (Math.min(t, t+a.t))+"px";
7842                     s.width = (w+a.w)+"px";
7843                     s.height = (h+a.h)+"px";
7844                 }
7845             }else if(sh){
7846                 if(doShow){
7847                    sh.show();
7848                 }
7849                 sh.setSize(w, h);
7850                 sh.setLeftTop(l, t);
7851             }
7852             
7853         }
7854     },
7855
7856     // private
7857     destroy : function(){
7858         this.hideShim();
7859         if(this.shadow){
7860             this.shadow.hide();
7861         }
7862         this.removeAllListeners();
7863         var pn = this.dom.parentNode;
7864         if(pn){
7865             pn.removeChild(this.dom);
7866         }
7867         Roo.Element.uncache(this.id);
7868     },
7869
7870     remove : function(){
7871         this.destroy();
7872     },
7873
7874     // private
7875     beginUpdate : function(){
7876         this.updating = true;
7877     },
7878
7879     // private
7880     endUpdate : function(){
7881         this.updating = false;
7882         this.sync(true);
7883     },
7884
7885     // private
7886     hideUnders : function(negOffset){
7887         if(this.shadow){
7888             this.shadow.hide();
7889         }
7890         this.hideShim();
7891     },
7892
7893     // private
7894     constrainXY : function(){
7895         if(this.constrain){
7896             var vw = Roo.lib.Dom.getViewWidth(),
7897                 vh = Roo.lib.Dom.getViewHeight();
7898             var s = Roo.get(document).getScroll();
7899
7900             var xy = this.getXY();
7901             var x = xy[0], y = xy[1];   
7902             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7903             // only move it if it needs it
7904             var moved = false;
7905             // first validate right/bottom
7906             if((x + w) > vw+s.left){
7907                 x = vw - w - this.shadowOffset;
7908                 moved = true;
7909             }
7910             if((y + h) > vh+s.top){
7911                 y = vh - h - this.shadowOffset;
7912                 moved = true;
7913             }
7914             // then make sure top/left isn't negative
7915             if(x < s.left){
7916                 x = s.left;
7917                 moved = true;
7918             }
7919             if(y < s.top){
7920                 y = s.top;
7921                 moved = true;
7922             }
7923             if(moved){
7924                 if(this.avoidY){
7925                     var ay = this.avoidY;
7926                     if(y <= ay && (y+h) >= ay){
7927                         y = ay-h-5;   
7928                     }
7929                 }
7930                 xy = [x, y];
7931                 this.storeXY(xy);
7932                 supr.setXY.call(this, xy);
7933                 this.sync();
7934             }
7935         }
7936     },
7937
7938     isVisible : function(){
7939         return this.visible;    
7940     },
7941
7942     // private
7943     showAction : function(){
7944         this.visible = true; // track visibility to prevent getStyle calls
7945         if(this.useDisplay === true){
7946             this.setDisplayed("");
7947         }else if(this.lastXY){
7948             supr.setXY.call(this, this.lastXY);
7949         }else if(this.lastLT){
7950             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7951         }
7952     },
7953
7954     // private
7955     hideAction : function(){
7956         this.visible = false;
7957         if(this.useDisplay === true){
7958             this.setDisplayed(false);
7959         }else{
7960             this.setLeftTop(-10000,-10000);
7961         }
7962     },
7963
7964     // overridden Element method
7965     setVisible : function(v, a, d, c, e){
7966         if(v){
7967             this.showAction();
7968         }
7969         if(a && v){
7970             var cb = function(){
7971                 this.sync(true);
7972                 if(c){
7973                     c();
7974                 }
7975             }.createDelegate(this);
7976             supr.setVisible.call(this, true, true, d, cb, e);
7977         }else{
7978             if(!v){
7979                 this.hideUnders(true);
7980             }
7981             var cb = c;
7982             if(a){
7983                 cb = function(){
7984                     this.hideAction();
7985                     if(c){
7986                         c();
7987                     }
7988                 }.createDelegate(this);
7989             }
7990             supr.setVisible.call(this, v, a, d, cb, e);
7991             if(v){
7992                 this.sync(true);
7993             }else if(!a){
7994                 this.hideAction();
7995             }
7996         }
7997     },
7998
7999     storeXY : function(xy){
8000         delete this.lastLT;
8001         this.lastXY = xy;
8002     },
8003
8004     storeLeftTop : function(left, top){
8005         delete this.lastXY;
8006         this.lastLT = [left, top];
8007     },
8008
8009     // private
8010     beforeFx : function(){
8011         this.beforeAction();
8012         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8013     },
8014
8015     // private
8016     afterFx : function(){
8017         Roo.Layer.superclass.afterFx.apply(this, arguments);
8018         this.sync(this.isVisible());
8019     },
8020
8021     // private
8022     beforeAction : function(){
8023         if(!this.updating && this.shadow){
8024             this.shadow.hide();
8025         }
8026     },
8027
8028     // overridden Element method
8029     setLeft : function(left){
8030         this.storeLeftTop(left, this.getTop(true));
8031         supr.setLeft.apply(this, arguments);
8032         this.sync();
8033     },
8034
8035     setTop : function(top){
8036         this.storeLeftTop(this.getLeft(true), top);
8037         supr.setTop.apply(this, arguments);
8038         this.sync();
8039     },
8040
8041     setLeftTop : function(left, top){
8042         this.storeLeftTop(left, top);
8043         supr.setLeftTop.apply(this, arguments);
8044         this.sync();
8045     },
8046
8047     setXY : function(xy, a, d, c, e){
8048         this.fixDisplay();
8049         this.beforeAction();
8050         this.storeXY(xy);
8051         var cb = this.createCB(c);
8052         supr.setXY.call(this, xy, a, d, cb, e);
8053         if(!a){
8054             cb();
8055         }
8056     },
8057
8058     // private
8059     createCB : function(c){
8060         var el = this;
8061         return function(){
8062             el.constrainXY();
8063             el.sync(true);
8064             if(c){
8065                 c();
8066             }
8067         };
8068     },
8069
8070     // overridden Element method
8071     setX : function(x, a, d, c, e){
8072         this.setXY([x, this.getY()], a, d, c, e);
8073     },
8074
8075     // overridden Element method
8076     setY : function(y, a, d, c, e){
8077         this.setXY([this.getX(), y], a, d, c, e);
8078     },
8079
8080     // overridden Element method
8081     setSize : function(w, h, a, d, c, e){
8082         this.beforeAction();
8083         var cb = this.createCB(c);
8084         supr.setSize.call(this, w, h, a, d, cb, e);
8085         if(!a){
8086             cb();
8087         }
8088     },
8089
8090     // overridden Element method
8091     setWidth : function(w, a, d, c, e){
8092         this.beforeAction();
8093         var cb = this.createCB(c);
8094         supr.setWidth.call(this, w, a, d, cb, e);
8095         if(!a){
8096             cb();
8097         }
8098     },
8099
8100     // overridden Element method
8101     setHeight : function(h, a, d, c, e){
8102         this.beforeAction();
8103         var cb = this.createCB(c);
8104         supr.setHeight.call(this, h, a, d, cb, e);
8105         if(!a){
8106             cb();
8107         }
8108     },
8109
8110     // overridden Element method
8111     setBounds : function(x, y, w, h, a, d, c, e){
8112         this.beforeAction();
8113         var cb = this.createCB(c);
8114         if(!a){
8115             this.storeXY([x, y]);
8116             supr.setXY.call(this, [x, y]);
8117             supr.setSize.call(this, w, h, a, d, cb, e);
8118             cb();
8119         }else{
8120             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8121         }
8122         return this;
8123     },
8124     
8125     /**
8126      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8127      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8128      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8129      * @param {Number} zindex The new z-index to set
8130      * @return {this} The Layer
8131      */
8132     setZIndex : function(zindex){
8133         this.zindex = zindex;
8134         this.setStyle("z-index", zindex + 2);
8135         if(this.shadow){
8136             this.shadow.setZIndex(zindex + 1);
8137         }
8138         if(this.shim){
8139             this.shim.setStyle("z-index", zindex);
8140         }
8141     }
8142 });
8143 })();/*
8144  * Based on:
8145  * Ext JS Library 1.1.1
8146  * Copyright(c) 2006-2007, Ext JS, LLC.
8147  *
8148  * Originally Released Under LGPL - original licence link has changed is not relivant.
8149  *
8150  * Fork - LGPL
8151  * <script type="text/javascript">
8152  */
8153
8154
8155 /**
8156  * @class Roo.Shadow
8157  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
8158  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
8159  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8160  * @constructor
8161  * Create a new Shadow
8162  * @param {Object} config The config object
8163  */
8164 Roo.Shadow = function(config){
8165     Roo.apply(this, config);
8166     if(typeof this.mode != "string"){
8167         this.mode = this.defaultMode;
8168     }
8169     var o = this.offset, a = {h: 0};
8170     var rad = Math.floor(this.offset/2);
8171     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8172         case "drop":
8173             a.w = 0;
8174             a.l = a.t = o;
8175             a.t -= 1;
8176             if(Roo.isIE){
8177                 a.l -= this.offset + rad;
8178                 a.t -= this.offset + rad;
8179                 a.w -= rad;
8180                 a.h -= rad;
8181                 a.t += 1;
8182             }
8183         break;
8184         case "sides":
8185             a.w = (o*2);
8186             a.l = -o;
8187             a.t = o-1;
8188             if(Roo.isIE){
8189                 a.l -= (this.offset - rad);
8190                 a.t -= this.offset + rad;
8191                 a.l += 1;
8192                 a.w -= (this.offset - rad)*2;
8193                 a.w -= rad + 1;
8194                 a.h -= 1;
8195             }
8196         break;
8197         case "frame":
8198             a.w = a.h = (o*2);
8199             a.l = a.t = -o;
8200             a.t += 1;
8201             a.h -= 2;
8202             if(Roo.isIE){
8203                 a.l -= (this.offset - rad);
8204                 a.t -= (this.offset - rad);
8205                 a.l += 1;
8206                 a.w -= (this.offset + rad + 1);
8207                 a.h -= (this.offset + rad);
8208                 a.h += 1;
8209             }
8210         break;
8211     };
8212
8213     this.adjusts = a;
8214 };
8215
8216 Roo.Shadow.prototype = {
8217     /**
8218      * @cfg {String} mode
8219      * The shadow display mode.  Supports the following options:<br />
8220      * sides: Shadow displays on both sides and bottom only<br />
8221      * frame: Shadow displays equally on all four sides<br />
8222      * drop: Traditional bottom-right drop shadow (default)
8223      */
8224     /**
8225      * @cfg {String} offset
8226      * The number of pixels to offset the shadow from the element (defaults to 4)
8227      */
8228     offset: 4,
8229
8230     // private
8231     defaultMode: "drop",
8232
8233     /**
8234      * Displays the shadow under the target element
8235      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8236      */
8237     show : function(target){
8238         target = Roo.get(target);
8239         if(!this.el){
8240             this.el = Roo.Shadow.Pool.pull();
8241             if(this.el.dom.nextSibling != target.dom){
8242                 this.el.insertBefore(target);
8243             }
8244         }
8245         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8246         if(Roo.isIE){
8247             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8248         }
8249         this.realign(
8250             target.getLeft(true),
8251             target.getTop(true),
8252             target.getWidth(),
8253             target.getHeight()
8254         );
8255         this.el.dom.style.display = "block";
8256     },
8257
8258     /**
8259      * Returns true if the shadow is visible, else false
8260      */
8261     isVisible : function(){
8262         return this.el ? true : false;  
8263     },
8264
8265     /**
8266      * Direct alignment when values are already available. Show must be called at least once before
8267      * calling this method to ensure it is initialized.
8268      * @param {Number} left The target element left position
8269      * @param {Number} top The target element top position
8270      * @param {Number} width The target element width
8271      * @param {Number} height The target element height
8272      */
8273     realign : function(l, t, w, h){
8274         if(!this.el){
8275             return;
8276         }
8277         var a = this.adjusts, d = this.el.dom, s = d.style;
8278         var iea = 0;
8279         s.left = (l+a.l)+"px";
8280         s.top = (t+a.t)+"px";
8281         var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8282  
8283         if(s.width != sws || s.height != shs){
8284             s.width = sws;
8285             s.height = shs;
8286             if(!Roo.isIE){
8287                 var cn = d.childNodes;
8288                 var sww = Math.max(0, (sw-12))+"px";
8289                 cn[0].childNodes[1].style.width = sww;
8290                 cn[1].childNodes[1].style.width = sww;
8291                 cn[2].childNodes[1].style.width = sww;
8292                 cn[1].style.height = Math.max(0, (sh-12))+"px";
8293             }
8294         }
8295     },
8296
8297     /**
8298      * Hides this shadow
8299      */
8300     hide : function(){
8301         if(this.el){
8302             this.el.dom.style.display = "none";
8303             Roo.Shadow.Pool.push(this.el);
8304             delete this.el;
8305         }
8306     },
8307
8308     /**
8309      * Adjust the z-index of this shadow
8310      * @param {Number} zindex The new z-index
8311      */
8312     setZIndex : function(z){
8313         this.zIndex = z;
8314         if(this.el){
8315             this.el.setStyle("z-index", z);
8316         }
8317     }
8318 };
8319
8320 // Private utility class that manages the internal Shadow cache
8321 Roo.Shadow.Pool = function(){
8322     var p = [];
8323     var markup = Roo.isIE ?
8324                  '<div class="x-ie-shadow"></div>' :
8325                  '<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>';
8326     return {
8327         pull : function(){
8328             var sh = p.shift();
8329             if(!sh){
8330                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8331                 sh.autoBoxAdjust = false;
8332             }
8333             return sh;
8334         },
8335
8336         push : function(sh){
8337             p.push(sh);
8338         }
8339     };
8340 }();/*
8341  * Based on:
8342  * Ext JS Library 1.1.1
8343  * Copyright(c) 2006-2007, Ext JS, LLC.
8344  *
8345  * Originally Released Under LGPL - original licence link has changed is not relivant.
8346  *
8347  * Fork - LGPL
8348  * <script type="text/javascript">
8349  */
8350
8351 /**
8352  * @class Roo.BoxComponent
8353  * @extends Roo.Component
8354  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
8355  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
8356  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8357  * layout containers.
8358  * @constructor
8359  * @param {Roo.Element/String/Object} config The configuration options.
8360  */
8361 Roo.BoxComponent = function(config){
8362     Roo.Component.call(this, config);
8363     this.addEvents({
8364         /**
8365          * @event resize
8366          * Fires after the component is resized.
8367              * @param {Roo.Component} this
8368              * @param {Number} adjWidth The box-adjusted width that was set
8369              * @param {Number} adjHeight The box-adjusted height that was set
8370              * @param {Number} rawWidth The width that was originally specified
8371              * @param {Number} rawHeight The height that was originally specified
8372              */
8373         resize : true,
8374         /**
8375          * @event move
8376          * Fires after the component is moved.
8377              * @param {Roo.Component} this
8378              * @param {Number} x The new x position
8379              * @param {Number} y The new y position
8380              */
8381         move : true
8382     });
8383 };
8384
8385 Roo.extend(Roo.BoxComponent, Roo.Component, {
8386     // private, set in afterRender to signify that the component has been rendered
8387     boxReady : false,
8388     // private, used to defer height settings to subclasses
8389     deferHeight: false,
8390     /** @cfg {Number} width
8391      * width (optional) size of component
8392      */
8393      /** @cfg {Number} height
8394      * height (optional) size of component
8395      */
8396      
8397     /**
8398      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
8399      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8400      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8401      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8402      * @return {Roo.BoxComponent} this
8403      */
8404     setSize : function(w, h){
8405         // support for standard size objects
8406         if(typeof w == 'object'){
8407             h = w.height;
8408             w = w.width;
8409         }
8410         // not rendered
8411         if(!this.boxReady){
8412             this.width = w;
8413             this.height = h;
8414             return this;
8415         }
8416
8417         // prevent recalcs when not needed
8418         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8419             return this;
8420         }
8421         this.lastSize = {width: w, height: h};
8422
8423         var adj = this.adjustSize(w, h);
8424         var aw = adj.width, ah = adj.height;
8425         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8426             var rz = this.getResizeEl();
8427             if(!this.deferHeight && aw !== undefined && ah !== undefined){
8428                 rz.setSize(aw, ah);
8429             }else if(!this.deferHeight && ah !== undefined){
8430                 rz.setHeight(ah);
8431             }else if(aw !== undefined){
8432                 rz.setWidth(aw);
8433             }
8434             this.onResize(aw, ah, w, h);
8435             this.fireEvent('resize', this, aw, ah, w, h);
8436         }
8437         return this;
8438     },
8439
8440     /**
8441      * Gets the current size of the component's underlying element.
8442      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8443      */
8444     getSize : function(){
8445         return this.el.getSize();
8446     },
8447
8448     /**
8449      * Gets the current XY position of the component's underlying element.
8450      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8451      * @return {Array} The XY position of the element (e.g., [100, 200])
8452      */
8453     getPosition : function(local){
8454         if(local === true){
8455             return [this.el.getLeft(true), this.el.getTop(true)];
8456         }
8457         return this.xy || this.el.getXY();
8458     },
8459
8460     /**
8461      * Gets the current box measurements of the component's underlying element.
8462      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8463      * @returns {Object} box An object in the format {x, y, width, height}
8464      */
8465     getBox : function(local){
8466         var s = this.el.getSize();
8467         if(local){
8468             s.x = this.el.getLeft(true);
8469             s.y = this.el.getTop(true);
8470         }else{
8471             var xy = this.xy || this.el.getXY();
8472             s.x = xy[0];
8473             s.y = xy[1];
8474         }
8475         return s;
8476     },
8477
8478     /**
8479      * Sets the current box measurements of the component's underlying element.
8480      * @param {Object} box An object in the format {x, y, width, height}
8481      * @returns {Roo.BoxComponent} this
8482      */
8483     updateBox : function(box){
8484         this.setSize(box.width, box.height);
8485         this.setPagePosition(box.x, box.y);
8486         return this;
8487     },
8488
8489     // protected
8490     getResizeEl : function(){
8491         return this.resizeEl || this.el;
8492     },
8493
8494     // protected
8495     getPositionEl : function(){
8496         return this.positionEl || this.el;
8497     },
8498
8499     /**
8500      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
8501      * This method fires the move event.
8502      * @param {Number} left The new left
8503      * @param {Number} top The new top
8504      * @returns {Roo.BoxComponent} this
8505      */
8506     setPosition : function(x, y){
8507         this.x = x;
8508         this.y = y;
8509         if(!this.boxReady){
8510             return this;
8511         }
8512         var adj = this.adjustPosition(x, y);
8513         var ax = adj.x, ay = adj.y;
8514
8515         var el = this.getPositionEl();
8516         if(ax !== undefined || ay !== undefined){
8517             if(ax !== undefined && ay !== undefined){
8518                 el.setLeftTop(ax, ay);
8519             }else if(ax !== undefined){
8520                 el.setLeft(ax);
8521             }else if(ay !== undefined){
8522                 el.setTop(ay);
8523             }
8524             this.onPosition(ax, ay);
8525             this.fireEvent('move', this, ax, ay);
8526         }
8527         return this;
8528     },
8529
8530     /**
8531      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
8532      * This method fires the move event.
8533      * @param {Number} x The new x position
8534      * @param {Number} y The new y position
8535      * @returns {Roo.BoxComponent} this
8536      */
8537     setPagePosition : function(x, y){
8538         this.pageX = x;
8539         this.pageY = y;
8540         if(!this.boxReady){
8541             return;
8542         }
8543         if(x === undefined || y === undefined){ // cannot translate undefined points
8544             return;
8545         }
8546         var p = this.el.translatePoints(x, y);
8547         this.setPosition(p.left, p.top);
8548         return this;
8549     },
8550
8551     // private
8552     onRender : function(ct, position){
8553         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8554         if(this.resizeEl){
8555             this.resizeEl = Roo.get(this.resizeEl);
8556         }
8557         if(this.positionEl){
8558             this.positionEl = Roo.get(this.positionEl);
8559         }
8560     },
8561
8562     // private
8563     afterRender : function(){
8564         Roo.BoxComponent.superclass.afterRender.call(this);
8565         this.boxReady = true;
8566         this.setSize(this.width, this.height);
8567         if(this.x || this.y){
8568             this.setPosition(this.x, this.y);
8569         }
8570         if(this.pageX || this.pageY){
8571             this.setPagePosition(this.pageX, this.pageY);
8572         }
8573     },
8574
8575     /**
8576      * Force the component's size to recalculate based on the underlying element's current height and width.
8577      * @returns {Roo.BoxComponent} this
8578      */
8579     syncSize : function(){
8580         delete this.lastSize;
8581         this.setSize(this.el.getWidth(), this.el.getHeight());
8582         return this;
8583     },
8584
8585     /**
8586      * Called after the component is resized, this method is empty by default but can be implemented by any
8587      * subclass that needs to perform custom logic after a resize occurs.
8588      * @param {Number} adjWidth The box-adjusted width that was set
8589      * @param {Number} adjHeight The box-adjusted height that was set
8590      * @param {Number} rawWidth The width that was originally specified
8591      * @param {Number} rawHeight The height that was originally specified
8592      */
8593     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8594
8595     },
8596
8597     /**
8598      * Called after the component is moved, this method is empty by default but can be implemented by any
8599      * subclass that needs to perform custom logic after a move occurs.
8600      * @param {Number} x The new x position
8601      * @param {Number} y The new y position
8602      */
8603     onPosition : function(x, y){
8604
8605     },
8606
8607     // private
8608     adjustSize : function(w, h){
8609         if(this.autoWidth){
8610             w = 'auto';
8611         }
8612         if(this.autoHeight){
8613             h = 'auto';
8614         }
8615         return {width : w, height: h};
8616     },
8617
8618     // private
8619     adjustPosition : function(x, y){
8620         return {x : x, y: y};
8621     }
8622 });/*
8623  * Based on:
8624  * Ext JS Library 1.1.1
8625  * Copyright(c) 2006-2007, Ext JS, LLC.
8626  *
8627  * Originally Released Under LGPL - original licence link has changed is not relivant.
8628  *
8629  * Fork - LGPL
8630  * <script type="text/javascript">
8631  */
8632
8633
8634 /**
8635  * @class Roo.SplitBar
8636  * @extends Roo.util.Observable
8637  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8638  * <br><br>
8639  * Usage:
8640  * <pre><code>
8641 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8642                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8643 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8644 split.minSize = 100;
8645 split.maxSize = 600;
8646 split.animate = true;
8647 split.on('moved', splitterMoved);
8648 </code></pre>
8649  * @constructor
8650  * Create a new SplitBar
8651  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
8652  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
8653  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8654  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
8655                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8656                         position of the SplitBar).
8657  */
8658 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8659     
8660     /** @private */
8661     this.el = Roo.get(dragElement, true);
8662     this.el.dom.unselectable = "on";
8663     /** @private */
8664     this.resizingEl = Roo.get(resizingElement, true);
8665
8666     /**
8667      * @private
8668      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8669      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8670      * @type Number
8671      */
8672     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8673     
8674     /**
8675      * The minimum size of the resizing element. (Defaults to 0)
8676      * @type Number
8677      */
8678     this.minSize = 0;
8679     
8680     /**
8681      * The maximum size of the resizing element. (Defaults to 2000)
8682      * @type Number
8683      */
8684     this.maxSize = 2000;
8685     
8686     /**
8687      * Whether to animate the transition to the new size
8688      * @type Boolean
8689      */
8690     this.animate = false;
8691     
8692     /**
8693      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8694      * @type Boolean
8695      */
8696     this.useShim = false;
8697     
8698     /** @private */
8699     this.shim = null;
8700     
8701     if(!existingProxy){
8702         /** @private */
8703         this.proxy = Roo.SplitBar.createProxy(this.orientation);
8704     }else{
8705         this.proxy = Roo.get(existingProxy).dom;
8706     }
8707     /** @private */
8708     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8709     
8710     /** @private */
8711     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8712     
8713     /** @private */
8714     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8715     
8716     /** @private */
8717     this.dragSpecs = {};
8718     
8719     /**
8720      * @private The adapter to use to positon and resize elements
8721      */
8722     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8723     this.adapter.init(this);
8724     
8725     if(this.orientation == Roo.SplitBar.HORIZONTAL){
8726         /** @private */
8727         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8728         this.el.addClass("x-splitbar-h");
8729     }else{
8730         /** @private */
8731         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8732         this.el.addClass("x-splitbar-v");
8733     }
8734     
8735     this.addEvents({
8736         /**
8737          * @event resize
8738          * Fires when the splitter is moved (alias for {@link #event-moved})
8739          * @param {Roo.SplitBar} this
8740          * @param {Number} newSize the new width or height
8741          */
8742         "resize" : true,
8743         /**
8744          * @event moved
8745          * Fires when the splitter is moved
8746          * @param {Roo.SplitBar} this
8747          * @param {Number} newSize the new width or height
8748          */
8749         "moved" : true,
8750         /**
8751          * @event beforeresize
8752          * Fires before the splitter is dragged
8753          * @param {Roo.SplitBar} this
8754          */
8755         "beforeresize" : true,
8756
8757         "beforeapply" : true
8758     });
8759
8760     Roo.util.Observable.call(this);
8761 };
8762
8763 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8764     onStartProxyDrag : function(x, y){
8765         this.fireEvent("beforeresize", this);
8766         if(!this.overlay){
8767             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
8768             o.unselectable();
8769             o.enableDisplayMode("block");
8770             // all splitbars share the same overlay
8771             Roo.SplitBar.prototype.overlay = o;
8772         }
8773         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8774         this.overlay.show();
8775         Roo.get(this.proxy).setDisplayed("block");
8776         var size = this.adapter.getElementSize(this);
8777         this.activeMinSize = this.getMinimumSize();;
8778         this.activeMaxSize = this.getMaximumSize();;
8779         var c1 = size - this.activeMinSize;
8780         var c2 = Math.max(this.activeMaxSize - size, 0);
8781         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8782             this.dd.resetConstraints();
8783             this.dd.setXConstraint(
8784                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
8785                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8786             );
8787             this.dd.setYConstraint(0, 0);
8788         }else{
8789             this.dd.resetConstraints();
8790             this.dd.setXConstraint(0, 0);
8791             this.dd.setYConstraint(
8792                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
8793                 this.placement == Roo.SplitBar.TOP ? c2 : c1
8794             );
8795          }
8796         this.dragSpecs.startSize = size;
8797         this.dragSpecs.startPoint = [x, y];
8798         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8799     },
8800     
8801     /** 
8802      * @private Called after the drag operation by the DDProxy
8803      */
8804     onEndProxyDrag : function(e){
8805         Roo.get(this.proxy).setDisplayed(false);
8806         var endPoint = Roo.lib.Event.getXY(e);
8807         if(this.overlay){
8808             this.overlay.hide();
8809         }
8810         var newSize;
8811         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8812             newSize = this.dragSpecs.startSize + 
8813                 (this.placement == Roo.SplitBar.LEFT ?
8814                     endPoint[0] - this.dragSpecs.startPoint[0] :
8815                     this.dragSpecs.startPoint[0] - endPoint[0]
8816                 );
8817         }else{
8818             newSize = this.dragSpecs.startSize + 
8819                 (this.placement == Roo.SplitBar.TOP ?
8820                     endPoint[1] - this.dragSpecs.startPoint[1] :
8821                     this.dragSpecs.startPoint[1] - endPoint[1]
8822                 );
8823         }
8824         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8825         if(newSize != this.dragSpecs.startSize){
8826             if(this.fireEvent('beforeapply', this, newSize) !== false){
8827                 this.adapter.setElementSize(this, newSize);
8828                 this.fireEvent("moved", this, newSize);
8829                 this.fireEvent("resize", this, newSize);
8830             }
8831         }
8832     },
8833     
8834     /**
8835      * Get the adapter this SplitBar uses
8836      * @return The adapter object
8837      */
8838     getAdapter : function(){
8839         return this.adapter;
8840     },
8841     
8842     /**
8843      * Set the adapter this SplitBar uses
8844      * @param {Object} adapter A SplitBar adapter object
8845      */
8846     setAdapter : function(adapter){
8847         this.adapter = adapter;
8848         this.adapter.init(this);
8849     },
8850     
8851     /**
8852      * Gets the minimum size for the resizing element
8853      * @return {Number} The minimum size
8854      */
8855     getMinimumSize : function(){
8856         return this.minSize;
8857     },
8858     
8859     /**
8860      * Sets the minimum size for the resizing element
8861      * @param {Number} minSize The minimum size
8862      */
8863     setMinimumSize : function(minSize){
8864         this.minSize = minSize;
8865     },
8866     
8867     /**
8868      * Gets the maximum size for the resizing element
8869      * @return {Number} The maximum size
8870      */
8871     getMaximumSize : function(){
8872         return this.maxSize;
8873     },
8874     
8875     /**
8876      * Sets the maximum size for the resizing element
8877      * @param {Number} maxSize The maximum size
8878      */
8879     setMaximumSize : function(maxSize){
8880         this.maxSize = maxSize;
8881     },
8882     
8883     /**
8884      * Sets the initialize size for the resizing element
8885      * @param {Number} size The initial size
8886      */
8887     setCurrentSize : function(size){
8888         var oldAnimate = this.animate;
8889         this.animate = false;
8890         this.adapter.setElementSize(this, size);
8891         this.animate = oldAnimate;
8892     },
8893     
8894     /**
8895      * Destroy this splitbar. 
8896      * @param {Boolean} removeEl True to remove the element
8897      */
8898     destroy : function(removeEl){
8899         if(this.shim){
8900             this.shim.remove();
8901         }
8902         this.dd.unreg();
8903         this.proxy.parentNode.removeChild(this.proxy);
8904         if(removeEl){
8905             this.el.remove();
8906         }
8907     }
8908 });
8909
8910 /**
8911  * @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.
8912  */
8913 Roo.SplitBar.createProxy = function(dir){
8914     var proxy = new Roo.Element(document.createElement("div"));
8915     proxy.unselectable();
8916     var cls = 'x-splitbar-proxy';
8917     proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8918     document.body.appendChild(proxy.dom);
8919     return proxy.dom;
8920 };
8921
8922 /** 
8923  * @class Roo.SplitBar.BasicLayoutAdapter
8924  * Default Adapter. It assumes the splitter and resizing element are not positioned
8925  * elements and only gets/sets the width of the element. Generally used for table based layouts.
8926  */
8927 Roo.SplitBar.BasicLayoutAdapter = function(){
8928 };
8929
8930 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8931     // do nothing for now
8932     init : function(s){
8933     
8934     },
8935     /**
8936      * Called before drag operations to get the current size of the resizing element. 
8937      * @param {Roo.SplitBar} s The SplitBar using this adapter
8938      */
8939      getElementSize : function(s){
8940         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8941             return s.resizingEl.getWidth();
8942         }else{
8943             return s.resizingEl.getHeight();
8944         }
8945     },
8946     
8947     /**
8948      * Called after drag operations to set the size of the resizing element.
8949      * @param {Roo.SplitBar} s The SplitBar using this adapter
8950      * @param {Number} newSize The new size to set
8951      * @param {Function} onComplete A function to be invoked when resizing is complete
8952      */
8953     setElementSize : function(s, newSize, onComplete){
8954         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8955             if(!s.animate){
8956                 s.resizingEl.setWidth(newSize);
8957                 if(onComplete){
8958                     onComplete(s, newSize);
8959                 }
8960             }else{
8961                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8962             }
8963         }else{
8964             
8965             if(!s.animate){
8966                 s.resizingEl.setHeight(newSize);
8967                 if(onComplete){
8968                     onComplete(s, newSize);
8969                 }
8970             }else{
8971                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8972             }
8973         }
8974     }
8975 };
8976
8977 /** 
8978  *@class Roo.SplitBar.AbsoluteLayoutAdapter
8979  * @extends Roo.SplitBar.BasicLayoutAdapter
8980  * Adapter that  moves the splitter element to align with the resized sizing element. 
8981  * Used with an absolute positioned SplitBar.
8982  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8983  * document.body, make sure you assign an id to the body element.
8984  */
8985 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8986     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8987     this.container = Roo.get(container);
8988 };
8989
8990 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8991     init : function(s){
8992         this.basic.init(s);
8993     },
8994     
8995     getElementSize : function(s){
8996         return this.basic.getElementSize(s);
8997     },
8998     
8999     setElementSize : function(s, newSize, onComplete){
9000         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9001     },
9002     
9003     moveSplitter : function(s){
9004         var yes = Roo.SplitBar;
9005         switch(s.placement){
9006             case yes.LEFT:
9007                 s.el.setX(s.resizingEl.getRight());
9008                 break;
9009             case yes.RIGHT:
9010                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9011                 break;
9012             case yes.TOP:
9013                 s.el.setY(s.resizingEl.getBottom());
9014                 break;
9015             case yes.BOTTOM:
9016                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9017                 break;
9018         }
9019     }
9020 };
9021
9022 /**
9023  * Orientation constant - Create a vertical SplitBar
9024  * @static
9025  * @type Number
9026  */
9027 Roo.SplitBar.VERTICAL = 1;
9028
9029 /**
9030  * Orientation constant - Create a horizontal SplitBar
9031  * @static
9032  * @type Number
9033  */
9034 Roo.SplitBar.HORIZONTAL = 2;
9035
9036 /**
9037  * Placement constant - The resizing element is to the left of the splitter element
9038  * @static
9039  * @type Number
9040  */
9041 Roo.SplitBar.LEFT = 1;
9042
9043 /**
9044  * Placement constant - The resizing element is to the right of the splitter element
9045  * @static
9046  * @type Number
9047  */
9048 Roo.SplitBar.RIGHT = 2;
9049
9050 /**
9051  * Placement constant - The resizing element is positioned above the splitter element
9052  * @static
9053  * @type Number
9054  */
9055 Roo.SplitBar.TOP = 3;
9056
9057 /**
9058  * Placement constant - The resizing element is positioned under splitter element
9059  * @static
9060  * @type Number
9061  */
9062 Roo.SplitBar.BOTTOM = 4;
9063 /*
9064  * Based on:
9065  * Ext JS Library 1.1.1
9066  * Copyright(c) 2006-2007, Ext JS, LLC.
9067  *
9068  * Originally Released Under LGPL - original licence link has changed is not relivant.
9069  *
9070  * Fork - LGPL
9071  * <script type="text/javascript">
9072  */
9073
9074 /**
9075  * @class Roo.View
9076  * @extends Roo.util.Observable
9077  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
9078  * This class also supports single and multi selection modes. <br>
9079  * Create a data model bound view:
9080  <pre><code>
9081  var store = new Roo.data.Store(...);
9082
9083  var view = new Roo.View({
9084     el : "my-element",
9085     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
9086  
9087     singleSelect: true,
9088     selectedClass: "ydataview-selected",
9089     store: store
9090  });
9091
9092  // listen for node click?
9093  view.on("click", function(vw, index, node, e){
9094  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9095  });
9096
9097  // load XML data
9098  dataModel.load("foobar.xml");
9099  </code></pre>
9100  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9101  * <br><br>
9102  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9103  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9104  * 
9105  * Note: old style constructor is still suported (container, template, config)
9106  * 
9107  * @constructor
9108  * Create a new View
9109  * @param {Object} config The config object
9110  * 
9111  */
9112 Roo.View = function(config, depreciated_tpl, depreciated_config){
9113     
9114     if (typeof(depreciated_tpl) == 'undefined') {
9115         // new way.. - universal constructor.
9116         Roo.apply(this, config);
9117         this.el  = Roo.get(this.el);
9118     } else {
9119         // old format..
9120         this.el  = Roo.get(config);
9121         this.tpl = depreciated_tpl;
9122         Roo.apply(this, depreciated_config);
9123     }
9124      
9125     
9126     if(typeof(this.tpl) == "string"){
9127         this.tpl = new Roo.Template(this.tpl);
9128     } else {
9129         // support xtype ctors..
9130         this.tpl = new Roo.factory(this.tpl, Roo);
9131     }
9132     
9133     
9134     this.tpl.compile();
9135    
9136
9137      
9138     /** @private */
9139     this.addEvents({
9140     /**
9141      * @event beforeclick
9142      * Fires before a click is processed. Returns false to cancel the default action.
9143      * @param {Roo.View} this
9144      * @param {Number} index The index of the target node
9145      * @param {HTMLElement} node The target node
9146      * @param {Roo.EventObject} e The raw event object
9147      */
9148         "beforeclick" : true,
9149     /**
9150      * @event click
9151      * Fires when a template node is clicked.
9152      * @param {Roo.View} this
9153      * @param {Number} index The index of the target node
9154      * @param {HTMLElement} node The target node
9155      * @param {Roo.EventObject} e The raw event object
9156      */
9157         "click" : true,
9158     /**
9159      * @event dblclick
9160      * Fires when a template node is double clicked.
9161      * @param {Roo.View} this
9162      * @param {Number} index The index of the target node
9163      * @param {HTMLElement} node The target node
9164      * @param {Roo.EventObject} e The raw event object
9165      */
9166         "dblclick" : true,
9167     /**
9168      * @event contextmenu
9169      * Fires when a template node is right clicked.
9170      * @param {Roo.View} this
9171      * @param {Number} index The index of the target node
9172      * @param {HTMLElement} node The target node
9173      * @param {Roo.EventObject} e The raw event object
9174      */
9175         "contextmenu" : true,
9176     /**
9177      * @event selectionchange
9178      * Fires when the selected nodes change.
9179      * @param {Roo.View} this
9180      * @param {Array} selections Array of the selected nodes
9181      */
9182         "selectionchange" : true,
9183
9184     /**
9185      * @event beforeselect
9186      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9187      * @param {Roo.View} this
9188      * @param {HTMLElement} node The node to be selected
9189      * @param {Array} selections Array of currently selected nodes
9190      */
9191         "beforeselect" : true
9192     });
9193
9194     this.el.on({
9195         "click": this.onClick,
9196         "dblclick": this.onDblClick,
9197         "contextmenu": this.onContextMenu,
9198         scope:this
9199     });
9200
9201     this.selections = [];
9202     this.nodes = [];
9203     this.cmp = new Roo.CompositeElementLite([]);
9204     if(this.store){
9205         this.store = Roo.factory(this.store, Roo.data);
9206         this.setStore(this.store, true);
9207     }
9208     Roo.View.superclass.constructor.call(this);
9209 };
9210
9211 Roo.extend(Roo.View, Roo.util.Observable, {
9212     
9213      /**
9214      * @cfg {Roo.data.Store} store Data store to load data from.
9215      */
9216     store : false,
9217     
9218     /**
9219      * @cfg {String|Roo.Element} el The container element.
9220      */
9221     el : '',
9222     
9223     /**
9224      * @cfg {String|Roo.Template} tpl The template used by this View 
9225      */
9226     tpl : false,
9227     
9228     /**
9229      * @cfg {String} selectedClass The css class to add to selected nodes
9230      */
9231     selectedClass : "x-view-selected",
9232      /**
9233      * @cfg {String} emptyText The empty text to show when nothing is loaded.
9234      */
9235     emptyText : "",
9236     /**
9237      * @cfg {Boolean} multiSelect Allow multiple selection
9238      */
9239     
9240     multiSelect : false,
9241     /**
9242      * @cfg {Boolean} singleSelect Allow single selection
9243      */
9244     singleSelect:  false,
9245     
9246     /**
9247      * Returns the element this view is bound to.
9248      * @return {Roo.Element}
9249      */
9250     getEl : function(){
9251         return this.el;
9252     },
9253
9254     /**
9255      * Refreshes the view.
9256      */
9257     refresh : function(){
9258         var t = this.tpl;
9259         this.clearSelections();
9260         this.el.update("");
9261         var html = [];
9262         var records = this.store.getRange();
9263         if(records.length < 1){
9264             this.el.update(this.emptyText);
9265             return;
9266         }
9267         for(var i = 0, len = records.length; i < len; i++){
9268             var data = this.prepareData(records[i].data, i, records[i]);
9269             html[html.length] = t.apply(data);
9270         }
9271         this.el.update(html.join(""));
9272         this.nodes = this.el.dom.childNodes;
9273         this.updateIndexes(0);
9274     },
9275
9276     /**
9277      * Function to override to reformat the data that is sent to
9278      * the template for each node.
9279      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9280      * a JSON object for an UpdateManager bound view).
9281      */
9282     prepareData : function(data){
9283         return data;
9284     },
9285
9286     onUpdate : function(ds, record){
9287         this.clearSelections();
9288         var index = this.store.indexOf(record);
9289         var n = this.nodes[index];
9290         this.tpl.insertBefore(n, this.prepareData(record.data));
9291         n.parentNode.removeChild(n);
9292         this.updateIndexes(index, index);
9293     },
9294
9295     onAdd : function(ds, records, index){
9296         this.clearSelections();
9297         if(this.nodes.length == 0){
9298             this.refresh();
9299             return;
9300         }
9301         var n = this.nodes[index];
9302         for(var i = 0, len = records.length; i < len; i++){
9303             var d = this.prepareData(records[i].data);
9304             if(n){
9305                 this.tpl.insertBefore(n, d);
9306             }else{
9307                 this.tpl.append(this.el, d);
9308             }
9309         }
9310         this.updateIndexes(index);
9311     },
9312
9313     onRemove : function(ds, record, index){
9314         this.clearSelections();
9315         this.el.dom.removeChild(this.nodes[index]);
9316         this.updateIndexes(index);
9317     },
9318
9319     /**
9320      * Refresh an individual node.
9321      * @param {Number} index
9322      */
9323     refreshNode : function(index){
9324         this.onUpdate(this.store, this.store.getAt(index));
9325     },
9326
9327     updateIndexes : function(startIndex, endIndex){
9328         var ns = this.nodes;
9329         startIndex = startIndex || 0;
9330         endIndex = endIndex || ns.length - 1;
9331         for(var i = startIndex; i <= endIndex; i++){
9332             ns[i].nodeIndex = i;
9333         }
9334     },
9335
9336     /**
9337      * Changes the data store this view uses and refresh the view.
9338      * @param {Store} store
9339      */
9340     setStore : function(store, initial){
9341         if(!initial && this.store){
9342             this.store.un("datachanged", this.refresh);
9343             this.store.un("add", this.onAdd);
9344             this.store.un("remove", this.onRemove);
9345             this.store.un("update", this.onUpdate);
9346             this.store.un("clear", this.refresh);
9347         }
9348         if(store){
9349           
9350             store.on("datachanged", this.refresh, this);
9351             store.on("add", this.onAdd, this);
9352             store.on("remove", this.onRemove, this);
9353             store.on("update", this.onUpdate, this);
9354             store.on("clear", this.refresh, this);
9355         }
9356         
9357         if(store){
9358             this.refresh();
9359         }
9360     },
9361
9362     /**
9363      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9364      * @param {HTMLElement} node
9365      * @return {HTMLElement} The template node
9366      */
9367     findItemFromChild : function(node){
9368         var el = this.el.dom;
9369         if(!node || node.parentNode == el){
9370                     return node;
9371             }
9372             var p = node.parentNode;
9373             while(p && p != el){
9374             if(p.parentNode == el){
9375                 return p;
9376             }
9377             p = p.parentNode;
9378         }
9379             return null;
9380     },
9381
9382     /** @ignore */
9383     onClick : function(e){
9384         var item = this.findItemFromChild(e.getTarget());
9385         if(item){
9386             var index = this.indexOf(item);
9387             if(this.onItemClick(item, index, e) !== false){
9388                 this.fireEvent("click", this, index, item, e);
9389             }
9390         }else{
9391             this.clearSelections();
9392         }
9393     },
9394
9395     /** @ignore */
9396     onContextMenu : function(e){
9397         var item = this.findItemFromChild(e.getTarget());
9398         if(item){
9399             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9400         }
9401     },
9402
9403     /** @ignore */
9404     onDblClick : function(e){
9405         var item = this.findItemFromChild(e.getTarget());
9406         if(item){
9407             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9408         }
9409     },
9410
9411     onItemClick : function(item, index, e){
9412         if(this.fireEvent("beforeclick", this, index, item, e) === false){
9413             return false;
9414         }
9415         if(this.multiSelect || this.singleSelect){
9416             if(this.multiSelect && e.shiftKey && this.lastSelection){
9417                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9418             }else{
9419                 this.select(item, this.multiSelect && e.ctrlKey);
9420                 this.lastSelection = item;
9421             }
9422             e.preventDefault();
9423         }
9424         return true;
9425     },
9426
9427     /**
9428      * Get the number of selected nodes.
9429      * @return {Number}
9430      */
9431     getSelectionCount : function(){
9432         return this.selections.length;
9433     },
9434
9435     /**
9436      * Get the currently selected nodes.
9437      * @return {Array} An array of HTMLElements
9438      */
9439     getSelectedNodes : function(){
9440         return this.selections;
9441     },
9442
9443     /**
9444      * Get the indexes of the selected nodes.
9445      * @return {Array}
9446      */
9447     getSelectedIndexes : function(){
9448         var indexes = [], s = this.selections;
9449         for(var i = 0, len = s.length; i < len; i++){
9450             indexes.push(s[i].nodeIndex);
9451         }
9452         return indexes;
9453     },
9454
9455     /**
9456      * Clear all selections
9457      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9458      */
9459     clearSelections : function(suppressEvent){
9460         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9461             this.cmp.elements = this.selections;
9462             this.cmp.removeClass(this.selectedClass);
9463             this.selections = [];
9464             if(!suppressEvent){
9465                 this.fireEvent("selectionchange", this, this.selections);
9466             }
9467         }
9468     },
9469
9470     /**
9471      * Returns true if the passed node is selected
9472      * @param {HTMLElement/Number} node The node or node index
9473      * @return {Boolean}
9474      */
9475     isSelected : function(node){
9476         var s = this.selections;
9477         if(s.length < 1){
9478             return false;
9479         }
9480         node = this.getNode(node);
9481         return s.indexOf(node) !== -1;
9482     },
9483
9484     /**
9485      * Selects nodes.
9486      * @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
9487      * @param {Boolean} keepExisting (optional) true to keep existing selections
9488      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9489      */
9490     select : function(nodeInfo, keepExisting, suppressEvent){
9491         if(nodeInfo instanceof Array){
9492             if(!keepExisting){
9493                 this.clearSelections(true);
9494             }
9495             for(var i = 0, len = nodeInfo.length; i < len; i++){
9496                 this.select(nodeInfo[i], true, true);
9497             }
9498         } else{
9499             var node = this.getNode(nodeInfo);
9500             if(node && !this.isSelected(node)){
9501                 if(!keepExisting){
9502                     this.clearSelections(true);
9503                 }
9504                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9505                     Roo.fly(node).addClass(this.selectedClass);
9506                     this.selections.push(node);
9507                     if(!suppressEvent){
9508                         this.fireEvent("selectionchange", this, this.selections);
9509                     }
9510                 }
9511             }
9512         }
9513     },
9514
9515     /**
9516      * Gets a template node.
9517      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9518      * @return {HTMLElement} The node or null if it wasn't found
9519      */
9520     getNode : function(nodeInfo){
9521         if(typeof nodeInfo == "string"){
9522             return document.getElementById(nodeInfo);
9523         }else if(typeof nodeInfo == "number"){
9524             return this.nodes[nodeInfo];
9525         }
9526         return nodeInfo;
9527     },
9528
9529     /**
9530      * Gets a range template nodes.
9531      * @param {Number} startIndex
9532      * @param {Number} endIndex
9533      * @return {Array} An array of nodes
9534      */
9535     getNodes : function(start, end){
9536         var ns = this.nodes;
9537         start = start || 0;
9538         end = typeof end == "undefined" ? ns.length - 1 : end;
9539         var nodes = [];
9540         if(start <= end){
9541             for(var i = start; i <= end; i++){
9542                 nodes.push(ns[i]);
9543             }
9544         } else{
9545             for(var i = start; i >= end; i--){
9546                 nodes.push(ns[i]);
9547             }
9548         }
9549         return nodes;
9550     },
9551
9552     /**
9553      * Finds the index of the passed node
9554      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9555      * @return {Number} The index of the node or -1
9556      */
9557     indexOf : function(node){
9558         node = this.getNode(node);
9559         if(typeof node.nodeIndex == "number"){
9560             return node.nodeIndex;
9561         }
9562         var ns = this.nodes;
9563         for(var i = 0, len = ns.length; i < len; i++){
9564             if(ns[i] == node){
9565                 return i;
9566             }
9567         }
9568         return -1;
9569     }
9570 });
9571 /*
9572  * Based on:
9573  * Ext JS Library 1.1.1
9574  * Copyright(c) 2006-2007, Ext JS, LLC.
9575  *
9576  * Originally Released Under LGPL - original licence link has changed is not relivant.
9577  *
9578  * Fork - LGPL
9579  * <script type="text/javascript">
9580  */
9581
9582 /**
9583  * @class Roo.JsonView
9584  * @extends Roo.View
9585  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9586 <pre><code>
9587 var view = new Roo.JsonView({
9588     container: "my-element",
9589     tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
9590     multiSelect: true, 
9591     jsonRoot: "data" 
9592 });
9593
9594 // listen for node click?
9595 view.on("click", function(vw, index, node, e){
9596     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9597 });
9598
9599 // direct load of JSON data
9600 view.load("foobar.php");
9601
9602 // Example from my blog list
9603 var tpl = new Roo.Template(
9604     '&lt;div class="entry"&gt;' +
9605     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
9606     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
9607     "&lt;/div&gt;&lt;hr /&gt;"
9608 );
9609
9610 var moreView = new Roo.JsonView({
9611     container :  "entry-list", 
9612     template : tpl,
9613     jsonRoot: "posts"
9614 });
9615 moreView.on("beforerender", this.sortEntries, this);
9616 moreView.load({
9617     url: "/blog/get-posts.php",
9618     params: "allposts=true",
9619     text: "Loading Blog Entries..."
9620 });
9621 </code></pre>
9622
9623 * Note: old code is supported with arguments : (container, template, config)
9624
9625
9626  * @constructor
9627  * Create a new JsonView
9628  * 
9629  * @param {Object} config The config object
9630  * 
9631  */
9632 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9633     
9634     
9635     Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9636
9637     var um = this.el.getUpdateManager();
9638     um.setRenderer(this);
9639     um.on("update", this.onLoad, this);
9640     um.on("failure", this.onLoadException, this);
9641
9642     /**
9643      * @event beforerender
9644      * Fires before rendering of the downloaded JSON data.
9645      * @param {Roo.JsonView} this
9646      * @param {Object} data The JSON data loaded
9647      */
9648     /**
9649      * @event load
9650      * Fires when data is loaded.
9651      * @param {Roo.JsonView} this
9652      * @param {Object} data The JSON data loaded
9653      * @param {Object} response The raw Connect response object
9654      */
9655     /**
9656      * @event loadexception
9657      * Fires when loading fails.
9658      * @param {Roo.JsonView} this
9659      * @param {Object} response The raw Connect response object
9660      */
9661     this.addEvents({
9662         'beforerender' : true,
9663         'load' : true,
9664         'loadexception' : true
9665     });
9666 };
9667 Roo.extend(Roo.JsonView, Roo.View, {
9668     /**
9669      * @type {String} The root property in the loaded JSON object that contains the data
9670      */
9671     jsonRoot : "",
9672
9673     /**
9674      * Refreshes the view.
9675      */
9676     refresh : function(){
9677         this.clearSelections();
9678         this.el.update("");
9679         var html = [];
9680         var o = this.jsonData;
9681         if(o && o.length > 0){
9682             for(var i = 0, len = o.length; i < len; i++){
9683                 var data = this.prepareData(o[i], i, o);
9684                 html[html.length] = this.tpl.apply(data);
9685             }
9686         }else{
9687             html.push(this.emptyText);
9688         }
9689         this.el.update(html.join(""));
9690         this.nodes = this.el.dom.childNodes;
9691         this.updateIndexes(0);
9692     },
9693
9694     /**
9695      * 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.
9696      * @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:
9697      <pre><code>
9698      view.load({
9699          url: "your-url.php",
9700          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9701          callback: yourFunction,
9702          scope: yourObject, //(optional scope)
9703          discardUrl: false,
9704          nocache: false,
9705          text: "Loading...",
9706          timeout: 30,
9707          scripts: false
9708      });
9709      </code></pre>
9710      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9711      * 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.
9712      * @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}
9713      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9714      * @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.
9715      */
9716     load : function(){
9717         var um = this.el.getUpdateManager();
9718         um.update.apply(um, arguments);
9719     },
9720
9721     render : function(el, response){
9722         this.clearSelections();
9723         this.el.update("");
9724         var o;
9725         try{
9726             o = Roo.util.JSON.decode(response.responseText);
9727             if(this.jsonRoot){
9728                 
9729                 o = o[this.jsonRoot];
9730             }
9731         } catch(e){
9732         }
9733         /**
9734          * The current JSON data or null
9735          */
9736         this.jsonData = o;
9737         this.beforeRender();
9738         this.refresh();
9739     },
9740
9741 /**
9742  * Get the number of records in the current JSON dataset
9743  * @return {Number}
9744  */
9745     getCount : function(){
9746         return this.jsonData ? this.jsonData.length : 0;
9747     },
9748
9749 /**
9750  * Returns the JSON object for the specified node(s)
9751  * @param {HTMLElement/Array} node The node or an array of nodes
9752  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9753  * you get the JSON object for the node
9754  */
9755     getNodeData : function(node){
9756         if(node instanceof Array){
9757             var data = [];
9758             for(var i = 0, len = node.length; i < len; i++){
9759                 data.push(this.getNodeData(node[i]));
9760             }
9761             return data;
9762         }
9763         return this.jsonData[this.indexOf(node)] || null;
9764     },
9765
9766     beforeRender : function(){
9767         this.snapshot = this.jsonData;
9768         if(this.sortInfo){
9769             this.sort.apply(this, this.sortInfo);
9770         }
9771         this.fireEvent("beforerender", this, this.jsonData);
9772     },
9773
9774     onLoad : function(el, o){
9775         this.fireEvent("load", this, this.jsonData, o);
9776     },
9777
9778     onLoadException : function(el, o){
9779         this.fireEvent("loadexception", this, o);
9780     },
9781
9782 /**
9783  * Filter the data by a specific property.
9784  * @param {String} property A property on your JSON objects
9785  * @param {String/RegExp} value Either string that the property values
9786  * should start with, or a RegExp to test against the property
9787  */
9788     filter : function(property, value){
9789         if(this.jsonData){
9790             var data = [];
9791             var ss = this.snapshot;
9792             if(typeof value == "string"){
9793                 var vlen = value.length;
9794                 if(vlen == 0){
9795                     this.clearFilter();
9796                     return;
9797                 }
9798                 value = value.toLowerCase();
9799                 for(var i = 0, len = ss.length; i < len; i++){
9800                     var o = ss[i];
9801                     if(o[property].substr(0, vlen).toLowerCase() == value){
9802                         data.push(o);
9803                     }
9804                 }
9805             } else if(value.exec){ // regex?
9806                 for(var i = 0, len = ss.length; i < len; i++){
9807                     var o = ss[i];
9808                     if(value.test(o[property])){
9809                         data.push(o);
9810                     }
9811                 }
9812             } else{
9813                 return;
9814             }
9815             this.jsonData = data;
9816             this.refresh();
9817         }
9818     },
9819
9820 /**
9821  * Filter by a function. The passed function will be called with each
9822  * object in the current dataset. If the function returns true the value is kept,
9823  * otherwise it is filtered.
9824  * @param {Function} fn
9825  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9826  */
9827     filterBy : function(fn, scope){
9828         if(this.jsonData){
9829             var data = [];
9830             var ss = this.snapshot;
9831             for(var i = 0, len = ss.length; i < len; i++){
9832                 var o = ss[i];
9833                 if(fn.call(scope || this, o)){
9834                     data.push(o);
9835                 }
9836             }
9837             this.jsonData = data;
9838             this.refresh();
9839         }
9840     },
9841
9842 /**
9843  * Clears the current filter.
9844  */
9845     clearFilter : function(){
9846         if(this.snapshot && this.jsonData != this.snapshot){
9847             this.jsonData = this.snapshot;
9848             this.refresh();
9849         }
9850     },
9851
9852
9853 /**
9854  * Sorts the data for this view and refreshes it.
9855  * @param {String} property A property on your JSON objects to sort on
9856  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9857  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9858  */
9859     sort : function(property, dir, sortType){
9860         this.sortInfo = Array.prototype.slice.call(arguments, 0);
9861         if(this.jsonData){
9862             var p = property;
9863             var dsc = dir && dir.toLowerCase() == "desc";
9864             var f = function(o1, o2){
9865                 var v1 = sortType ? sortType(o1[p]) : o1[p];
9866                 var v2 = sortType ? sortType(o2[p]) : o2[p];
9867                 ;
9868                 if(v1 < v2){
9869                     return dsc ? +1 : -1;
9870                 } else if(v1 > v2){
9871                     return dsc ? -1 : +1;
9872                 } else{
9873                     return 0;
9874                 }
9875             };
9876             this.jsonData.sort(f);
9877             this.refresh();
9878             if(this.jsonData != this.snapshot){
9879                 this.snapshot.sort(f);
9880             }
9881         }
9882     }
9883 });/*
9884  * Based on:
9885  * Ext JS Library 1.1.1
9886  * Copyright(c) 2006-2007, Ext JS, LLC.
9887  *
9888  * Originally Released Under LGPL - original licence link has changed is not relivant.
9889  *
9890  * Fork - LGPL
9891  * <script type="text/javascript">
9892  */
9893  
9894
9895 /**
9896  * @class Roo.ColorPalette
9897  * @extends Roo.Component
9898  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
9899  * Here's an example of typical usage:
9900  * <pre><code>
9901 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
9902 cp.render('my-div');
9903
9904 cp.on('select', function(palette, selColor){
9905     // do something with selColor
9906 });
9907 </code></pre>
9908  * @constructor
9909  * Create a new ColorPalette
9910  * @param {Object} config The config object
9911  */
9912 Roo.ColorPalette = function(config){
9913     Roo.ColorPalette.superclass.constructor.call(this, config);
9914     this.addEvents({
9915         /**
9916              * @event select
9917              * Fires when a color is selected
9918              * @param {ColorPalette} this
9919              * @param {String} color The 6-digit color hex code (without the # symbol)
9920              */
9921         select: true
9922     });
9923
9924     if(this.handler){
9925         this.on("select", this.handler, this.scope, true);
9926     }
9927 };
9928 Roo.extend(Roo.ColorPalette, Roo.Component, {
9929     /**
9930      * @cfg {String} itemCls
9931      * The CSS class to apply to the containing element (defaults to "x-color-palette")
9932      */
9933     itemCls : "x-color-palette",
9934     /**
9935      * @cfg {String} value
9936      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
9937      * the hex codes are case-sensitive.
9938      */
9939     value : null,
9940     clickEvent:'click',
9941     // private
9942     ctype: "Roo.ColorPalette",
9943
9944     /**
9945      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9946      */
9947     allowReselect : false,
9948
9949     /**
9950      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
9951      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
9952      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9953      * of colors with the width setting until the box is symmetrical.</p>
9954      * <p>You can override individual colors if needed:</p>
9955      * <pre><code>
9956 var cp = new Roo.ColorPalette();
9957 cp.colors[0] = "FF0000";  // change the first box to red
9958 </code></pre>
9959
9960 Or you can provide a custom array of your own for complete control:
9961 <pre><code>
9962 var cp = new Roo.ColorPalette();
9963 cp.colors = ["000000", "993300", "333300"];
9964 </code></pre>
9965      * @type Array
9966      */
9967     colors : [
9968         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9969         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9970         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9971         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9972         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9973     ],
9974
9975     // private
9976     onRender : function(container, position){
9977         var t = new Roo.MasterTemplate(
9978             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
9979         );
9980         var c = this.colors;
9981         for(var i = 0, len = c.length; i < len; i++){
9982             t.add([c[i]]);
9983         }
9984         var el = document.createElement("div");
9985         el.className = this.itemCls;
9986         t.overwrite(el);
9987         container.dom.insertBefore(el, position);
9988         this.el = Roo.get(el);
9989         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
9990         if(this.clickEvent != 'click'){
9991             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
9992         }
9993     },
9994
9995     // private
9996     afterRender : function(){
9997         Roo.ColorPalette.superclass.afterRender.call(this);
9998         if(this.value){
9999             var s = this.value;
10000             this.value = null;
10001             this.select(s);
10002         }
10003     },
10004
10005     // private
10006     handleClick : function(e, t){
10007         e.preventDefault();
10008         if(!this.disabled){
10009             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10010             this.select(c.toUpperCase());
10011         }
10012     },
10013
10014     /**
10015      * Selects the specified color in the palette (fires the select event)
10016      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10017      */
10018     select : function(color){
10019         color = color.replace("#", "");
10020         if(color != this.value || this.allowReselect){
10021             var el = this.el;
10022             if(this.value){
10023                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10024             }
10025             el.child("a.color-"+color).addClass("x-color-palette-sel");
10026             this.value = color;
10027             this.fireEvent("select", this, color);
10028         }
10029     }
10030 });/*
10031  * Based on:
10032  * Ext JS Library 1.1.1
10033  * Copyright(c) 2006-2007, Ext JS, LLC.
10034  *
10035  * Originally Released Under LGPL - original licence link has changed is not relivant.
10036  *
10037  * Fork - LGPL
10038  * <script type="text/javascript">
10039  */
10040  
10041 /**
10042  * @class Roo.DatePicker
10043  * @extends Roo.Component
10044  * Simple date picker class.
10045  * @constructor
10046  * Create a new DatePicker
10047  * @param {Object} config The config object
10048  */
10049 Roo.DatePicker = function(config){
10050     Roo.DatePicker.superclass.constructor.call(this, config);
10051
10052     this.value = config && config.value ?
10053                  config.value.clearTime() : new Date().clearTime();
10054
10055     this.addEvents({
10056         /**
10057              * @event select
10058              * Fires when a date is selected
10059              * @param {DatePicker} this
10060              * @param {Date} date The selected date
10061              */
10062         select: true
10063     });
10064
10065     if(this.handler){
10066         this.on("select", this.handler,  this.scope || this);
10067     }
10068     // build the disabledDatesRE
10069     if(!this.disabledDatesRE && this.disabledDates){
10070         var dd = this.disabledDates;
10071         var re = "(?:";
10072         for(var i = 0; i < dd.length; i++){
10073             re += dd[i];
10074             if(i != dd.length-1) re += "|";
10075         }
10076         this.disabledDatesRE = new RegExp(re + ")");
10077     }
10078 };
10079
10080 Roo.extend(Roo.DatePicker, Roo.Component, {
10081     /**
10082      * @cfg {String} todayText
10083      * The text to display on the button that selects the current date (defaults to "Today")
10084      */
10085     todayText : "Today",
10086     /**
10087      * @cfg {String} okText
10088      * The text to display on the ok button
10089      */
10090     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
10091     /**
10092      * @cfg {String} cancelText
10093      * The text to display on the cancel button
10094      */
10095     cancelText : "Cancel",
10096     /**
10097      * @cfg {String} todayTip
10098      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10099      */
10100     todayTip : "{0} (Spacebar)",
10101     /**
10102      * @cfg {Date} minDate
10103      * Minimum allowable date (JavaScript date object, defaults to null)
10104      */
10105     minDate : null,
10106     /**
10107      * @cfg {Date} maxDate
10108      * Maximum allowable date (JavaScript date object, defaults to null)
10109      */
10110     maxDate : null,
10111     /**
10112      * @cfg {String} minText
10113      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10114      */
10115     minText : "This date is before the minimum date",
10116     /**
10117      * @cfg {String} maxText
10118      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10119      */
10120     maxText : "This date is after the maximum date",
10121     /**
10122      * @cfg {String} format
10123      * The default date format string which can be overriden for localization support.  The format must be
10124      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10125      */
10126     format : "m/d/y",
10127     /**
10128      * @cfg {Array} disabledDays
10129      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10130      */
10131     disabledDays : null,
10132     /**
10133      * @cfg {String} disabledDaysText
10134      * The tooltip to display when the date falls on a disabled day (defaults to "")
10135      */
10136     disabledDaysText : "",
10137     /**
10138      * @cfg {RegExp} disabledDatesRE
10139      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10140      */
10141     disabledDatesRE : null,
10142     /**
10143      * @cfg {String} disabledDatesText
10144      * The tooltip text to display when the date falls on a disabled date (defaults to "")
10145      */
10146     disabledDatesText : "",
10147     /**
10148      * @cfg {Boolean} constrainToViewport
10149      * True to constrain the date picker to the viewport (defaults to true)
10150      */
10151     constrainToViewport : true,
10152     /**
10153      * @cfg {Array} monthNames
10154      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10155      */
10156     monthNames : Date.monthNames,
10157     /**
10158      * @cfg {Array} dayNames
10159      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10160      */
10161     dayNames : Date.dayNames,
10162     /**
10163      * @cfg {String} nextText
10164      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10165      */
10166     nextText: 'Next Month (Control+Right)',
10167     /**
10168      * @cfg {String} prevText
10169      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10170      */
10171     prevText: 'Previous Month (Control+Left)',
10172     /**
10173      * @cfg {String} monthYearText
10174      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10175      */
10176     monthYearText: 'Choose a month (Control+Up/Down to move years)',
10177     /**
10178      * @cfg {Number} startDay
10179      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10180      */
10181     startDay : 0,
10182     /**
10183      * @cfg {Bool} showClear
10184      * Show a clear button (usefull for date form elements that can be blank.)
10185      */
10186     
10187     showClear: false,
10188     
10189     /**
10190      * Sets the value of the date field
10191      * @param {Date} value The date to set
10192      */
10193     setValue : function(value){
10194         var old = this.value;
10195         this.value = value.clearTime(true);
10196         if(this.el){
10197             this.update(this.value);
10198         }
10199     },
10200
10201     /**
10202      * Gets the current selected value of the date field
10203      * @return {Date} The selected date
10204      */
10205     getValue : function(){
10206         return this.value;
10207     },
10208
10209     // private
10210     focus : function(){
10211         if(this.el){
10212             this.update(this.activeDate);
10213         }
10214     },
10215
10216     // private
10217     onRender : function(container, position){
10218         var m = [
10219              '<table cellspacing="0">',
10220                 '<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>',
10221                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10222         var dn = this.dayNames;
10223         for(var i = 0; i < 7; i++){
10224             var d = this.startDay+i;
10225             if(d > 6){
10226                 d = d-7;
10227             }
10228             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10229         }
10230         m[m.length] = "</tr></thead><tbody><tr>";
10231         for(var i = 0; i < 42; i++) {
10232             if(i % 7 == 0 && i != 0){
10233                 m[m.length] = "</tr><tr>";
10234             }
10235             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10236         }
10237         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10238             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10239
10240         var el = document.createElement("div");
10241         el.className = "x-date-picker";
10242         el.innerHTML = m.join("");
10243
10244         container.dom.insertBefore(el, position);
10245
10246         this.el = Roo.get(el);
10247         this.eventEl = Roo.get(el.firstChild);
10248
10249         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10250             handler: this.showPrevMonth,
10251             scope: this,
10252             preventDefault:true,
10253             stopDefault:true
10254         });
10255
10256         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10257             handler: this.showNextMonth,
10258             scope: this,
10259             preventDefault:true,
10260             stopDefault:true
10261         });
10262
10263         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
10264
10265         this.monthPicker = this.el.down('div.x-date-mp');
10266         this.monthPicker.enableDisplayMode('block');
10267         
10268         var kn = new Roo.KeyNav(this.eventEl, {
10269             "left" : function(e){
10270                 e.ctrlKey ?
10271                     this.showPrevMonth() :
10272                     this.update(this.activeDate.add("d", -1));
10273             },
10274
10275             "right" : function(e){
10276                 e.ctrlKey ?
10277                     this.showNextMonth() :
10278                     this.update(this.activeDate.add("d", 1));
10279             },
10280
10281             "up" : function(e){
10282                 e.ctrlKey ?
10283                     this.showNextYear() :
10284                     this.update(this.activeDate.add("d", -7));
10285             },
10286
10287             "down" : function(e){
10288                 e.ctrlKey ?
10289                     this.showPrevYear() :
10290                     this.update(this.activeDate.add("d", 7));
10291             },
10292
10293             "pageUp" : function(e){
10294                 this.showNextMonth();
10295             },
10296
10297             "pageDown" : function(e){
10298                 this.showPrevMonth();
10299             },
10300
10301             "enter" : function(e){
10302                 e.stopPropagation();
10303                 return true;
10304             },
10305
10306             scope : this
10307         });
10308
10309         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
10310
10311         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
10312
10313         this.el.unselectable();
10314         
10315         this.cells = this.el.select("table.x-date-inner tbody td");
10316         this.textNodes = this.el.query("table.x-date-inner tbody span");
10317
10318         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10319             text: "&#160;",
10320             tooltip: this.monthYearText
10321         });
10322
10323         this.mbtn.on('click', this.showMonthPicker, this);
10324         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10325
10326
10327         var today = (new Date()).dateFormat(this.format);
10328         
10329         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10330         if (this.showClear) {
10331             baseTb.add( new Roo.Toolbar.Fill());
10332         }
10333         baseTb.add({
10334             text: String.format(this.todayText, today),
10335             tooltip: String.format(this.todayTip, today),
10336             handler: this.selectToday,
10337             scope: this
10338         });
10339         
10340         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10341             
10342         //});
10343         if (this.showClear) {
10344             
10345             baseTb.add( new Roo.Toolbar.Fill());
10346             baseTb.add({
10347                 text: '&#160;',
10348                 cls: 'x-btn-icon x-btn-clear',
10349                 handler: function() {
10350                     //this.value = '';
10351                     this.fireEvent("select", this, '');
10352                 },
10353                 scope: this
10354             });
10355         }
10356         
10357         
10358         if(Roo.isIE){
10359             this.el.repaint();
10360         }
10361         this.update(this.value);
10362     },
10363
10364     createMonthPicker : function(){
10365         if(!this.monthPicker.dom.firstChild){
10366             var buf = ['<table border="0" cellspacing="0">'];
10367             for(var i = 0; i < 6; i++){
10368                 buf.push(
10369                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10370                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10371                     i == 0 ?
10372                     '<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>' :
10373                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10374                 );
10375             }
10376             buf.push(
10377                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10378                     this.okText,
10379                     '</button><button type="button" class="x-date-mp-cancel">',
10380                     this.cancelText,
10381                     '</button></td></tr>',
10382                 '</table>'
10383             );
10384             this.monthPicker.update(buf.join(''));
10385             this.monthPicker.on('click', this.onMonthClick, this);
10386             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10387
10388             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10389             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10390
10391             this.mpMonths.each(function(m, a, i){
10392                 i += 1;
10393                 if((i%2) == 0){
10394                     m.dom.xmonth = 5 + Math.round(i * .5);
10395                 }else{
10396                     m.dom.xmonth = Math.round((i-1) * .5);
10397                 }
10398             });
10399         }
10400     },
10401
10402     showMonthPicker : function(){
10403         this.createMonthPicker();
10404         var size = this.el.getSize();
10405         this.monthPicker.setSize(size);
10406         this.monthPicker.child('table').setSize(size);
10407
10408         this.mpSelMonth = (this.activeDate || this.value).getMonth();
10409         this.updateMPMonth(this.mpSelMonth);
10410         this.mpSelYear = (this.activeDate || this.value).getFullYear();
10411         this.updateMPYear(this.mpSelYear);
10412
10413         this.monthPicker.slideIn('t', {duration:.2});
10414     },
10415
10416     updateMPYear : function(y){
10417         this.mpyear = y;
10418         var ys = this.mpYears.elements;
10419         for(var i = 1; i <= 10; i++){
10420             var td = ys[i-1], y2;
10421             if((i%2) == 0){
10422                 y2 = y + Math.round(i * .5);
10423                 td.firstChild.innerHTML = y2;
10424                 td.xyear = y2;
10425             }else{
10426                 y2 = y - (5-Math.round(i * .5));
10427                 td.firstChild.innerHTML = y2;
10428                 td.xyear = y2;
10429             }
10430             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10431         }
10432     },
10433
10434     updateMPMonth : function(sm){
10435         this.mpMonths.each(function(m, a, i){
10436             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10437         });
10438     },
10439
10440     selectMPMonth: function(m){
10441         
10442     },
10443
10444     onMonthClick : function(e, t){
10445         e.stopEvent();
10446         var el = new Roo.Element(t), pn;
10447         if(el.is('button.x-date-mp-cancel')){
10448             this.hideMonthPicker();
10449         }
10450         else if(el.is('button.x-date-mp-ok')){
10451             this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10452             this.hideMonthPicker();
10453         }
10454         else if(pn = el.up('td.x-date-mp-month', 2)){
10455             this.mpMonths.removeClass('x-date-mp-sel');
10456             pn.addClass('x-date-mp-sel');
10457             this.mpSelMonth = pn.dom.xmonth;
10458         }
10459         else if(pn = el.up('td.x-date-mp-year', 2)){
10460             this.mpYears.removeClass('x-date-mp-sel');
10461             pn.addClass('x-date-mp-sel');
10462             this.mpSelYear = pn.dom.xyear;
10463         }
10464         else if(el.is('a.x-date-mp-prev')){
10465             this.updateMPYear(this.mpyear-10);
10466         }
10467         else if(el.is('a.x-date-mp-next')){
10468             this.updateMPYear(this.mpyear+10);
10469         }
10470     },
10471
10472     onMonthDblClick : function(e, t){
10473         e.stopEvent();
10474         var el = new Roo.Element(t), pn;
10475         if(pn = el.up('td.x-date-mp-month', 2)){
10476             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10477             this.hideMonthPicker();
10478         }
10479         else if(pn = el.up('td.x-date-mp-year', 2)){
10480             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10481             this.hideMonthPicker();
10482         }
10483     },
10484
10485     hideMonthPicker : function(disableAnim){
10486         if(this.monthPicker){
10487             if(disableAnim === true){
10488                 this.monthPicker.hide();
10489             }else{
10490                 this.monthPicker.slideOut('t', {duration:.2});
10491             }
10492         }
10493     },
10494
10495     // private
10496     showPrevMonth : function(e){
10497         this.update(this.activeDate.add("mo", -1));
10498     },
10499
10500     // private
10501     showNextMonth : function(e){
10502         this.update(this.activeDate.add("mo", 1));
10503     },
10504
10505     // private
10506     showPrevYear : function(){
10507         this.update(this.activeDate.add("y", -1));
10508     },
10509
10510     // private
10511     showNextYear : function(){
10512         this.update(this.activeDate.add("y", 1));
10513     },
10514
10515     // private
10516     handleMouseWheel : function(e){
10517         var delta = e.getWheelDelta();
10518         if(delta > 0){
10519             this.showPrevMonth();
10520             e.stopEvent();
10521         } else if(delta < 0){
10522             this.showNextMonth();
10523             e.stopEvent();
10524         }
10525     },
10526
10527     // private
10528     handleDateClick : function(e, t){
10529         e.stopEvent();
10530         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10531             this.setValue(new Date(t.dateValue));
10532             this.fireEvent("select", this, this.value);
10533         }
10534     },
10535
10536     // private
10537     selectToday : function(){
10538         this.setValue(new Date().clearTime());
10539         this.fireEvent("select", this, this.value);
10540     },
10541
10542     // private
10543     update : function(date){
10544         var vd = this.activeDate;
10545         this.activeDate = date;
10546         if(vd && this.el){
10547             var t = date.getTime();
10548             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10549                 this.cells.removeClass("x-date-selected");
10550                 this.cells.each(function(c){
10551                    if(c.dom.firstChild.dateValue == t){
10552                        c.addClass("x-date-selected");
10553                        setTimeout(function(){
10554                             try{c.dom.firstChild.focus();}catch(e){}
10555                        }, 50);
10556                        return false;
10557                    }
10558                 });
10559                 return;
10560             }
10561         }
10562         var days = date.getDaysInMonth();
10563         var firstOfMonth = date.getFirstDateOfMonth();
10564         var startingPos = firstOfMonth.getDay()-this.startDay;
10565
10566         if(startingPos <= this.startDay){
10567             startingPos += 7;
10568         }
10569
10570         var pm = date.add("mo", -1);
10571         var prevStart = pm.getDaysInMonth()-startingPos;
10572
10573         var cells = this.cells.elements;
10574         var textEls = this.textNodes;
10575         days += startingPos;
10576
10577         // convert everything to numbers so it's fast
10578         var day = 86400000;
10579         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10580         var today = new Date().clearTime().getTime();
10581         var sel = date.clearTime().getTime();
10582         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10583         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10584         var ddMatch = this.disabledDatesRE;
10585         var ddText = this.disabledDatesText;
10586         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10587         var ddaysText = this.disabledDaysText;
10588         var format = this.format;
10589
10590         var setCellClass = function(cal, cell){
10591             cell.title = "";
10592             var t = d.getTime();
10593             cell.firstChild.dateValue = t;
10594             if(t == today){
10595                 cell.className += " x-date-today";
10596                 cell.title = cal.todayText;
10597             }
10598             if(t == sel){
10599                 cell.className += " x-date-selected";
10600                 setTimeout(function(){
10601                     try{cell.firstChild.focus();}catch(e){}
10602                 }, 50);
10603             }
10604             // disabling
10605             if(t < min) {
10606                 cell.className = " x-date-disabled";
10607                 cell.title = cal.minText;
10608                 return;
10609             }
10610             if(t > max) {
10611                 cell.className = " x-date-disabled";
10612                 cell.title = cal.maxText;
10613                 return;
10614             }
10615             if(ddays){
10616                 if(ddays.indexOf(d.getDay()) != -1){
10617                     cell.title = ddaysText;
10618                     cell.className = " x-date-disabled";
10619                 }
10620             }
10621             if(ddMatch && format){
10622                 var fvalue = d.dateFormat(format);
10623                 if(ddMatch.test(fvalue)){
10624                     cell.title = ddText.replace("%0", fvalue);
10625                     cell.className = " x-date-disabled";
10626                 }
10627             }
10628         };
10629
10630         var i = 0;
10631         for(; i < startingPos; i++) {
10632             textEls[i].innerHTML = (++prevStart);
10633             d.setDate(d.getDate()+1);
10634             cells[i].className = "x-date-prevday";
10635             setCellClass(this, cells[i]);
10636         }
10637         for(; i < days; i++){
10638             intDay = i - startingPos + 1;
10639             textEls[i].innerHTML = (intDay);
10640             d.setDate(d.getDate()+1);
10641             cells[i].className = "x-date-active";
10642             setCellClass(this, cells[i]);
10643         }
10644         var extraDays = 0;
10645         for(; i < 42; i++) {
10646              textEls[i].innerHTML = (++extraDays);
10647              d.setDate(d.getDate()+1);
10648              cells[i].className = "x-date-nextday";
10649              setCellClass(this, cells[i]);
10650         }
10651
10652         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10653
10654         if(!this.internalRender){
10655             var main = this.el.dom.firstChild;
10656             var w = main.offsetWidth;
10657             this.el.setWidth(w + this.el.getBorderWidth("lr"));
10658             Roo.fly(main).setWidth(w);
10659             this.internalRender = true;
10660             // opera does not respect the auto grow header center column
10661             // then, after it gets a width opera refuses to recalculate
10662             // without a second pass
10663             if(Roo.isOpera && !this.secondPass){
10664                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10665                 this.secondPass = true;
10666                 this.update.defer(10, this, [date]);
10667             }
10668         }
10669     }
10670 });/*
10671  * Based on:
10672  * Ext JS Library 1.1.1
10673  * Copyright(c) 2006-2007, Ext JS, LLC.
10674  *
10675  * Originally Released Under LGPL - original licence link has changed is not relivant.
10676  *
10677  * Fork - LGPL
10678  * <script type="text/javascript">
10679  */
10680 /**
10681  * @class Roo.TabPanel
10682  * @extends Roo.util.Observable
10683  * A lightweight tab container.
10684  * <br><br>
10685  * Usage:
10686  * <pre><code>
10687 // basic tabs 1, built from existing content
10688 var tabs = new Roo.TabPanel("tabs1");
10689 tabs.addTab("script", "View Script");
10690 tabs.addTab("markup", "View Markup");
10691 tabs.activate("script");
10692
10693 // more advanced tabs, built from javascript
10694 var jtabs = new Roo.TabPanel("jtabs");
10695 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10696
10697 // set up the UpdateManager
10698 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10699 var updater = tab2.getUpdateManager();
10700 updater.setDefaultUrl("ajax1.htm");
10701 tab2.on('activate', updater.refresh, updater, true);
10702
10703 // Use setUrl for Ajax loading
10704 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10705 tab3.setUrl("ajax2.htm", null, true);
10706
10707 // Disabled tab
10708 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10709 tab4.disable();
10710
10711 jtabs.activate("jtabs-1");
10712  * </code></pre>
10713  * @constructor
10714  * Create a new TabPanel.
10715  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10716  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10717  */
10718 Roo.TabPanel = function(container, config){
10719     /**
10720     * The container element for this TabPanel.
10721     * @type Roo.Element
10722     */
10723     this.el = Roo.get(container, true);
10724     if(config){
10725         if(typeof config == "boolean"){
10726             this.tabPosition = config ? "bottom" : "top";
10727         }else{
10728             Roo.apply(this, config);
10729         }
10730     }
10731     if(this.tabPosition == "bottom"){
10732         this.bodyEl = Roo.get(this.createBody(this.el.dom));
10733         this.el.addClass("x-tabs-bottom");
10734     }
10735     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10736     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10737     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10738     if(Roo.isIE){
10739         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10740     }
10741     if(this.tabPosition != "bottom"){
10742     /** The body element that contains {@link Roo.TabPanelItem} bodies.
10743      * @type Roo.Element
10744      */
10745       this.bodyEl = Roo.get(this.createBody(this.el.dom));
10746       this.el.addClass("x-tabs-top");
10747     }
10748     this.items = [];
10749
10750     this.bodyEl.setStyle("position", "relative");
10751
10752     this.active = null;
10753     this.activateDelegate = this.activate.createDelegate(this);
10754
10755     this.addEvents({
10756         /**
10757          * @event tabchange
10758          * Fires when the active tab changes
10759          * @param {Roo.TabPanel} this
10760          * @param {Roo.TabPanelItem} activePanel The new active tab
10761          */
10762         "tabchange": true,
10763         /**
10764          * @event beforetabchange
10765          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10766          * @param {Roo.TabPanel} this
10767          * @param {Object} e Set cancel to true on this object to cancel the tab change
10768          * @param {Roo.TabPanelItem} tab The tab being changed to
10769          */
10770         "beforetabchange" : true
10771     });
10772
10773     Roo.EventManager.onWindowResize(this.onResize, this);
10774     this.cpad = this.el.getPadding("lr");
10775     this.hiddenCount = 0;
10776
10777     Roo.TabPanel.superclass.constructor.call(this);
10778 };
10779
10780 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10781         /*
10782          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10783          */
10784     tabPosition : "top",
10785         /*
10786          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10787          */
10788     currentTabWidth : 0,
10789         /*
10790          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10791          */
10792     minTabWidth : 40,
10793         /*
10794          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10795          */
10796     maxTabWidth : 250,
10797         /*
10798          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10799          */
10800     preferredTabWidth : 175,
10801         /*
10802          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10803          */
10804     resizeTabs : false,
10805         /*
10806          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10807          */
10808     monitorResize : true,
10809
10810     /**
10811      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10812      * @param {String} id The id of the div to use <b>or create</b>
10813      * @param {String} text The text for the tab
10814      * @param {String} content (optional) Content to put in the TabPanelItem body
10815      * @param {Boolean} closable (optional) True to create a close icon on the tab
10816      * @return {Roo.TabPanelItem} The created TabPanelItem
10817      */
10818     addTab : function(id, text, content, closable){
10819         var item = new Roo.TabPanelItem(this, id, text, closable);
10820         this.addTabItem(item);
10821         if(content){
10822             item.setContent(content);
10823         }
10824         return item;
10825     },
10826
10827     /**
10828      * Returns the {@link Roo.TabPanelItem} with the specified id/index
10829      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10830      * @return {Roo.TabPanelItem}
10831      */
10832     getTab : function(id){
10833         return this.items[id];
10834     },
10835
10836     /**
10837      * Hides the {@link Roo.TabPanelItem} with the specified id/index
10838      * @param {String/Number} id The id or index of the TabPanelItem to hide.
10839      */
10840     hideTab : function(id){
10841         var t = this.items[id];
10842         if(!t.isHidden()){
10843            t.setHidden(true);
10844            this.hiddenCount++;
10845            this.autoSizeTabs();
10846         }
10847     },
10848
10849     /**
10850      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10851      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10852      */
10853     unhideTab : function(id){
10854         var t = this.items[id];
10855         if(t.isHidden()){
10856            t.setHidden(false);
10857            this.hiddenCount--;
10858            this.autoSizeTabs();
10859         }
10860     },
10861
10862     /**
10863      * Adds an existing {@link Roo.TabPanelItem}.
10864      * @param {Roo.TabPanelItem} item The TabPanelItem to add
10865      */
10866     addTabItem : function(item){
10867         this.items[item.id] = item;
10868         this.items.push(item);
10869         if(this.resizeTabs){
10870            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10871            this.autoSizeTabs();
10872         }else{
10873             item.autoSize();
10874         }
10875     },
10876
10877     /**
10878      * Removes a {@link Roo.TabPanelItem}.
10879      * @param {String/Number} id The id or index of the TabPanelItem to remove.
10880      */
10881     removeTab : function(id){
10882         var items = this.items;
10883         var tab = items[id];
10884         if(!tab) { return; }
10885         var index = items.indexOf(tab);
10886         if(this.active == tab && items.length > 1){
10887             var newTab = this.getNextAvailable(index);
10888             if(newTab) {
10889                 newTab.activate();
10890             }
10891         }
10892         this.stripEl.dom.removeChild(tab.pnode.dom);
10893         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10894             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10895         }
10896         items.splice(index, 1);
10897         delete this.items[tab.id];
10898         tab.fireEvent("close", tab);
10899         tab.purgeListeners();
10900         this.autoSizeTabs();
10901     },
10902
10903     getNextAvailable : function(start){
10904         var items = this.items;
10905         var index = start;
10906         // look for a next tab that will slide over to
10907         // replace the one being removed
10908         while(index < items.length){
10909             var item = items[++index];
10910             if(item && !item.isHidden()){
10911                 return item;
10912             }
10913         }
10914         // if one isn't found select the previous tab (on the left)
10915         index = start;
10916         while(index >= 0){
10917             var item = items[--index];
10918             if(item && !item.isHidden()){
10919                 return item;
10920             }
10921         }
10922         return null;
10923     },
10924
10925     /**
10926      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10927      * @param {String/Number} id The id or index of the TabPanelItem to disable.
10928      */
10929     disableTab : function(id){
10930         var tab = this.items[id];
10931         if(tab && this.active != tab){
10932             tab.disable();
10933         }
10934     },
10935
10936     /**
10937      * Enables a {@link Roo.TabPanelItem} that is disabled.
10938      * @param {String/Number} id The id or index of the TabPanelItem to enable.
10939      */
10940     enableTab : function(id){
10941         var tab = this.items[id];
10942         tab.enable();
10943     },
10944
10945     /**
10946      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10947      * @param {String/Number} id The id or index of the TabPanelItem to activate.
10948      * @return {Roo.TabPanelItem} The TabPanelItem.
10949      */
10950     activate : function(id){
10951         var tab = this.items[id];
10952         if(!tab){
10953             return null;
10954         }
10955         if(tab == this.active || tab.disabled){
10956             return tab;
10957         }
10958         var e = {};
10959         this.fireEvent("beforetabchange", this, e, tab);
10960         if(e.cancel !== true && !tab.disabled){
10961             if(this.active){
10962                 this.active.hide();
10963             }
10964             this.active = this.items[id];
10965             this.active.show();
10966             this.fireEvent("tabchange", this, this.active);
10967         }
10968         return tab;
10969     },
10970
10971     /**
10972      * Gets the active {@link Roo.TabPanelItem}.
10973      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10974      */
10975     getActiveTab : function(){
10976         return this.active;
10977     },
10978
10979     /**
10980      * Updates the tab body element to fit the height of the container element
10981      * for overflow scrolling
10982      * @param {Number} targetHeight (optional) Override the starting height from the elements height
10983      */
10984     syncHeight : function(targetHeight){
10985         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10986         var bm = this.bodyEl.getMargins();
10987         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10988         this.bodyEl.setHeight(newHeight);
10989         return newHeight;
10990     },
10991
10992     onResize : function(){
10993         if(this.monitorResize){
10994             this.autoSizeTabs();
10995         }
10996     },
10997
10998     /**
10999      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11000      */
11001     beginUpdate : function(){
11002         this.updating = true;
11003     },
11004
11005     /**
11006      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11007      */
11008     endUpdate : function(){
11009         this.updating = false;
11010         this.autoSizeTabs();
11011     },
11012
11013     /**
11014      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11015      */
11016     autoSizeTabs : function(){
11017         var count = this.items.length;
11018         var vcount = count - this.hiddenCount;
11019         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11020         var w = Math.max(this.el.getWidth() - this.cpad, 10);
11021         var availWidth = Math.floor(w / vcount);
11022         var b = this.stripBody;
11023         if(b.getWidth() > w){
11024             var tabs = this.items;
11025             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11026             if(availWidth < this.minTabWidth){
11027                 /*if(!this.sleft){    // incomplete scrolling code
11028                     this.createScrollButtons();
11029                 }
11030                 this.showScroll();
11031                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11032             }
11033         }else{
11034             if(this.currentTabWidth < this.preferredTabWidth){
11035                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11036             }
11037         }
11038     },
11039
11040     /**
11041      * Returns the number of tabs in this TabPanel.
11042      * @return {Number}
11043      */
11044      getCount : function(){
11045          return this.items.length;
11046      },
11047
11048     /**
11049      * Resizes all the tabs to the passed width
11050      * @param {Number} The new width
11051      */
11052     setTabWidth : function(width){
11053         this.currentTabWidth = width;
11054         for(var i = 0, len = this.items.length; i < len; i++) {
11055                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11056         }
11057     },
11058
11059     /**
11060      * Destroys this TabPanel
11061      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11062      */
11063     destroy : function(removeEl){
11064         Roo.EventManager.removeResizeListener(this.onResize, this);
11065         for(var i = 0, len = this.items.length; i < len; i++){
11066             this.items[i].purgeListeners();
11067         }
11068         if(removeEl === true){
11069             this.el.update("");
11070             this.el.remove();
11071         }
11072     }
11073 });
11074
11075 /**
11076  * @class Roo.TabPanelItem
11077  * @extends Roo.util.Observable
11078  * Represents an individual item (tab plus body) in a TabPanel.
11079  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11080  * @param {String} id The id of this TabPanelItem
11081  * @param {String} text The text for the tab of this TabPanelItem
11082  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11083  */
11084 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11085     /**
11086      * The {@link Roo.TabPanel} this TabPanelItem belongs to
11087      * @type Roo.TabPanel
11088      */
11089     this.tabPanel = tabPanel;
11090     /**
11091      * The id for this TabPanelItem
11092      * @type String
11093      */
11094     this.id = id;
11095     /** @private */
11096     this.disabled = false;
11097     /** @private */
11098     this.text = text;
11099     /** @private */
11100     this.loaded = false;
11101     this.closable = closable;
11102
11103     /**
11104      * The body element for this TabPanelItem.
11105      * @type Roo.Element
11106      */
11107     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11108     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11109     this.bodyEl.setStyle("display", "block");
11110     this.bodyEl.setStyle("zoom", "1");
11111     this.hideAction();
11112
11113     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11114     /** @private */
11115     this.el = Roo.get(els.el, true);
11116     this.inner = Roo.get(els.inner, true);
11117     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11118     this.pnode = Roo.get(els.el.parentNode, true);
11119     this.el.on("mousedown", this.onTabMouseDown, this);
11120     this.el.on("click", this.onTabClick, this);
11121     /** @private */
11122     if(closable){
11123         var c = Roo.get(els.close, true);
11124         c.dom.title = this.closeText;
11125         c.addClassOnOver("close-over");
11126         c.on("click", this.closeClick, this);
11127      }
11128
11129     this.addEvents({
11130          /**
11131          * @event activate
11132          * Fires when this tab becomes the active tab.
11133          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11134          * @param {Roo.TabPanelItem} this
11135          */
11136         "activate": true,
11137         /**
11138          * @event beforeclose
11139          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11140          * @param {Roo.TabPanelItem} this
11141          * @param {Object} e Set cancel to true on this object to cancel the close.
11142          */
11143         "beforeclose": true,
11144         /**
11145          * @event close
11146          * Fires when this tab is closed.
11147          * @param {Roo.TabPanelItem} this
11148          */
11149          "close": true,
11150         /**
11151          * @event deactivate
11152          * Fires when this tab is no longer the active tab.
11153          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11154          * @param {Roo.TabPanelItem} this
11155          */
11156          "deactivate" : true
11157     });
11158     this.hidden = false;
11159
11160     Roo.TabPanelItem.superclass.constructor.call(this);
11161 };
11162
11163 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11164     purgeListeners : function(){
11165        Roo.util.Observable.prototype.purgeListeners.call(this);
11166        this.el.removeAllListeners();
11167     },
11168     /**
11169      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11170      */
11171     show : function(){
11172         this.pnode.addClass("on");
11173         this.showAction();
11174         if(Roo.isOpera){
11175             this.tabPanel.stripWrap.repaint();
11176         }
11177         this.fireEvent("activate", this.tabPanel, this);
11178     },
11179
11180     /**
11181      * Returns true if this tab is the active tab.
11182      * @return {Boolean}
11183      */
11184     isActive : function(){
11185         return this.tabPanel.getActiveTab() == this;
11186     },
11187
11188     /**
11189      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11190      */
11191     hide : function(){
11192         this.pnode.removeClass("on");
11193         this.hideAction();
11194         this.fireEvent("deactivate", this.tabPanel, this);
11195     },
11196
11197     hideAction : function(){
11198         this.bodyEl.hide();
11199         this.bodyEl.setStyle("position", "absolute");
11200         this.bodyEl.setLeft("-20000px");
11201         this.bodyEl.setTop("-20000px");
11202     },
11203
11204     showAction : function(){
11205         this.bodyEl.setStyle("position", "relative");
11206         this.bodyEl.setTop("");
11207         this.bodyEl.setLeft("");
11208         this.bodyEl.show();
11209     },
11210
11211     /**
11212      * Set the tooltip for the tab.
11213      * @param {String} tooltip The tab's tooltip
11214      */
11215     setTooltip : function(text){
11216         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11217             this.textEl.dom.qtip = text;
11218             this.textEl.dom.removeAttribute('title');
11219         }else{
11220             this.textEl.dom.title = text;
11221         }
11222     },
11223
11224     onTabClick : function(e){
11225         e.preventDefault();
11226         this.tabPanel.activate(this.id);
11227     },
11228
11229     onTabMouseDown : function(e){
11230         e.preventDefault();
11231         this.tabPanel.activate(this.id);
11232     },
11233
11234     getWidth : function(){
11235         return this.inner.getWidth();
11236     },
11237
11238     setWidth : function(width){
11239         var iwidth = width - this.pnode.getPadding("lr");
11240         this.inner.setWidth(iwidth);
11241         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11242         this.pnode.setWidth(width);
11243     },
11244
11245     /**
11246      * Show or hide the tab
11247      * @param {Boolean} hidden True to hide or false to show.
11248      */
11249     setHidden : function(hidden){
11250         this.hidden = hidden;
11251         this.pnode.setStyle("display", hidden ? "none" : "");
11252     },
11253
11254     /**
11255      * Returns true if this tab is "hidden"
11256      * @return {Boolean}
11257      */
11258     isHidden : function(){
11259         return this.hidden;
11260     },
11261
11262     /**
11263      * Returns the text for this tab
11264      * @return {String}
11265      */
11266     getText : function(){
11267         return this.text;
11268     },
11269
11270     autoSize : function(){
11271         //this.el.beginMeasure();
11272         this.textEl.setWidth(1);
11273         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11274         //this.el.endMeasure();
11275     },
11276
11277     /**
11278      * Sets the text for the tab (Note: this also sets the tooltip text)
11279      * @param {String} text The tab's text and tooltip
11280      */
11281     setText : function(text){
11282         this.text = text;
11283         this.textEl.update(text);
11284         this.setTooltip(text);
11285         if(!this.tabPanel.resizeTabs){
11286             this.autoSize();
11287         }
11288     },
11289     /**
11290      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11291      */
11292     activate : function(){
11293         this.tabPanel.activate(this.id);
11294     },
11295
11296     /**
11297      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11298      */
11299     disable : function(){
11300         if(this.tabPanel.active != this){
11301             this.disabled = true;
11302             this.pnode.addClass("disabled");
11303         }
11304     },
11305
11306     /**
11307      * Enables this TabPanelItem if it was previously disabled.
11308      */
11309     enable : function(){
11310         this.disabled = false;
11311         this.pnode.removeClass("disabled");
11312     },
11313
11314     /**
11315      * Sets the content for this TabPanelItem.
11316      * @param {String} content The content
11317      * @param {Boolean} loadScripts true to look for and load scripts
11318      */
11319     setContent : function(content, loadScripts){
11320         this.bodyEl.update(content, loadScripts);
11321     },
11322
11323     /**
11324      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11325      * @return {Roo.UpdateManager} The UpdateManager
11326      */
11327     getUpdateManager : function(){
11328         return this.bodyEl.getUpdateManager();
11329     },
11330
11331     /**
11332      * Set a URL to be used to load the content for this TabPanelItem.
11333      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11334      * @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)
11335      * @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)
11336      * @return {Roo.UpdateManager} The UpdateManager
11337      */
11338     setUrl : function(url, params, loadOnce){
11339         if(this.refreshDelegate){
11340             this.un('activate', this.refreshDelegate);
11341         }
11342         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11343         this.on("activate", this.refreshDelegate);
11344         return this.bodyEl.getUpdateManager();
11345     },
11346
11347     /** @private */
11348     _handleRefresh : function(url, params, loadOnce){
11349         if(!loadOnce || !this.loaded){
11350             var updater = this.bodyEl.getUpdateManager();
11351             updater.update(url, params, this._setLoaded.createDelegate(this));
11352         }
11353     },
11354
11355     /**
11356      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
11357      *   Will fail silently if the setUrl method has not been called.
11358      *   This does not activate the panel, just updates its content.
11359      */
11360     refresh : function(){
11361         if(this.refreshDelegate){
11362            this.loaded = false;
11363            this.refreshDelegate();
11364         }
11365     },
11366
11367     /** @private */
11368     _setLoaded : function(){
11369         this.loaded = true;
11370     },
11371
11372     /** @private */
11373     closeClick : function(e){
11374         var o = {};
11375         e.stopEvent();
11376         this.fireEvent("beforeclose", this, o);
11377         if(o.cancel !== true){
11378             this.tabPanel.removeTab(this.id);
11379         }
11380     },
11381     /**
11382      * The text displayed in the tooltip for the close icon.
11383      * @type String
11384      */
11385     closeText : "Close this tab"
11386 });
11387
11388 /** @private */
11389 Roo.TabPanel.prototype.createStrip = function(container){
11390     var strip = document.createElement("div");
11391     strip.className = "x-tabs-wrap";
11392     container.appendChild(strip);
11393     return strip;
11394 };
11395 /** @private */
11396 Roo.TabPanel.prototype.createStripList = function(strip){
11397     // div wrapper for retard IE
11398     strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11399     return strip.firstChild.firstChild.firstChild.firstChild;
11400 };
11401 /** @private */
11402 Roo.TabPanel.prototype.createBody = function(container){
11403     var body = document.createElement("div");
11404     Roo.id(body, "tab-body");
11405     Roo.fly(body).addClass("x-tabs-body");
11406     container.appendChild(body);
11407     return body;
11408 };
11409 /** @private */
11410 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11411     var body = Roo.getDom(id);
11412     if(!body){
11413         body = document.createElement("div");
11414         body.id = id;
11415     }
11416     Roo.fly(body).addClass("x-tabs-item-body");
11417     bodyEl.insertBefore(body, bodyEl.firstChild);
11418     return body;
11419 };
11420 /** @private */
11421 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11422     var td = document.createElement("td");
11423     stripEl.appendChild(td);
11424     if(closable){
11425         td.className = "x-tabs-closable";
11426         if(!this.closeTpl){
11427             this.closeTpl = new Roo.Template(
11428                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11429                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11430                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
11431             );
11432         }
11433         var el = this.closeTpl.overwrite(td, {"text": text});
11434         var close = el.getElementsByTagName("div")[0];
11435         var inner = el.getElementsByTagName("em")[0];
11436         return {"el": el, "close": close, "inner": inner};
11437     } else {
11438         if(!this.tabTpl){
11439             this.tabTpl = new Roo.Template(
11440                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11441                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11442             );
11443         }
11444         var el = this.tabTpl.overwrite(td, {"text": text});
11445         var inner = el.getElementsByTagName("em")[0];
11446         return {"el": el, "inner": inner};
11447     }
11448 };/*
11449  * Based on:
11450  * Ext JS Library 1.1.1
11451  * Copyright(c) 2006-2007, Ext JS, LLC.
11452  *
11453  * Originally Released Under LGPL - original licence link has changed is not relivant.
11454  *
11455  * Fork - LGPL
11456  * <script type="text/javascript">
11457  */
11458
11459 /**
11460  * @class Roo.Button
11461  * @extends Roo.util.Observable
11462  * Simple Button class
11463  * @cfg {String} text The button text
11464  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11465  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11466  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11467  * @cfg {Object} scope The scope of the handler
11468  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11469  * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11470  * @cfg {Boolean} hidden True to start hidden (defaults to false)
11471  * @cfg {Boolean} disabled True to start disabled (defaults to false)
11472  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11473  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11474    applies if enableToggle = true)
11475  * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11476  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11477   an {@link Roo.util.ClickRepeater} config object (defaults to false).
11478  * @constructor
11479  * Create a new button
11480  * @param {Object} config The config object
11481  */
11482 Roo.Button = function(renderTo, config)
11483 {
11484     if (!config) {
11485         config = renderTo;
11486         renderTo = config.renderTo || false;
11487     }
11488     
11489     Roo.apply(this, config);
11490     this.addEvents({
11491         /**
11492              * @event click
11493              * Fires when this button is clicked
11494              * @param {Button} this
11495              * @param {EventObject} e The click event
11496              */
11497             "click" : true,
11498         /**
11499              * @event toggle
11500              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11501              * @param {Button} this
11502              * @param {Boolean} pressed
11503              */
11504             "toggle" : true,
11505         /**
11506              * @event mouseover
11507              * Fires when the mouse hovers over the button
11508              * @param {Button} this
11509              * @param {Event} e The event object
11510              */
11511         'mouseover' : true,
11512         /**
11513              * @event mouseout
11514              * Fires when the mouse exits the button
11515              * @param {Button} this
11516              * @param {Event} e The event object
11517              */
11518         'mouseout': true,
11519          /**
11520              * @event render
11521              * Fires when the button is rendered
11522              * @param {Button} this
11523              */
11524         'render': true
11525     });
11526     if(this.menu){
11527         this.menu = Roo.menu.MenuMgr.get(this.menu);
11528     }
11529     // register listeners first!!  - so render can be captured..
11530     Roo.util.Observable.call(this);
11531     if(renderTo){
11532         this.render(renderTo);
11533     }
11534     
11535   
11536 };
11537
11538 Roo.extend(Roo.Button, Roo.util.Observable, {
11539     /**
11540      * 
11541      */
11542     
11543     /**
11544      * Read-only. True if this button is hidden
11545      * @type Boolean
11546      */
11547     hidden : false,
11548     /**
11549      * Read-only. True if this button is disabled
11550      * @type Boolean
11551      */
11552     disabled : false,
11553     /**
11554      * Read-only. True if this button is pressed (only if enableToggle = true)
11555      * @type Boolean
11556      */
11557     pressed : false,
11558
11559     /**
11560      * @cfg {Number} tabIndex 
11561      * The DOM tabIndex for this button (defaults to undefined)
11562      */
11563     tabIndex : undefined,
11564
11565     /**
11566      * @cfg {Boolean} enableToggle
11567      * True to enable pressed/not pressed toggling (defaults to false)
11568      */
11569     enableToggle: false,
11570     /**
11571      * @cfg {Mixed} menu
11572      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11573      */
11574     menu : undefined,
11575     /**
11576      * @cfg {String} menuAlign
11577      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11578      */
11579     menuAlign : "tl-bl?",
11580
11581     /**
11582      * @cfg {String} iconCls
11583      * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11584      */
11585     iconCls : undefined,
11586     /**
11587      * @cfg {String} type
11588      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
11589      */
11590     type : 'button',
11591
11592     // private
11593     menuClassTarget: 'tr',
11594
11595     /**
11596      * @cfg {String} clickEvent
11597      * The type of event to map to the button's event handler (defaults to 'click')
11598      */
11599     clickEvent : 'click',
11600
11601     /**
11602      * @cfg {Boolean} handleMouseEvents
11603      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11604      */
11605     handleMouseEvents : true,
11606
11607     /**
11608      * @cfg {String} tooltipType
11609      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11610      */
11611     tooltipType : 'qtip',
11612
11613     /**
11614      * @cfg {String} cls
11615      * A CSS class to apply to the button's main element.
11616      */
11617     
11618     /**
11619      * @cfg {Roo.Template} template (Optional)
11620      * An {@link Roo.Template} with which to create the Button's main element. This Template must
11621      * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11622      * require code modifications if required elements (e.g. a button) aren't present.
11623      */
11624
11625     // private
11626     render : function(renderTo){
11627         var btn;
11628         if(this.hideParent){
11629             this.parentEl = Roo.get(renderTo);
11630         }
11631         if(!this.dhconfig){
11632             if(!this.template){
11633                 if(!Roo.Button.buttonTemplate){
11634                     // hideous table template
11635                     Roo.Button.buttonTemplate = new Roo.Template(
11636                         '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11637                         '<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>',
11638                         "</tr></tbody></table>");
11639                 }
11640                 this.template = Roo.Button.buttonTemplate;
11641             }
11642             btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
11643             var btnEl = btn.child("button:first");
11644             btnEl.on('focus', this.onFocus, this);
11645             btnEl.on('blur', this.onBlur, this);
11646             if(this.cls){
11647                 btn.addClass(this.cls);
11648             }
11649             if(this.icon){
11650                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11651             }
11652             if(this.iconCls){
11653                 btnEl.addClass(this.iconCls);
11654                 if(!this.cls){
11655                     btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11656                 }
11657             }
11658             if(this.tabIndex !== undefined){
11659                 btnEl.dom.tabIndex = this.tabIndex;
11660             }
11661             if(this.tooltip){
11662                 if(typeof this.tooltip == 'object'){
11663                     Roo.QuickTips.tips(Roo.apply({
11664                           target: btnEl.id
11665                     }, this.tooltip));
11666                 } else {
11667                     btnEl.dom[this.tooltipType] = this.tooltip;
11668                 }
11669             }
11670         }else{
11671             btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11672         }
11673         this.el = btn;
11674         if(this.id){
11675             this.el.dom.id = this.el.id = this.id;
11676         }
11677         if(this.menu){
11678             this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11679             this.menu.on("show", this.onMenuShow, this);
11680             this.menu.on("hide", this.onMenuHide, this);
11681         }
11682         btn.addClass("x-btn");
11683         if(Roo.isIE && !Roo.isIE7){
11684             this.autoWidth.defer(1, this);
11685         }else{
11686             this.autoWidth();
11687         }
11688         if(this.handleMouseEvents){
11689             btn.on("mouseover", this.onMouseOver, this);
11690             btn.on("mouseout", this.onMouseOut, this);
11691             btn.on("mousedown", this.onMouseDown, this);
11692         }
11693         btn.on(this.clickEvent, this.onClick, this);
11694         //btn.on("mouseup", this.onMouseUp, this);
11695         if(this.hidden){
11696             this.hide();
11697         }
11698         if(this.disabled){
11699             this.disable();
11700         }
11701         Roo.ButtonToggleMgr.register(this);
11702         if(this.pressed){
11703             this.el.addClass("x-btn-pressed");
11704         }
11705         if(this.repeat){
11706             var repeater = new Roo.util.ClickRepeater(btn,
11707                 typeof this.repeat == "object" ? this.repeat : {}
11708             );
11709             repeater.on("click", this.onClick,  this);
11710         }
11711         
11712         this.fireEvent('render', this);
11713         
11714     },
11715     /**
11716      * Returns the button's underlying element
11717      * @return {Roo.Element} The element
11718      */
11719     getEl : function(){
11720         return this.el;  
11721     },
11722     
11723     /**
11724      * Destroys this Button and removes any listeners.
11725      */
11726     destroy : function(){
11727         Roo.ButtonToggleMgr.unregister(this);
11728         this.el.removeAllListeners();
11729         this.purgeListeners();
11730         this.el.remove();
11731     },
11732
11733     // private
11734     autoWidth : function(){
11735         if(this.el){
11736             this.el.setWidth("auto");
11737             if(Roo.isIE7 && Roo.isStrict){
11738                 var ib = this.el.child('button');
11739                 if(ib && ib.getWidth() > 20){
11740                     ib.clip();
11741                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11742                 }
11743             }
11744             if(this.minWidth){
11745                 if(this.hidden){
11746                     this.el.beginMeasure();
11747                 }
11748                 if(this.el.getWidth() < this.minWidth){
11749                     this.el.setWidth(this.minWidth);
11750                 }
11751                 if(this.hidden){
11752                     this.el.endMeasure();
11753                 }
11754             }
11755         }
11756     },
11757
11758     /**
11759      * Assigns this button's click handler
11760      * @param {Function} handler The function to call when the button is clicked
11761      * @param {Object} scope (optional) Scope for the function passed in
11762      */
11763     setHandler : function(handler, scope){
11764         this.handler = handler;
11765         this.scope = scope;  
11766     },
11767     
11768     /**
11769      * Sets this button's text
11770      * @param {String} text The button text
11771      */
11772     setText : function(text){
11773         this.text = text;
11774         if(this.el){
11775             this.el.child("td.x-btn-center button.x-btn-text").update(text);
11776         }
11777         this.autoWidth();
11778     },
11779     
11780     /**
11781      * Gets the text for this button
11782      * @return {String} The button text
11783      */
11784     getText : function(){
11785         return this.text;  
11786     },
11787     
11788     /**
11789      * Show this button
11790      */
11791     show: function(){
11792         this.hidden = false;
11793         if(this.el){
11794             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11795         }
11796     },
11797     
11798     /**
11799      * Hide this button
11800      */
11801     hide: function(){
11802         this.hidden = true;
11803         if(this.el){
11804             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11805         }
11806     },
11807     
11808     /**
11809      * Convenience function for boolean show/hide
11810      * @param {Boolean} visible True to show, false to hide
11811      */
11812     setVisible: function(visible){
11813         if(visible) {
11814             this.show();
11815         }else{
11816             this.hide();
11817         }
11818     },
11819     
11820     /**
11821      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11822      * @param {Boolean} state (optional) Force a particular state
11823      */
11824     toggle : function(state){
11825         state = state === undefined ? !this.pressed : state;
11826         if(state != this.pressed){
11827             if(state){
11828                 this.el.addClass("x-btn-pressed");
11829                 this.pressed = true;
11830                 this.fireEvent("toggle", this, true);
11831             }else{
11832                 this.el.removeClass("x-btn-pressed");
11833                 this.pressed = false;
11834                 this.fireEvent("toggle", this, false);
11835             }
11836             if(this.toggleHandler){
11837                 this.toggleHandler.call(this.scope || this, this, state);
11838             }
11839         }
11840     },
11841     
11842     /**
11843      * Focus the button
11844      */
11845     focus : function(){
11846         this.el.child('button:first').focus();
11847     },
11848     
11849     /**
11850      * Disable this button
11851      */
11852     disable : function(){
11853         if(this.el){
11854             this.el.addClass("x-btn-disabled");
11855         }
11856         this.disabled = true;
11857     },
11858     
11859     /**
11860      * Enable this button
11861      */
11862     enable : function(){
11863         if(this.el){
11864             this.el.removeClass("x-btn-disabled");
11865         }
11866         this.disabled = false;
11867     },
11868
11869     /**
11870      * Convenience function for boolean enable/disable
11871      * @param {Boolean} enabled True to enable, false to disable
11872      */
11873     setDisabled : function(v){
11874         this[v !== true ? "enable" : "disable"]();
11875     },
11876
11877     // private
11878     onClick : function(e){
11879         if(e){
11880             e.preventDefault();
11881         }
11882         if(e.button != 0){
11883             return;
11884         }
11885         if(!this.disabled){
11886             if(this.enableToggle){
11887                 this.toggle();
11888             }
11889             if(this.menu && !this.menu.isVisible()){
11890                 this.menu.show(this.el, this.menuAlign);
11891             }
11892             this.fireEvent("click", this, e);
11893             if(this.handler){
11894                 this.el.removeClass("x-btn-over");
11895                 this.handler.call(this.scope || this, this, e);
11896             }
11897         }
11898     },
11899     // private
11900     onMouseOver : function(e){
11901         if(!this.disabled){
11902             this.el.addClass("x-btn-over");
11903             this.fireEvent('mouseover', this, e);
11904         }
11905     },
11906     // private
11907     onMouseOut : function(e){
11908         if(!e.within(this.el,  true)){
11909             this.el.removeClass("x-btn-over");
11910             this.fireEvent('mouseout', this, e);
11911         }
11912     },
11913     // private
11914     onFocus : function(e){
11915         if(!this.disabled){
11916             this.el.addClass("x-btn-focus");
11917         }
11918     },
11919     // private
11920     onBlur : function(e){
11921         this.el.removeClass("x-btn-focus");
11922     },
11923     // private
11924     onMouseDown : function(e){
11925         if(!this.disabled && e.button == 0){
11926             this.el.addClass("x-btn-click");
11927             Roo.get(document).on('mouseup', this.onMouseUp, this);
11928         }
11929     },
11930     // private
11931     onMouseUp : function(e){
11932         if(e.button == 0){
11933             this.el.removeClass("x-btn-click");
11934             Roo.get(document).un('mouseup', this.onMouseUp, this);
11935         }
11936     },
11937     // private
11938     onMenuShow : function(e){
11939         this.el.addClass("x-btn-menu-active");
11940     },
11941     // private
11942     onMenuHide : function(e){
11943         this.el.removeClass("x-btn-menu-active");
11944     }   
11945 });
11946
11947 // Private utility class used by Button
11948 Roo.ButtonToggleMgr = function(){
11949    var groups = {};
11950    
11951    function toggleGroup(btn, state){
11952        if(state){
11953            var g = groups[btn.toggleGroup];
11954            for(var i = 0, l = g.length; i < l; i++){
11955                if(g[i] != btn){
11956                    g[i].toggle(false);
11957                }
11958            }
11959        }
11960    }
11961    
11962    return {
11963        register : function(btn){
11964            if(!btn.toggleGroup){
11965                return;
11966            }
11967            var g = groups[btn.toggleGroup];
11968            if(!g){
11969                g = groups[btn.toggleGroup] = [];
11970            }
11971            g.push(btn);
11972            btn.on("toggle", toggleGroup);
11973        },
11974        
11975        unregister : function(btn){
11976            if(!btn.toggleGroup){
11977                return;
11978            }
11979            var g = groups[btn.toggleGroup];
11980            if(g){
11981                g.remove(btn);
11982                btn.un("toggle", toggleGroup);
11983            }
11984        }
11985    };
11986 }();/*
11987  * Based on:
11988  * Ext JS Library 1.1.1
11989  * Copyright(c) 2006-2007, Ext JS, LLC.
11990  *
11991  * Originally Released Under LGPL - original licence link has changed is not relivant.
11992  *
11993  * Fork - LGPL
11994  * <script type="text/javascript">
11995  */
11996  
11997 /**
11998  * @class Roo.SplitButton
11999  * @extends Roo.Button
12000  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12001  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
12002  * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12003  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12004  * @cfg {String} arrowTooltip The title attribute of the arrow
12005  * @constructor
12006  * Create a new menu button
12007  * @param {String/HTMLElement/Element} renderTo The element to append the button to
12008  * @param {Object} config The config object
12009  */
12010 Roo.SplitButton = function(renderTo, config){
12011     Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12012     /**
12013      * @event arrowclick
12014      * Fires when this button's arrow is clicked
12015      * @param {SplitButton} this
12016      * @param {EventObject} e The click event
12017      */
12018     this.addEvents({"arrowclick":true});
12019 };
12020
12021 Roo.extend(Roo.SplitButton, Roo.Button, {
12022     render : function(renderTo){
12023         // this is one sweet looking template!
12024         var tpl = new Roo.Template(
12025             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12026             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12027             '<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>',
12028             "</tbody></table></td><td>",
12029             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12030             '<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>',
12031             "</tbody></table></td></tr></table>"
12032         );
12033         var btn = tpl.append(renderTo, [this.text, this.type], true);
12034         var btnEl = btn.child("button");
12035         if(this.cls){
12036             btn.addClass(this.cls);
12037         }
12038         if(this.icon){
12039             btnEl.setStyle('background-image', 'url(' +this.icon +')');
12040         }
12041         if(this.iconCls){
12042             btnEl.addClass(this.iconCls);
12043             if(!this.cls){
12044                 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12045             }
12046         }
12047         this.el = btn;
12048         if(this.handleMouseEvents){
12049             btn.on("mouseover", this.onMouseOver, this);
12050             btn.on("mouseout", this.onMouseOut, this);
12051             btn.on("mousedown", this.onMouseDown, this);
12052             btn.on("mouseup", this.onMouseUp, this);
12053         }
12054         btn.on(this.clickEvent, this.onClick, this);
12055         if(this.tooltip){
12056             if(typeof this.tooltip == 'object'){
12057                 Roo.QuickTips.tips(Roo.apply({
12058                       target: btnEl.id
12059                 }, this.tooltip));
12060             } else {
12061                 btnEl.dom[this.tooltipType] = this.tooltip;
12062             }
12063         }
12064         if(this.arrowTooltip){
12065             btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12066         }
12067         if(this.hidden){
12068             this.hide();
12069         }
12070         if(this.disabled){
12071             this.disable();
12072         }
12073         if(this.pressed){
12074             this.el.addClass("x-btn-pressed");
12075         }
12076         if(Roo.isIE && !Roo.isIE7){
12077             this.autoWidth.defer(1, this);
12078         }else{
12079             this.autoWidth();
12080         }
12081         if(this.menu){
12082             this.menu.on("show", this.onMenuShow, this);
12083             this.menu.on("hide", this.onMenuHide, this);
12084         }
12085         this.fireEvent('render', this);
12086     },
12087
12088     // private
12089     autoWidth : function(){
12090         if(this.el){
12091             var tbl = this.el.child("table:first");
12092             var tbl2 = this.el.child("table:last");
12093             this.el.setWidth("auto");
12094             tbl.setWidth("auto");
12095             if(Roo.isIE7 && Roo.isStrict){
12096                 var ib = this.el.child('button:first');
12097                 if(ib && ib.getWidth() > 20){
12098                     ib.clip();
12099                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12100                 }
12101             }
12102             if(this.minWidth){
12103                 if(this.hidden){
12104                     this.el.beginMeasure();
12105                 }
12106                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12107                     tbl.setWidth(this.minWidth-tbl2.getWidth());
12108                 }
12109                 if(this.hidden){
12110                     this.el.endMeasure();
12111                 }
12112             }
12113             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12114         } 
12115     },
12116     /**
12117      * Sets this button's click handler
12118      * @param {Function} handler The function to call when the button is clicked
12119      * @param {Object} scope (optional) Scope for the function passed above
12120      */
12121     setHandler : function(handler, scope){
12122         this.handler = handler;
12123         this.scope = scope;  
12124     },
12125     
12126     /**
12127      * Sets this button's arrow click handler
12128      * @param {Function} handler The function to call when the arrow is clicked
12129      * @param {Object} scope (optional) Scope for the function passed above
12130      */
12131     setArrowHandler : function(handler, scope){
12132         this.arrowHandler = handler;
12133         this.scope = scope;  
12134     },
12135     
12136     /**
12137      * Focus the button
12138      */
12139     focus : function(){
12140         if(this.el){
12141             this.el.child("button:first").focus();
12142         }
12143     },
12144
12145     // private
12146     onClick : function(e){
12147         e.preventDefault();
12148         if(!this.disabled){
12149             if(e.getTarget(".x-btn-menu-arrow-wrap")){
12150                 if(this.menu && !this.menu.isVisible()){
12151                     this.menu.show(this.el, this.menuAlign);
12152                 }
12153                 this.fireEvent("arrowclick", this, e);
12154                 if(this.arrowHandler){
12155                     this.arrowHandler.call(this.scope || this, this, e);
12156                 }
12157             }else{
12158                 this.fireEvent("click", this, e);
12159                 if(this.handler){
12160                     this.handler.call(this.scope || this, this, e);
12161                 }
12162             }
12163         }
12164     },
12165     // private
12166     onMouseDown : function(e){
12167         if(!this.disabled){
12168             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12169         }
12170     },
12171     // private
12172     onMouseUp : function(e){
12173         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12174     }   
12175 });
12176
12177
12178 // backwards compat
12179 Roo.MenuButton = Roo.SplitButton;/*
12180  * Based on:
12181  * Ext JS Library 1.1.1
12182  * Copyright(c) 2006-2007, Ext JS, LLC.
12183  *
12184  * Originally Released Under LGPL - original licence link has changed is not relivant.
12185  *
12186  * Fork - LGPL
12187  * <script type="text/javascript">
12188  */
12189
12190 /**
12191  * @class Roo.Toolbar
12192  * Basic Toolbar class.
12193  * @constructor
12194  * Creates a new Toolbar
12195  * @param {Object} config The config object
12196  */ 
12197 Roo.Toolbar = function(container, buttons, config)
12198 {
12199     /// old consturctor format still supported..
12200     if(container instanceof Array){ // omit the container for later rendering
12201         buttons = container;
12202         config = buttons;
12203         container = null;
12204     }
12205     if (typeof(container) == 'object' && container.xtype) {
12206         config = container;
12207         container = config.container;
12208         buttons = config.buttons; // not really - use items!!
12209     }
12210     var xitems = [];
12211     if (config && config.items) {
12212         xitems = config.items;
12213         delete config.items;
12214     }
12215     Roo.apply(this, config);
12216     this.buttons = buttons;
12217     
12218     if(container){
12219         this.render(container);
12220     }
12221     Roo.each(xitems, function(b) {
12222         this.add(b);
12223     }, this);
12224     
12225 };
12226
12227 Roo.Toolbar.prototype = {
12228     /**
12229      * @cfg {Roo.data.Store} items
12230      * array of button configs or elements to add
12231      */
12232     
12233     /**
12234      * @cfg {String/HTMLElement/Element} container
12235      * The id or element that will contain the toolbar
12236      */
12237     // private
12238     render : function(ct){
12239         this.el = Roo.get(ct);
12240         if(this.cls){
12241             this.el.addClass(this.cls);
12242         }
12243         // using a table allows for vertical alignment
12244         // 100% width is needed by Safari...
12245         this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12246         this.tr = this.el.child("tr", true);
12247         var autoId = 0;
12248         this.items = new Roo.util.MixedCollection(false, function(o){
12249             return o.id || ("item" + (++autoId));
12250         });
12251         if(this.buttons){
12252             this.add.apply(this, this.buttons);
12253             delete this.buttons;
12254         }
12255     },
12256
12257     /**
12258      * Adds element(s) to the toolbar -- this function takes a variable number of 
12259      * arguments of mixed type and adds them to the toolbar.
12260      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12261      * <ul>
12262      * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12263      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12264      * <li>Field: Any form field (equivalent to {@link #addField})</li>
12265      * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12266      * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12267      * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12268      * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12269      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12270      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12271      * </ul>
12272      * @param {Mixed} arg2
12273      * @param {Mixed} etc.
12274      */
12275     add : function(){
12276         var a = arguments, l = a.length;
12277         for(var i = 0; i < l; i++){
12278             this._add(a[i]);
12279         }
12280     },
12281     // private..
12282     _add : function(el) {
12283         
12284         if (el.xtype) {
12285             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12286         }
12287         
12288         if (el.applyTo){ // some kind of form field
12289             return this.addField(el);
12290         } 
12291         if (el.render){ // some kind of Toolbar.Item
12292             return this.addItem(el);
12293         }
12294         if (typeof el == "string"){ // string
12295             if(el == "separator" || el == "-"){
12296                 return this.addSeparator();
12297             }
12298             if (el == " "){
12299                 return this.addSpacer();
12300             }
12301             if(el == "->"){
12302                 return this.addFill();
12303             }
12304             return this.addText(el);
12305             
12306         }
12307         if(el.tagName){ // element
12308             return this.addElement(el);
12309         }
12310         if(typeof el == "object"){ // must be button config?
12311             return this.addButton(el);
12312         }
12313         // and now what?!?!
12314         return false;
12315         
12316     },
12317     
12318     /**
12319      * Add an Xtype element
12320      * @param {Object} xtype Xtype Object
12321      * @return {Object} created Object
12322      */
12323     addxtype : function(e){
12324         return this.add(e);  
12325     },
12326     
12327     /**
12328      * Returns the Element for this toolbar.
12329      * @return {Roo.Element}
12330      */
12331     getEl : function(){
12332         return this.el;  
12333     },
12334     
12335     /**
12336      * Adds a separator
12337      * @return {Roo.Toolbar.Item} The separator item
12338      */
12339     addSeparator : function(){
12340         return this.addItem(new Roo.Toolbar.Separator());
12341     },
12342
12343     /**
12344      * Adds a spacer element
12345      * @return {Roo.Toolbar.Spacer} The spacer item
12346      */
12347     addSpacer : function(){
12348         return this.addItem(new Roo.Toolbar.Spacer());
12349     },
12350
12351     /**
12352      * Adds a fill element that forces subsequent additions to the right side of the toolbar
12353      * @return {Roo.Toolbar.Fill} The fill item
12354      */
12355     addFill : function(){
12356         return this.addItem(new Roo.Toolbar.Fill());
12357     },
12358
12359     /**
12360      * Adds any standard HTML element to the toolbar
12361      * @param {String/HTMLElement/Element} el The element or id of the element to add
12362      * @return {Roo.Toolbar.Item} The element's item
12363      */
12364     addElement : function(el){
12365         return this.addItem(new Roo.Toolbar.Item(el));
12366     },
12367     /**
12368      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12369      * @type Roo.util.MixedCollection  
12370      */
12371     items : false,
12372      
12373     /**
12374      * Adds any Toolbar.Item or subclass
12375      * @param {Roo.Toolbar.Item} item
12376      * @return {Roo.Toolbar.Item} The item
12377      */
12378     addItem : function(item){
12379         var td = this.nextBlock();
12380         item.render(td);
12381         this.items.add(item);
12382         return item;
12383     },
12384     
12385     /**
12386      * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12387      * @param {Object/Array} config A button config or array of configs
12388      * @return {Roo.Toolbar.Button/Array}
12389      */
12390     addButton : function(config){
12391         if(config instanceof Array){
12392             var buttons = [];
12393             for(var i = 0, len = config.length; i < len; i++) {
12394                 buttons.push(this.addButton(config[i]));
12395             }
12396             return buttons;
12397         }
12398         var b = config;
12399         if(!(config instanceof Roo.Toolbar.Button)){
12400             b = config.split ?
12401                 new Roo.Toolbar.SplitButton(config) :
12402                 new Roo.Toolbar.Button(config);
12403         }
12404         var td = this.nextBlock();
12405         b.render(td);
12406         this.items.add(b);
12407         return b;
12408     },
12409     
12410     /**
12411      * Adds text to the toolbar
12412      * @param {String} text The text to add
12413      * @return {Roo.Toolbar.Item} The element's item
12414      */
12415     addText : function(text){
12416         return this.addItem(new Roo.Toolbar.TextItem(text));
12417     },
12418     
12419     /**
12420      * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12421      * @param {Number} index The index where the item is to be inserted
12422      * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12423      * @return {Roo.Toolbar.Button/Item}
12424      */
12425     insertButton : function(index, item){
12426         if(item instanceof Array){
12427             var buttons = [];
12428             for(var i = 0, len = item.length; i < len; i++) {
12429                buttons.push(this.insertButton(index + i, item[i]));
12430             }
12431             return buttons;
12432         }
12433         if (!(item instanceof Roo.Toolbar.Button)){
12434            item = new Roo.Toolbar.Button(item);
12435         }
12436         var td = document.createElement("td");
12437         this.tr.insertBefore(td, this.tr.childNodes[index]);
12438         item.render(td);
12439         this.items.insert(index, item);
12440         return item;
12441     },
12442     
12443     /**
12444      * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12445      * @param {Object} config
12446      * @return {Roo.Toolbar.Item} The element's item
12447      */
12448     addDom : function(config, returnEl){
12449         var td = this.nextBlock();
12450         Roo.DomHelper.overwrite(td, config);
12451         var ti = new Roo.Toolbar.Item(td.firstChild);
12452         ti.render(td);
12453         this.items.add(ti);
12454         return ti;
12455     },
12456
12457     /**
12458      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12459      * @type Roo.util.MixedCollection  
12460      */
12461     fields : false,
12462     
12463     /**
12464      * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12465      * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12466      * @param {Roo.form.Field} field
12467      * @return {Roo.ToolbarItem}
12468      */
12469      
12470       
12471     addField : function(field) {
12472         if (!this.fields) {
12473             var autoId = 0;
12474             this.fields = new Roo.util.MixedCollection(false, function(o){
12475                 return o.id || ("item" + (++autoId));
12476             });
12477
12478         }
12479         
12480         var td = this.nextBlock();
12481         field.render(td);
12482         var ti = new Roo.Toolbar.Item(td.firstChild);
12483         ti.render(td);
12484         this.items.add(ti);
12485         this.fields.add(field);
12486         return ti;
12487     },
12488     /**
12489      * Hide the toolbar
12490      * @method hide
12491      */
12492      
12493       
12494     hide : function()
12495     {
12496         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12497         this.el.child('div').hide();
12498     },
12499     /**
12500      * Show the toolbar
12501      * @method show
12502      */
12503     show : function()
12504     {
12505         this.el.child('div').show();
12506     },
12507       
12508     // private
12509     nextBlock : function(){
12510         var td = document.createElement("td");
12511         this.tr.appendChild(td);
12512         return td;
12513     },
12514
12515     // private
12516     destroy : function(){
12517         if(this.items){ // rendered?
12518             Roo.destroy.apply(Roo, this.items.items);
12519         }
12520         if(this.fields){ // rendered?
12521             Roo.destroy.apply(Roo, this.fields.items);
12522         }
12523         Roo.Element.uncache(this.el, this.tr);
12524     }
12525 };
12526
12527 /**
12528  * @class Roo.Toolbar.Item
12529  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12530  * @constructor
12531  * Creates a new Item
12532  * @param {HTMLElement} el 
12533  */
12534 Roo.Toolbar.Item = function(el){
12535     this.el = Roo.getDom(el);
12536     this.id = Roo.id(this.el);
12537     this.hidden = false;
12538 };
12539
12540 Roo.Toolbar.Item.prototype = {
12541     
12542     /**
12543      * Get this item's HTML Element
12544      * @return {HTMLElement}
12545      */
12546     getEl : function(){
12547        return this.el;  
12548     },
12549
12550     // private
12551     render : function(td){
12552         this.td = td;
12553         td.appendChild(this.el);
12554     },
12555     
12556     /**
12557      * Removes and destroys this item.
12558      */
12559     destroy : function(){
12560         this.td.parentNode.removeChild(this.td);
12561     },
12562     
12563     /**
12564      * Shows this item.
12565      */
12566     show: function(){
12567         this.hidden = false;
12568         this.td.style.display = "";
12569     },
12570     
12571     /**
12572      * Hides this item.
12573      */
12574     hide: function(){
12575         this.hidden = true;
12576         this.td.style.display = "none";
12577     },
12578     
12579     /**
12580      * Convenience function for boolean show/hide.
12581      * @param {Boolean} visible true to show/false to hide
12582      */
12583     setVisible: function(visible){
12584         if(visible) {
12585             this.show();
12586         }else{
12587             this.hide();
12588         }
12589     },
12590     
12591     /**
12592      * Try to focus this item.
12593      */
12594     focus : function(){
12595         Roo.fly(this.el).focus();
12596     },
12597     
12598     /**
12599      * Disables this item.
12600      */
12601     disable : function(){
12602         Roo.fly(this.td).addClass("x-item-disabled");
12603         this.disabled = true;
12604         this.el.disabled = true;
12605     },
12606     
12607     /**
12608      * Enables this item.
12609      */
12610     enable : function(){
12611         Roo.fly(this.td).removeClass("x-item-disabled");
12612         this.disabled = false;
12613         this.el.disabled = false;
12614     }
12615 };
12616
12617
12618 /**
12619  * @class Roo.Toolbar.Separator
12620  * @extends Roo.Toolbar.Item
12621  * A simple toolbar separator class
12622  * @constructor
12623  * Creates a new Separator
12624  */
12625 Roo.Toolbar.Separator = function(){
12626     var s = document.createElement("span");
12627     s.className = "ytb-sep";
12628     Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12629 };
12630 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12631     enable:Roo.emptyFn,
12632     disable:Roo.emptyFn,
12633     focus:Roo.emptyFn
12634 });
12635
12636 /**
12637  * @class Roo.Toolbar.Spacer
12638  * @extends Roo.Toolbar.Item
12639  * A simple element that adds extra horizontal space to a toolbar.
12640  * @constructor
12641  * Creates a new Spacer
12642  */
12643 Roo.Toolbar.Spacer = function(){
12644     var s = document.createElement("div");
12645     s.className = "ytb-spacer";
12646     Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12647 };
12648 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12649     enable:Roo.emptyFn,
12650     disable:Roo.emptyFn,
12651     focus:Roo.emptyFn
12652 });
12653
12654 /**
12655  * @class Roo.Toolbar.Fill
12656  * @extends Roo.Toolbar.Spacer
12657  * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12658  * @constructor
12659  * Creates a new Spacer
12660  */
12661 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12662     // private
12663     render : function(td){
12664         td.style.width = '100%';
12665         Roo.Toolbar.Fill.superclass.render.call(this, td);
12666     }
12667 });
12668
12669 /**
12670  * @class Roo.Toolbar.TextItem
12671  * @extends Roo.Toolbar.Item
12672  * A simple class that renders text directly into a toolbar.
12673  * @constructor
12674  * Creates a new TextItem
12675  * @param {String} text
12676  */
12677 Roo.Toolbar.TextItem = function(text){
12678     if (typeof(text) == 'object') {
12679         text = text.text;
12680     }
12681     var s = document.createElement("span");
12682     s.className = "ytb-text";
12683     s.innerHTML = text;
12684     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12685 };
12686 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12687     enable:Roo.emptyFn,
12688     disable:Roo.emptyFn,
12689     focus:Roo.emptyFn
12690 });
12691
12692 /**
12693  * @class Roo.Toolbar.Button
12694  * @extends Roo.Button
12695  * A button that renders into a toolbar.
12696  * @constructor
12697  * Creates a new Button
12698  * @param {Object} config A standard {@link Roo.Button} config object
12699  */
12700 Roo.Toolbar.Button = function(config){
12701     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12702 };
12703 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12704     render : function(td){
12705         this.td = td;
12706         Roo.Toolbar.Button.superclass.render.call(this, td);
12707     },
12708     
12709     /**
12710      * Removes and destroys this button
12711      */
12712     destroy : function(){
12713         Roo.Toolbar.Button.superclass.destroy.call(this);
12714         this.td.parentNode.removeChild(this.td);
12715     },
12716     
12717     /**
12718      * Shows this button
12719      */
12720     show: function(){
12721         this.hidden = false;
12722         this.td.style.display = "";
12723     },
12724     
12725     /**
12726      * Hides this button
12727      */
12728     hide: function(){
12729         this.hidden = true;
12730         this.td.style.display = "none";
12731     },
12732
12733     /**
12734      * Disables this item
12735      */
12736     disable : function(){
12737         Roo.fly(this.td).addClass("x-item-disabled");
12738         this.disabled = true;
12739     },
12740
12741     /**
12742      * Enables this item
12743      */
12744     enable : function(){
12745         Roo.fly(this.td).removeClass("x-item-disabled");
12746         this.disabled = false;
12747     }
12748 });
12749 // backwards compat
12750 Roo.ToolbarButton = Roo.Toolbar.Button;
12751
12752 /**
12753  * @class Roo.Toolbar.SplitButton
12754  * @extends Roo.SplitButton
12755  * A menu button that renders into a toolbar.
12756  * @constructor
12757  * Creates a new SplitButton
12758  * @param {Object} config A standard {@link Roo.SplitButton} config object
12759  */
12760 Roo.Toolbar.SplitButton = function(config){
12761     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12762 };
12763 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12764     render : function(td){
12765         this.td = td;
12766         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12767     },
12768     
12769     /**
12770      * Removes and destroys this button
12771      */
12772     destroy : function(){
12773         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12774         this.td.parentNode.removeChild(this.td);
12775     },
12776     
12777     /**
12778      * Shows this button
12779      */
12780     show: function(){
12781         this.hidden = false;
12782         this.td.style.display = "";
12783     },
12784     
12785     /**
12786      * Hides this button
12787      */
12788     hide: function(){
12789         this.hidden = true;
12790         this.td.style.display = "none";
12791     }
12792 });
12793
12794 // backwards compat
12795 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12796  * Based on:
12797  * Ext JS Library 1.1.1
12798  * Copyright(c) 2006-2007, Ext JS, LLC.
12799  *
12800  * Originally Released Under LGPL - original licence link has changed is not relivant.
12801  *
12802  * Fork - LGPL
12803  * <script type="text/javascript">
12804  */
12805  
12806 /**
12807  * @class Roo.PagingToolbar
12808  * @extends Roo.Toolbar
12809  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12810  * @constructor
12811  * Create a new PagingToolbar
12812  * @param {Object} config The config object
12813  */
12814 Roo.PagingToolbar = function(el, ds, config)
12815 {
12816     // old args format still supported... - xtype is prefered..
12817     if (typeof(el) == 'object' && el.xtype) {
12818         // created from xtype...
12819         config = el;
12820         ds = el.dataSource;
12821         el = config.container;
12822     }
12823     var items = [];
12824     if (config.items) {
12825         items = config.items;
12826         config.items = [];
12827     }
12828     
12829     Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12830     this.ds = ds;
12831     this.cursor = 0;
12832     this.renderButtons(this.el);
12833     this.bind(ds);
12834     
12835     // supprot items array.
12836    
12837     Roo.each(items, function(e) {
12838         this.add(Roo.factory(e));
12839     },this);
12840     
12841 };
12842
12843 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12844     /**
12845      * @cfg {Roo.data.Store} dataSource
12846      * The underlying data store providing the paged data
12847      */
12848     /**
12849      * @cfg {String/HTMLElement/Element} container
12850      * container The id or element that will contain the toolbar
12851      */
12852     /**
12853      * @cfg {Boolean} displayInfo
12854      * True to display the displayMsg (defaults to false)
12855      */
12856     /**
12857      * @cfg {Number} pageSize
12858      * The number of records to display per page (defaults to 20)
12859      */
12860     pageSize: 20,
12861     /**
12862      * @cfg {String} displayMsg
12863      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12864      */
12865     displayMsg : 'Displaying {0} - {1} of {2}',
12866     /**
12867      * @cfg {String} emptyMsg
12868      * The message to display when no records are found (defaults to "No data to display")
12869      */
12870     emptyMsg : 'No data to display',
12871     /**
12872      * Customizable piece of the default paging text (defaults to "Page")
12873      * @type String
12874      */
12875     beforePageText : "Page",
12876     /**
12877      * Customizable piece of the default paging text (defaults to "of %0")
12878      * @type String
12879      */
12880     afterPageText : "of {0}",
12881     /**
12882      * Customizable piece of the default paging text (defaults to "First Page")
12883      * @type String
12884      */
12885     firstText : "First Page",
12886     /**
12887      * Customizable piece of the default paging text (defaults to "Previous Page")
12888      * @type String
12889      */
12890     prevText : "Previous Page",
12891     /**
12892      * Customizable piece of the default paging text (defaults to "Next Page")
12893      * @type String
12894      */
12895     nextText : "Next Page",
12896     /**
12897      * Customizable piece of the default paging text (defaults to "Last Page")
12898      * @type String
12899      */
12900     lastText : "Last Page",
12901     /**
12902      * Customizable piece of the default paging text (defaults to "Refresh")
12903      * @type String
12904      */
12905     refreshText : "Refresh",
12906
12907     // private
12908     renderButtons : function(el){
12909         Roo.PagingToolbar.superclass.render.call(this, el);
12910         this.first = this.addButton({
12911             tooltip: this.firstText,
12912             cls: "x-btn-icon x-grid-page-first",
12913             disabled: true,
12914             handler: this.onClick.createDelegate(this, ["first"])
12915         });
12916         this.prev = this.addButton({
12917             tooltip: this.prevText,
12918             cls: "x-btn-icon x-grid-page-prev",
12919             disabled: true,
12920             handler: this.onClick.createDelegate(this, ["prev"])
12921         });
12922         //this.addSeparator();
12923         this.add(this.beforePageText);
12924         this.field = Roo.get(this.addDom({
12925            tag: "input",
12926            type: "text",
12927            size: "3",
12928            value: "1",
12929            cls: "x-grid-page-number"
12930         }).el);
12931         this.field.on("keydown", this.onPagingKeydown, this);
12932         this.field.on("focus", function(){this.dom.select();});
12933         this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12934         this.field.setHeight(18);
12935         //this.addSeparator();
12936         this.next = this.addButton({
12937             tooltip: this.nextText,
12938             cls: "x-btn-icon x-grid-page-next",
12939             disabled: true,
12940             handler: this.onClick.createDelegate(this, ["next"])
12941         });
12942         this.last = this.addButton({
12943             tooltip: this.lastText,
12944             cls: "x-btn-icon x-grid-page-last",
12945             disabled: true,
12946             handler: this.onClick.createDelegate(this, ["last"])
12947         });
12948         //this.addSeparator();
12949         this.loading = this.addButton({
12950             tooltip: this.refreshText,
12951             cls: "x-btn-icon x-grid-loading",
12952             handler: this.onClick.createDelegate(this, ["refresh"])
12953         });
12954
12955         if(this.displayInfo){
12956             this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12957         }
12958     },
12959
12960     // private
12961     updateInfo : function(){
12962         if(this.displayEl){
12963             var count = this.ds.getCount();
12964             var msg = count == 0 ?
12965                 this.emptyMsg :
12966                 String.format(
12967                     this.displayMsg,
12968                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
12969                 );
12970             this.displayEl.update(msg);
12971         }
12972     },
12973
12974     // private
12975     onLoad : function(ds, r, o){
12976        this.cursor = o.params ? o.params.start : 0;
12977        var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12978
12979        this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12980        this.field.dom.value = ap;
12981        this.first.setDisabled(ap == 1);
12982        this.prev.setDisabled(ap == 1);
12983        this.next.setDisabled(ap == ps);
12984        this.last.setDisabled(ap == ps);
12985        this.loading.enable();
12986        this.updateInfo();
12987     },
12988
12989     // private
12990     getPageData : function(){
12991         var total = this.ds.getTotalCount();
12992         return {
12993             total : total,
12994             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12995             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12996         };
12997     },
12998
12999     // private
13000     onLoadError : function(){
13001         this.loading.enable();
13002     },
13003
13004     // private
13005     onPagingKeydown : function(e){
13006         var k = e.getKey();
13007         var d = this.getPageData();
13008         if(k == e.RETURN){
13009             var v = this.field.dom.value, pageNum;
13010             if(!v || isNaN(pageNum = parseInt(v, 10))){
13011                 this.field.dom.value = d.activePage;
13012                 return;
13013             }
13014             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13015             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13016             e.stopEvent();
13017         }
13018         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))
13019         {
13020           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13021           this.field.dom.value = pageNum;
13022           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13023           e.stopEvent();
13024         }
13025         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13026         {
13027           var v = this.field.dom.value, pageNum; 
13028           var increment = (e.shiftKey) ? 10 : 1;
13029           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13030             increment *= -1;
13031           if(!v || isNaN(pageNum = parseInt(v, 10))) {
13032             this.field.dom.value = d.activePage;
13033             return;
13034           }
13035           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13036           {
13037             this.field.dom.value = parseInt(v, 10) + increment;
13038             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13039             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13040           }
13041           e.stopEvent();
13042         }
13043     },
13044
13045     // private
13046     beforeLoad : function(){
13047         if(this.loading){
13048             this.loading.disable();
13049         }
13050     },
13051
13052     // private
13053     onClick : function(which){
13054         var ds = this.ds;
13055         switch(which){
13056             case "first":
13057                 ds.load({params:{start: 0, limit: this.pageSize}});
13058             break;
13059             case "prev":
13060                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13061             break;
13062             case "next":
13063                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13064             break;
13065             case "last":
13066                 var total = ds.getTotalCount();
13067                 var extra = total % this.pageSize;
13068                 var lastStart = extra ? (total - extra) : total-this.pageSize;
13069                 ds.load({params:{start: lastStart, limit: this.pageSize}});
13070             break;
13071             case "refresh":
13072                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13073             break;
13074         }
13075     },
13076
13077     /**
13078      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13079      * @param {Roo.data.Store} store The data store to unbind
13080      */
13081     unbind : function(ds){
13082         ds.un("beforeload", this.beforeLoad, this);
13083         ds.un("load", this.onLoad, this);
13084         ds.un("loadexception", this.onLoadError, this);
13085         ds.un("remove", this.updateInfo, this);
13086         ds.un("add", this.updateInfo, this);
13087         this.ds = undefined;
13088     },
13089
13090     /**
13091      * Binds the paging toolbar to the specified {@link Roo.data.Store}
13092      * @param {Roo.data.Store} store The data store to bind
13093      */
13094     bind : function(ds){
13095         ds.on("beforeload", this.beforeLoad, this);
13096         ds.on("load", this.onLoad, this);
13097         ds.on("loadexception", this.onLoadError, this);
13098         ds.on("remove", this.updateInfo, this);
13099         ds.on("add", this.updateInfo, this);
13100         this.ds = ds;
13101     }
13102 });