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  * Defines the interface and base operation of items that that can be
30  * dragged or can be drop targets.  It was designed to be extended, overriding
31  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32  * Up to three html elements can be associated with a DragDrop instance:
33  * <ul>
34  * <li>linked element: the element that is passed into the constructor.
35  * This is the element which defines the boundaries for interaction with
36  * other DragDrop objects.</li>
37  * <li>handle element(s): The drag operation only occurs if the element that
38  * was clicked matches a handle element.  By default this is the linked
39  * element, but there are times that you will want only a portion of the
40  * linked element to initiate the drag operation, and the setHandleElId()
41  * method provides a way to define this.</li>
42  * <li>drag element: this represents the element that would be moved along
43  * with the cursor during a drag operation.  By default, this is the linked
44  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
45  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
46  * </li>
47  * </ul>
48  * This class should not be instantiated until the onload event to ensure that
49  * the associated elements are available.
50  * The following would define a DragDrop obj that would interact with any
51  * other DragDrop obj in the "group1" group:
52  * <pre>
53  *  dd = new Roo.dd.DragDrop("div1", "group1");
54  * </pre>
55  * Since none of the event handlers have been implemented, nothing would
56  * actually happen if you were to run the code above.  Normally you would
57  * override this class or one of the default implementations, but you can
58  * also override the methods you want on an instance of the class...
59  * <pre>
60  *  dd.onDragDrop = function(e, id) {
61  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
62  *  }
63  * </pre>
64  * @constructor
65  * @param {String} id of the element that is linked to this instance
66  * @param {String} sGroup the group of related DragDrop objects
67  * @param {object} config an object containing configurable attributes
68  *                Valid properties for DragDrop:
69  *                    padding, isTarget, maintainOffset, primaryButtonOnly
70  */
71 Roo.dd.DragDrop = function(id, sGroup, config) {
72     if (id) {
73         this.init(id, sGroup, config);
74     }
75 };
76
77 Roo.dd.DragDrop.prototype = {
78
79     /**
80      * The id of the element associated with this object.  This is what we
81      * refer to as the "linked element" because the size and position of
82      * this element is used to determine when the drag and drop objects have
83      * interacted.
84      * @property id
85      * @type String
86      */
87     id: null,
88
89     /**
90      * Configuration attributes passed into the constructor
91      * @property config
92      * @type object
93      */
94     config: null,
95
96     /**
97      * The id of the element that will be dragged.  By default this is same
98      * as the linked element , but could be changed to another element. Ex:
99      * Roo.dd.DDProxy
100      * @property dragElId
101      * @type String
102      * @private
103      */
104     dragElId: null,
105
106     /**
107      * the id of the element that initiates the drag operation.  By default
108      * this is the linked element, but could be changed to be a child of this
109      * element.  This lets us do things like only starting the drag when the
110      * header element within the linked html element is clicked.
111      * @property handleElId
112      * @type String
113      * @private
114      */
115     handleElId: null,
116
117     /**
118      * An associative array of HTML tags that will be ignored if clicked.
119      * @property invalidHandleTypes
120      * @type {string: string}
121      */
122     invalidHandleTypes: null,
123
124     /**
125      * An associative array of ids for elements that will be ignored if clicked
126      * @property invalidHandleIds
127      * @type {string: string}
128      */
129     invalidHandleIds: null,
130
131     /**
132      * An indexted array of css class names for elements that will be ignored
133      * if clicked.
134      * @property invalidHandleClasses
135      * @type string[]
136      */
137     invalidHandleClasses: null,
138
139     /**
140      * The linked element's absolute X position at the time the drag was
141      * started
142      * @property startPageX
143      * @type int
144      * @private
145      */
146     startPageX: 0,
147
148     /**
149      * The linked element's absolute X position at the time the drag was
150      * started
151      * @property startPageY
152      * @type int
153      * @private
154      */
155     startPageY: 0,
156
157     /**
158      * The group defines a logical collection of DragDrop objects that are
159      * related.  Instances only get events when interacting with other
160      * DragDrop object in the same group.  This lets us define multiple
161      * groups using a single DragDrop subclass if we want.
162      * @property groups
163      * @type {string: string}
164      */
165     groups: null,
166
167     /**
168      * Individual drag/drop instances can be locked.  This will prevent
169      * onmousedown start drag.
170      * @property locked
171      * @type boolean
172      * @private
173      */
174     locked: false,
175
176     /**
177      * Lock this instance
178      * @method lock
179      */
180     lock: function() { this.locked = true; },
181
182     /**
183      * Unlock this instace
184      * @method unlock
185      */
186     unlock: function() { this.locked = false; },
187
188     /**
189      * By default, all insances can be a drop target.  This can be disabled by
190      * setting isTarget to false.
191      * @method isTarget
192      * @type boolean
193      */
194     isTarget: true,
195
196     /**
197      * The padding configured for this drag and drop object for calculating
198      * the drop zone intersection with this object.
199      * @method padding
200      * @type int[]
201      */
202     padding: null,
203
204     /**
205      * Cached reference to the linked element
206      * @property _domRef
207      * @private
208      */
209     _domRef: null,
210
211     /**
212      * Internal typeof flag
213      * @property __ygDragDrop
214      * @private
215      */
216     __ygDragDrop: true,
217
218     /**
219      * Set to true when horizontal contraints are applied
220      * @property constrainX
221      * @type boolean
222      * @private
223      */
224     constrainX: false,
225
226     /**
227      * Set to true when vertical contraints are applied
228      * @property constrainY
229      * @type boolean
230      * @private
231      */
232     constrainY: false,
233
234     /**
235      * The left constraint
236      * @property minX
237      * @type int
238      * @private
239      */
240     minX: 0,
241
242     /**
243      * The right constraint
244      * @property maxX
245      * @type int
246      * @private
247      */
248     maxX: 0,
249
250     /**
251      * The up constraint
252      * @property minY
253      * @type int
254      * @type int
255      * @private
256      */
257     minY: 0,
258
259     /**
260      * The down constraint
261      * @property maxY
262      * @type int
263      * @private
264      */
265     maxY: 0,
266
267     /**
268      * Maintain offsets when we resetconstraints.  Set to true when you want
269      * the position of the element relative to its parent to stay the same
270      * when the page changes
271      *
272      * @property maintainOffset
273      * @type boolean
274      */
275     maintainOffset: false,
276
277     /**
278      * Array of pixel locations the element will snap to if we specified a
279      * horizontal graduation/interval.  This array is generated automatically
280      * when you define a tick interval.
281      * @property xTicks
282      * @type int[]
283      */
284     xTicks: null,
285
286     /**
287      * Array of pixel locations the element will snap to if we specified a
288      * vertical graduation/interval.  This array is generated automatically
289      * when you define a tick interval.
290      * @property yTicks
291      * @type int[]
292      */
293     yTicks: null,
294
295     /**
296      * By default the drag and drop instance will only respond to the primary
297      * button click (left button for a right-handed mouse).  Set to true to
298      * allow drag and drop to start with any mouse click that is propogated
299      * by the browser
300      * @property primaryButtonOnly
301      * @type boolean
302      */
303     primaryButtonOnly: true,
304
305     /**
306      * The availabe property is false until the linked dom element is accessible.
307      * @property available
308      * @type boolean
309      */
310     available: false,
311
312     /**
313      * By default, drags can only be initiated if the mousedown occurs in the
314      * region the linked element is.  This is done in part to work around a
315      * bug in some browsers that mis-report the mousedown if the previous
316      * mouseup happened outside of the window.  This property is set to true
317      * if outer handles are defined.
318      *
319      * @property hasOuterHandles
320      * @type boolean
321      * @default false
322      */
323     hasOuterHandles: false,
324
325     /**
326      * Code that executes immediately before the startDrag event
327      * @method b4StartDrag
328      * @private
329      */
330     b4StartDrag: function(x, y) { },
331
332     /**
333      * Abstract method called after a drag/drop object is clicked
334      * and the drag or mousedown time thresholds have beeen met.
335      * @method startDrag
336      * @param {int} X click location
337      * @param {int} Y click location
338      */
339     startDrag: function(x, y) { /* override this */ },
340
341     /**
342      * Code that executes immediately before the onDrag event
343      * @method b4Drag
344      * @private
345      */
346     b4Drag: function(e) { },
347
348     /**
349      * Abstract method called during the onMouseMove event while dragging an
350      * object.
351      * @method onDrag
352      * @param {Event} e the mousemove event
353      */
354     onDrag: function(e) { /* override this */ },
355
356     /**
357      * Abstract method called when this element fist begins hovering over
358      * another DragDrop obj
359      * @method onDragEnter
360      * @param {Event} e the mousemove event
361      * @param {String|DragDrop[]} id In POINT mode, the element
362      * id this is hovering over.  In INTERSECT mode, an array of one or more
363      * dragdrop items being hovered over.
364      */
365     onDragEnter: function(e, id) { /* override this */ },
366
367     /**
368      * Code that executes immediately before the onDragOver event
369      * @method b4DragOver
370      * @private
371      */
372     b4DragOver: function(e) { },
373
374     /**
375      * Abstract method called when this element is hovering over another
376      * DragDrop obj
377      * @method onDragOver
378      * @param {Event} e the mousemove event
379      * @param {String|DragDrop[]} id In POINT mode, the element
380      * id this is hovering over.  In INTERSECT mode, an array of dd items
381      * being hovered over.
382      */
383     onDragOver: function(e, id) { /* override this */ },
384
385     /**
386      * Code that executes immediately before the onDragOut event
387      * @method b4DragOut
388      * @private
389      */
390     b4DragOut: function(e) { },
391
392     /**
393      * Abstract method called when we are no longer hovering over an element
394      * @method onDragOut
395      * @param {Event} e the mousemove event
396      * @param {String|DragDrop[]} id In POINT mode, the element
397      * id this was hovering over.  In INTERSECT mode, an array of dd items
398      * that the mouse is no longer over.
399      */
400     onDragOut: function(e, id) { /* override this */ },
401
402     /**
403      * Code that executes immediately before the onDragDrop event
404      * @method b4DragDrop
405      * @private
406      */
407     b4DragDrop: function(e) { },
408
409     /**
410      * Abstract method called when this item is dropped on another DragDrop
411      * obj
412      * @method onDragDrop
413      * @param {Event} e the mouseup event
414      * @param {String|DragDrop[]} id In POINT mode, the element
415      * id this was dropped on.  In INTERSECT mode, an array of dd items this
416      * was dropped on.
417      */
418     onDragDrop: function(e, id) { /* override this */ },
419
420     /**
421      * Abstract method called when this item is dropped on an area with no
422      * drop target
423      * @method onInvalidDrop
424      * @param {Event} e the mouseup event
425      */
426     onInvalidDrop: function(e) { /* override this */ },
427
428     /**
429      * Code that executes immediately before the endDrag event
430      * @method b4EndDrag
431      * @private
432      */
433     b4EndDrag: function(e) { },
434
435     /**
436      * Fired when we are done dragging the object
437      * @method endDrag
438      * @param {Event} e the mouseup event
439      */
440     endDrag: function(e) { /* override this */ },
441
442     /**
443      * Code executed immediately before the onMouseDown event
444      * @method b4MouseDown
445      * @param {Event} e the mousedown event
446      * @private
447      */
448     b4MouseDown: function(e) {  },
449
450     /**
451      * Event handler that fires when a drag/drop obj gets a mousedown
452      * @method onMouseDown
453      * @param {Event} e the mousedown event
454      */
455     onMouseDown: function(e) { /* override this */ },
456
457     /**
458      * Event handler that fires when a drag/drop obj gets a mouseup
459      * @method onMouseUp
460      * @param {Event} e the mouseup event
461      */
462     onMouseUp: function(e) { /* override this */ },
463
464     /**
465      * Override the onAvailable method to do what is needed after the initial
466      * position was determined.
467      * @method onAvailable
468      */
469     onAvailable: function () {
470     },
471
472     /*
473      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
474      * @type Object
475      */
476     defaultPadding : {left:0, right:0, top:0, bottom:0},
477
478     /*
479      * Initializes the drag drop object's constraints to restrict movement to a certain element.
480  *
481  * Usage:
482  <pre><code>
483  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
484                 { dragElId: "existingProxyDiv" });
485  dd.startDrag = function(){
486      this.constrainTo("parent-id");
487  };
488  </code></pre>
489  * Or you can initalize it using the {@link Roo.Element} object:
490  <pre><code>
491  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
492      startDrag : function(){
493          this.constrainTo("parent-id");
494      }
495  });
496  </code></pre>
497      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
498      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
499      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
500      * an object containing the sides to pad. For example: {right:10, bottom:10}
501      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
502      */
503     constrainTo : function(constrainTo, pad, inContent){
504         if(typeof pad == "number"){
505             pad = {left: pad, right:pad, top:pad, bottom:pad};
506         }
507         pad = pad || this.defaultPadding;
508         var b = Roo.get(this.getEl()).getBox();
509         var ce = Roo.get(constrainTo);
510         var s = ce.getScroll();
511         var c, cd = ce.dom;
512         if(cd == document.body){
513             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
514         }else{
515             xy = ce.getXY();
516             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
517         }
518
519
520         var topSpace = b.y - c.y;
521         var leftSpace = b.x - c.x;
522
523         this.resetConstraints();
524         this.setXConstraint(leftSpace - (pad.left||0), // left
525                 c.width - leftSpace - b.width - (pad.right||0) //right
526         );
527         this.setYConstraint(topSpace - (pad.top||0), //top
528                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
529         );
530     },
531
532     /**
533      * Returns a reference to the linked element
534      * @method getEl
535      * @return {HTMLElement} the html element
536      */
537     getEl: function() {
538         if (!this._domRef) {
539             this._domRef = Roo.getDom(this.id);
540         }
541
542         return this._domRef;
543     },
544
545     /**
546      * Returns a reference to the actual element to drag.  By default this is
547      * the same as the html element, but it can be assigned to another
548      * element. An example of this can be found in Roo.dd.DDProxy
549      * @method getDragEl
550      * @return {HTMLElement} the html element
551      */
552     getDragEl: function() {
553         return Roo.getDom(this.dragElId);
554     },
555
556     /**
557      * Sets up the DragDrop object.  Must be called in the constructor of any
558      * Roo.dd.DragDrop subclass
559      * @method init
560      * @param id the id of the linked element
561      * @param {String} sGroup the group of related items
562      * @param {object} config configuration attributes
563      */
564     init: function(id, sGroup, config) {
565         this.initTarget(id, sGroup, config);
566         Event.on(this.id, "mousedown", this.handleMouseDown, this);
567         // Event.on(this.id, "selectstart", Event.preventDefault);
568     },
569
570     /**
571      * Initializes Targeting functionality only... the object does not
572      * get a mousedown handler.
573      * @method initTarget
574      * @param id the id of the linked element
575      * @param {String} sGroup the group of related items
576      * @param {object} config configuration attributes
577      */
578     initTarget: function(id, sGroup, config) {
579
580         // configuration attributes
581         this.config = config || {};
582
583         // create a local reference to the drag and drop manager
584         this.DDM = Roo.dd.DDM;
585         // initialize the groups array
586         this.groups = {};
587
588         // assume that we have an element reference instead of an id if the
589         // parameter is not a string
590         if (typeof id !== "string") {
591             id = Roo.id(id);
592         }
593
594         // set the id
595         this.id = id;
596
597         // add to an interaction group
598         this.addToGroup((sGroup) ? sGroup : "default");
599
600         // We don't want to register this as the handle with the manager
601         // so we just set the id rather than calling the setter.
602         this.handleElId = id;
603
604         // the linked element is the element that gets dragged by default
605         this.setDragElId(id);
606
607         // by default, clicked anchors will not start drag operations.
608         this.invalidHandleTypes = { A: "A" };
609         this.invalidHandleIds = {};
610         this.invalidHandleClasses = [];
611
612         this.applyConfig();
613
614         this.handleOnAvailable();
615     },
616
617     /**
618      * Applies the configuration parameters that were passed into the constructor.
619      * This is supposed to happen at each level through the inheritance chain.  So
620      * a DDProxy implentation will execute apply config on DDProxy, DD, and
621      * DragDrop in order to get all of the parameters that are available in
622      * each object.
623      * @method applyConfig
624      */
625     applyConfig: function() {
626
627         // configurable properties:
628         //    padding, isTarget, maintainOffset, primaryButtonOnly
629         this.padding           = this.config.padding || [0, 0, 0, 0];
630         this.isTarget          = (this.config.isTarget !== false);
631         this.maintainOffset    = (this.config.maintainOffset);
632         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
633
634     },
635
636     /**
637      * Executed when the linked element is available
638      * @method handleOnAvailable
639      * @private
640      */
641     handleOnAvailable: function() {
642         this.available = true;
643         this.resetConstraints();
644         this.onAvailable();
645     },
646
647      /**
648      * Configures the padding for the target zone in px.  Effectively expands
649      * (or reduces) the virtual object size for targeting calculations.
650      * Supports css-style shorthand; if only one parameter is passed, all sides
651      * will have that padding, and if only two are passed, the top and bottom
652      * will have the first param, the left and right the second.
653      * @method setPadding
654      * @param {int} iTop    Top pad
655      * @param {int} iRight  Right pad
656      * @param {int} iBot    Bot pad
657      * @param {int} iLeft   Left pad
658      */
659     setPadding: function(iTop, iRight, iBot, iLeft) {
660         // this.padding = [iLeft, iRight, iTop, iBot];
661         if (!iRight && 0 !== iRight) {
662             this.padding = [iTop, iTop, iTop, iTop];
663         } else if (!iBot && 0 !== iBot) {
664             this.padding = [iTop, iRight, iTop, iRight];
665         } else {
666             this.padding = [iTop, iRight, iBot, iLeft];
667         }
668     },
669
670     /**
671      * Stores the initial placement of the linked element.
672      * @method setInitialPosition
673      * @param {int} diffX   the X offset, default 0
674      * @param {int} diffY   the Y offset, default 0
675      */
676     setInitPosition: function(diffX, diffY) {
677         var el = this.getEl();
678
679         if (!this.DDM.verifyEl(el)) {
680             return;
681         }
682
683         var dx = diffX || 0;
684         var dy = diffY || 0;
685
686         var p = Dom.getXY( el );
687
688         this.initPageX = p[0] - dx;
689         this.initPageY = p[1] - dy;
690
691         this.lastPageX = p[0];
692         this.lastPageY = p[1];
693
694
695         this.setStartPosition(p);
696     },
697
698     /**
699      * Sets the start position of the element.  This is set when the obj
700      * is initialized, the reset when a drag is started.
701      * @method setStartPosition
702      * @param pos current position (from previous lookup)
703      * @private
704      */
705     setStartPosition: function(pos) {
706         var p = pos || Dom.getXY( this.getEl() );
707         this.deltaSetXY = null;
708
709         this.startPageX = p[0];
710         this.startPageY = p[1];
711     },
712
713     /**
714      * Add this instance to a group of related drag/drop objects.  All
715      * instances belong to at least one group, and can belong to as many
716      * groups as needed.
717      * @method addToGroup
718      * @param sGroup {string} the name of the group
719      */
720     addToGroup: function(sGroup) {
721         this.groups[sGroup] = true;
722         this.DDM.regDragDrop(this, sGroup);
723     },
724
725     /**
726      * Remove's this instance from the supplied interaction group
727      * @method removeFromGroup
728      * @param {string}  sGroup  The group to drop
729      */
730     removeFromGroup: function(sGroup) {
731         if (this.groups[sGroup]) {
732             delete this.groups[sGroup];
733         }
734
735         this.DDM.removeDDFromGroup(this, sGroup);
736     },
737
738     /**
739      * Allows you to specify that an element other than the linked element
740      * will be moved with the cursor during a drag
741      * @method setDragElId
742      * @param id {string} the id of the element that will be used to initiate the drag
743      */
744     setDragElId: function(id) {
745         this.dragElId = id;
746     },
747
748     /**
749      * Allows you to specify a child of the linked element that should be
750      * used to initiate the drag operation.  An example of this would be if
751      * you have a content div with text and links.  Clicking anywhere in the
752      * content area would normally start the drag operation.  Use this method
753      * to specify that an element inside of the content div is the element
754      * that starts the drag operation.
755      * @method setHandleElId
756      * @param id {string} the id of the element that will be used to
757      * initiate the drag.
758      */
759     setHandleElId: function(id) {
760         if (typeof id !== "string") {
761             id = Roo.id(id);
762         }
763         this.handleElId = id;
764         this.DDM.regHandle(this.id, id);
765     },
766
767     /**
768      * Allows you to set an element outside of the linked element as a drag
769      * handle
770      * @method setOuterHandleElId
771      * @param id the id of the element that will be used to initiate the drag
772      */
773     setOuterHandleElId: function(id) {
774         if (typeof id !== "string") {
775             id = Roo.id(id);
776         }
777         Event.on(id, "mousedown",
778                 this.handleMouseDown, this);
779         this.setHandleElId(id);
780
781         this.hasOuterHandles = true;
782     },
783
784     /**
785      * Remove all drag and drop hooks for this element
786      * @method unreg
787      */
788     unreg: function() {
789         Event.un(this.id, "mousedown",
790                 this.handleMouseDown);
791         this._domRef = null;
792         this.DDM._remove(this);
793     },
794
795     destroy : function(){
796         this.unreg();
797     },
798
799     /**
800      * Returns true if this instance is locked, or the drag drop mgr is locked
801      * (meaning that all drag/drop is disabled on the page.)
802      * @method isLocked
803      * @return {boolean} true if this obj or all drag/drop is locked, else
804      * false
805      */
806     isLocked: function() {
807         return (this.DDM.isLocked() || this.locked);
808     },
809
810     /**
811      * Fired when this object is clicked
812      * @method handleMouseDown
813      * @param {Event} e
814      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
815      * @private
816      */
817     handleMouseDown: function(e, oDD){
818         if (this.primaryButtonOnly && e.button != 0) {
819             return;
820         }
821
822         if (this.isLocked()) {
823             return;
824         }
825
826         this.DDM.refreshCache(this.groups);
827
828         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
829         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
830         } else {
831             if (this.clickValidator(e)) {
832
833                 // set the initial element position
834                 this.setStartPosition();
835
836
837                 this.b4MouseDown(e);
838                 this.onMouseDown(e);
839
840                 this.DDM.handleMouseDown(e, this);
841
842                 this.DDM.stopEvent(e);
843             } else {
844
845
846             }
847         }
848     },
849
850     clickValidator: function(e) {
851         var target = e.getTarget();
852         return ( this.isValidHandleChild(target) &&
853                     (this.id == this.handleElId ||
854                         this.DDM.handleWasClicked(target, this.id)) );
855     },
856
857     /**
858      * Allows you to specify a tag name that should not start a drag operation
859      * when clicked.  This is designed to facilitate embedding links within a
860      * drag handle that do something other than start the drag.
861      * @method addInvalidHandleType
862      * @param {string} tagName the type of element to exclude
863      */
864     addInvalidHandleType: function(tagName) {
865         var type = tagName.toUpperCase();
866         this.invalidHandleTypes[type] = type;
867     },
868
869     /**
870      * Lets you to specify an element id for a child of a drag handle
871      * that should not initiate a drag
872      * @method addInvalidHandleId
873      * @param {string} id the element id of the element you wish to ignore
874      */
875     addInvalidHandleId: function(id) {
876         if (typeof id !== "string") {
877             id = Roo.id(id);
878         }
879         this.invalidHandleIds[id] = id;
880     },
881
882     /**
883      * Lets you specify a css class of elements that will not initiate a drag
884      * @method addInvalidHandleClass
885      * @param {string} cssClass the class of the elements you wish to ignore
886      */
887     addInvalidHandleClass: function(cssClass) {
888         this.invalidHandleClasses.push(cssClass);
889     },
890
891     /**
892      * Unsets an excluded tag name set by addInvalidHandleType
893      * @method removeInvalidHandleType
894      * @param {string} tagName the type of element to unexclude
895      */
896     removeInvalidHandleType: function(tagName) {
897         var type = tagName.toUpperCase();
898         // this.invalidHandleTypes[type] = null;
899         delete this.invalidHandleTypes[type];
900     },
901
902     /**
903      * Unsets an invalid handle id
904      * @method removeInvalidHandleId
905      * @param {string} id the id of the element to re-enable
906      */
907     removeInvalidHandleId: function(id) {
908         if (typeof id !== "string") {
909             id = Roo.id(id);
910         }
911         delete this.invalidHandleIds[id];
912     },
913
914     /**
915      * Unsets an invalid css class
916      * @method removeInvalidHandleClass
917      * @param {string} cssClass the class of the element(s) you wish to
918      * re-enable
919      */
920     removeInvalidHandleClass: function(cssClass) {
921         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
922             if (this.invalidHandleClasses[i] == cssClass) {
923                 delete this.invalidHandleClasses[i];
924             }
925         }
926     },
927
928     /**
929      * Checks the tag exclusion list to see if this click should be ignored
930      * @method isValidHandleChild
931      * @param {HTMLElement} node the HTMLElement to evaluate
932      * @return {boolean} true if this is a valid tag type, false if not
933      */
934     isValidHandleChild: function(node) {
935
936         var valid = true;
937         // var n = (node.nodeName == "#text") ? node.parentNode : node;
938         var nodeName;
939         try {
940             nodeName = node.nodeName.toUpperCase();
941         } catch(e) {
942             nodeName = node.nodeName;
943         }
944         valid = valid && !this.invalidHandleTypes[nodeName];
945         valid = valid && !this.invalidHandleIds[node.id];
946
947         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
948             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
949         }
950
951
952         return valid;
953
954     },
955
956     /**
957      * Create the array of horizontal tick marks if an interval was specified
958      * in setXConstraint().
959      * @method setXTicks
960      * @private
961      */
962     setXTicks: function(iStartX, iTickSize) {
963         this.xTicks = [];
964         this.xTickSize = iTickSize;
965
966         var tickMap = {};
967
968         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
969             if (!tickMap[i]) {
970                 this.xTicks[this.xTicks.length] = i;
971                 tickMap[i] = true;
972             }
973         }
974
975         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
976             if (!tickMap[i]) {
977                 this.xTicks[this.xTicks.length] = i;
978                 tickMap[i] = true;
979             }
980         }
981
982         this.xTicks.sort(this.DDM.numericSort) ;
983     },
984
985     /**
986      * Create the array of vertical tick marks if an interval was specified in
987      * setYConstraint().
988      * @method setYTicks
989      * @private
990      */
991     setYTicks: function(iStartY, iTickSize) {
992         this.yTicks = [];
993         this.yTickSize = iTickSize;
994
995         var tickMap = {};
996
997         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
998             if (!tickMap[i]) {
999                 this.yTicks[this.yTicks.length] = i;
1000                 tickMap[i] = true;
1001             }
1002         }
1003
1004         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1005             if (!tickMap[i]) {
1006                 this.yTicks[this.yTicks.length] = i;
1007                 tickMap[i] = true;
1008             }
1009         }
1010
1011         this.yTicks.sort(this.DDM.numericSort) ;
1012     },
1013
1014     /**
1015      * By default, the element can be dragged any place on the screen.  Use
1016      * this method to limit the horizontal travel of the element.  Pass in
1017      * 0,0 for the parameters if you want to lock the drag to the y axis.
1018      * @method setXConstraint
1019      * @param {int} iLeft the number of pixels the element can move to the left
1020      * @param {int} iRight the number of pixels the element can move to the
1021      * right
1022      * @param {int} iTickSize optional parameter for specifying that the
1023      * element
1024      * should move iTickSize pixels at a time.
1025      */
1026     setXConstraint: function(iLeft, iRight, iTickSize) {
1027         this.leftConstraint = iLeft;
1028         this.rightConstraint = iRight;
1029
1030         this.minX = this.initPageX - iLeft;
1031         this.maxX = this.initPageX + iRight;
1032         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1033
1034         this.constrainX = true;
1035     },
1036
1037     /**
1038      * Clears any constraints applied to this instance.  Also clears ticks
1039      * since they can't exist independent of a constraint at this time.
1040      * @method clearConstraints
1041      */
1042     clearConstraints: function() {
1043         this.constrainX = false;
1044         this.constrainY = false;
1045         this.clearTicks();
1046     },
1047
1048     /**
1049      * Clears any tick interval defined for this instance
1050      * @method clearTicks
1051      */
1052     clearTicks: function() {
1053         this.xTicks = null;
1054         this.yTicks = null;
1055         this.xTickSize = 0;
1056         this.yTickSize = 0;
1057     },
1058
1059     /**
1060      * By default, the element can be dragged any place on the screen.  Set
1061      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1062      * parameters if you want to lock the drag to the x axis.
1063      * @method setYConstraint
1064      * @param {int} iUp the number of pixels the element can move up
1065      * @param {int} iDown the number of pixels the element can move down
1066      * @param {int} iTickSize optional parameter for specifying that the
1067      * element should move iTickSize pixels at a time.
1068      */
1069     setYConstraint: function(iUp, iDown, iTickSize) {
1070         this.topConstraint = iUp;
1071         this.bottomConstraint = iDown;
1072
1073         this.minY = this.initPageY - iUp;
1074         this.maxY = this.initPageY + iDown;
1075         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1076
1077         this.constrainY = true;
1078
1079     },
1080
1081     /**
1082      * resetConstraints must be called if you manually reposition a dd element.
1083      * @method resetConstraints
1084      * @param {boolean} maintainOffset
1085      */
1086     resetConstraints: function() {
1087
1088
1089         // Maintain offsets if necessary
1090         if (this.initPageX || this.initPageX === 0) {
1091             // figure out how much this thing has moved
1092             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1093             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1094
1095             this.setInitPosition(dx, dy);
1096
1097         // This is the first time we have detected the element's position
1098         } else {
1099             this.setInitPosition();
1100         }
1101
1102         if (this.constrainX) {
1103             this.setXConstraint( this.leftConstraint,
1104                                  this.rightConstraint,
1105                                  this.xTickSize        );
1106         }
1107
1108         if (this.constrainY) {
1109             this.setYConstraint( this.topConstraint,
1110                                  this.bottomConstraint,
1111                                  this.yTickSize         );
1112         }
1113     },
1114
1115     /**
1116      * Normally the drag element is moved pixel by pixel, but we can specify
1117      * that it move a number of pixels at a time.  This method resolves the
1118      * location when we have it set up like this.
1119      * @method getTick
1120      * @param {int} val where we want to place the object
1121      * @param {int[]} tickArray sorted array of valid points
1122      * @return {int} the closest tick
1123      * @private
1124      */
1125     getTick: function(val, tickArray) {
1126
1127         if (!tickArray) {
1128             // If tick interval is not defined, it is effectively 1 pixel,
1129             // so we return the value passed to us.
1130             return val;
1131         } else if (tickArray[0] >= val) {
1132             // The value is lower than the first tick, so we return the first
1133             // tick.
1134             return tickArray[0];
1135         } else {
1136             for (var i=0, len=tickArray.length; i<len; ++i) {
1137                 var next = i + 1;
1138                 if (tickArray[next] && tickArray[next] >= val) {
1139                     var diff1 = val - tickArray[i];
1140                     var diff2 = tickArray[next] - val;
1141                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1142                 }
1143             }
1144
1145             // The value is larger than the last tick, so we return the last
1146             // tick.
1147             return tickArray[tickArray.length - 1];
1148         }
1149     },
1150
1151     /**
1152      * toString method
1153      * @method toString
1154      * @return {string} string representation of the dd obj
1155      */
1156     toString: function() {
1157         return ("DragDrop " + this.id);
1158     }
1159
1160 };
1161
1162 })();
1163 /*
1164  * Based on:
1165  * Ext JS Library 1.1.1
1166  * Copyright(c) 2006-2007, Ext JS, LLC.
1167  *
1168  * Originally Released Under LGPL - original licence link has changed is not relivant.
1169  *
1170  * Fork - LGPL
1171  * <script type="text/javascript">
1172  */
1173
1174
1175 /**
1176  * The drag and drop utility provides a framework for building drag and drop
1177  * applications.  In addition to enabling drag and drop for specific elements,
1178  * the drag and drop elements are tracked by the manager class, and the
1179  * interactions between the various elements are tracked during the drag and
1180  * the implementing code is notified about these important moments.
1181  */
1182
1183 // Only load the library once.  Rewriting the manager class would orphan
1184 // existing drag and drop instances.
1185 if (!Roo.dd.DragDropMgr) {
1186
1187 /**
1188  * @class Roo.dd.DragDropMgr
1189  * DragDropMgr is a singleton that tracks the element interaction for
1190  * all DragDrop items in the window.  Generally, you will not call
1191  * this class directly, but it does have helper methods that could
1192  * be useful in your DragDrop implementations.
1193  * @singleton
1194  */
1195 Roo.dd.DragDropMgr = function() {
1196
1197     var Event = Roo.EventManager;
1198
1199     return {
1200
1201         /**
1202          * Two dimensional Array of registered DragDrop objects.  The first
1203          * dimension is the DragDrop item group, the second the DragDrop
1204          * object.
1205          * @property ids
1206          * @type {string: string}
1207          * @private
1208          * @static
1209          */
1210         ids: {},
1211
1212         /**
1213          * Array of element ids defined as drag handles.  Used to determine
1214          * if the element that generated the mousedown event is actually the
1215          * handle and not the html element itself.
1216          * @property handleIds
1217          * @type {string: string}
1218          * @private
1219          * @static
1220          */
1221         handleIds: {},
1222
1223         /**
1224          * the DragDrop object that is currently being dragged
1225          * @property dragCurrent
1226          * @type DragDrop
1227          * @private
1228          * @static
1229          **/
1230         dragCurrent: null,
1231
1232         /**
1233          * the DragDrop object(s) that are being hovered over
1234          * @property dragOvers
1235          * @type Array
1236          * @private
1237          * @static
1238          */
1239         dragOvers: {},
1240
1241         /**
1242          * the X distance between the cursor and the object being dragged
1243          * @property deltaX
1244          * @type int
1245          * @private
1246          * @static
1247          */
1248         deltaX: 0,
1249
1250         /**
1251          * the Y distance between the cursor and the object being dragged
1252          * @property deltaY
1253          * @type int
1254          * @private
1255          * @static
1256          */
1257         deltaY: 0,
1258
1259         /**
1260          * Flag to determine if we should prevent the default behavior of the
1261          * events we define. By default this is true, but this can be set to
1262          * false if you need the default behavior (not recommended)
1263          * @property preventDefault
1264          * @type boolean
1265          * @static
1266          */
1267         preventDefault: true,
1268
1269         /**
1270          * Flag to determine if we should stop the propagation of the events
1271          * we generate. This is true by default but you may want to set it to
1272          * false if the html element contains other features that require the
1273          * mouse click.
1274          * @property stopPropagation
1275          * @type boolean
1276          * @static
1277          */
1278         stopPropagation: true,
1279
1280         /**
1281          * Internal flag that is set to true when drag and drop has been
1282          * intialized
1283          * @property initialized
1284          * @private
1285          * @static
1286          */
1287         initalized: false,
1288
1289         /**
1290          * All drag and drop can be disabled.
1291          * @property locked
1292          * @private
1293          * @static
1294          */
1295         locked: false,
1296
1297         /**
1298          * Called the first time an element is registered.
1299          * @method init
1300          * @private
1301          * @static
1302          */
1303         init: function() {
1304             this.initialized = true;
1305         },
1306
1307         /**
1308          * In point mode, drag and drop interaction is defined by the
1309          * location of the cursor during the drag/drop
1310          * @property POINT
1311          * @type int
1312          * @static
1313          */
1314         POINT: 0,
1315
1316         /**
1317          * In intersect mode, drag and drop interactio nis defined by the
1318          * overlap of two or more drag and drop objects.
1319          * @property INTERSECT
1320          * @type int
1321          * @static
1322          */
1323         INTERSECT: 1,
1324
1325         /**
1326          * The current drag and drop mode.  Default: POINT
1327          * @property mode
1328          * @type int
1329          * @static
1330          */
1331         mode: 0,
1332
1333         /**
1334          * Runs method on all drag and drop objects
1335          * @method _execOnAll
1336          * @private
1337          * @static
1338          */
1339         _execOnAll: function(sMethod, args) {
1340             for (var i in this.ids) {
1341                 for (var j in this.ids[i]) {
1342                     var oDD = this.ids[i][j];
1343                     if (! this.isTypeOfDD(oDD)) {
1344                         continue;
1345                     }
1346                     oDD[sMethod].apply(oDD, args);
1347                 }
1348             }
1349         },
1350
1351         /**
1352          * Drag and drop initialization.  Sets up the global event handlers
1353          * @method _onLoad
1354          * @private
1355          * @static
1356          */
1357         _onLoad: function() {
1358
1359             this.init();
1360
1361
1362             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1363             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1364             Event.on(window,   "unload",    this._onUnload, this, true);
1365             Event.on(window,   "resize",    this._onResize, this, true);
1366             // Event.on(window,   "mouseout",    this._test);
1367
1368         },
1369
1370         /**
1371          * Reset constraints on all drag and drop objs
1372          * @method _onResize
1373          * @private
1374          * @static
1375          */
1376         _onResize: function(e) {
1377             this._execOnAll("resetConstraints", []);
1378         },
1379
1380         /**
1381          * Lock all drag and drop functionality
1382          * @method lock
1383          * @static
1384          */
1385         lock: function() { this.locked = true; },
1386
1387         /**
1388          * Unlock all drag and drop functionality
1389          * @method unlock
1390          * @static
1391          */
1392         unlock: function() { this.locked = false; },
1393
1394         /**
1395          * Is drag and drop locked?
1396          * @method isLocked
1397          * @return {boolean} True if drag and drop is locked, false otherwise.
1398          * @static
1399          */
1400         isLocked: function() { return this.locked; },
1401
1402         /**
1403          * Location cache that is set for all drag drop objects when a drag is
1404          * initiated, cleared when the drag is finished.
1405          * @property locationCache
1406          * @private
1407          * @static
1408          */
1409         locationCache: {},
1410
1411         /**
1412          * Set useCache to false if you want to force object the lookup of each
1413          * drag and drop linked element constantly during a drag.
1414          * @property useCache
1415          * @type boolean
1416          * @static
1417          */
1418         useCache: true,
1419
1420         /**
1421          * The number of pixels that the mouse needs to move after the
1422          * mousedown before the drag is initiated.  Default=3;
1423          * @property clickPixelThresh
1424          * @type int
1425          * @static
1426          */
1427         clickPixelThresh: 3,
1428
1429         /**
1430          * The number of milliseconds after the mousedown event to initiate the
1431          * drag if we don't get a mouseup event. Default=1000
1432          * @property clickTimeThresh
1433          * @type int
1434          * @static
1435          */
1436         clickTimeThresh: 350,
1437
1438         /**
1439          * Flag that indicates that either the drag pixel threshold or the
1440          * mousdown time threshold has been met
1441          * @property dragThreshMet
1442          * @type boolean
1443          * @private
1444          * @static
1445          */
1446         dragThreshMet: false,
1447
1448         /**
1449          * Timeout used for the click time threshold
1450          * @property clickTimeout
1451          * @type Object
1452          * @private
1453          * @static
1454          */
1455         clickTimeout: null,
1456
1457         /**
1458          * The X position of the mousedown event stored for later use when a
1459          * drag threshold is met.
1460          * @property startX
1461          * @type int
1462          * @private
1463          * @static
1464          */
1465         startX: 0,
1466
1467         /**
1468          * The Y position of the mousedown event stored for later use when a
1469          * drag threshold is met.
1470          * @property startY
1471          * @type int
1472          * @private
1473          * @static
1474          */
1475         startY: 0,
1476
1477         /**
1478          * Each DragDrop instance must be registered with the DragDropMgr.
1479          * This is executed in DragDrop.init()
1480          * @method regDragDrop
1481          * @param {DragDrop} oDD the DragDrop object to register
1482          * @param {String} sGroup the name of the group this element belongs to
1483          * @static
1484          */
1485         regDragDrop: function(oDD, sGroup) {
1486             if (!this.initialized) { this.init(); }
1487
1488             if (!this.ids[sGroup]) {
1489                 this.ids[sGroup] = {};
1490             }
1491             this.ids[sGroup][oDD.id] = oDD;
1492         },
1493
1494         /**
1495          * Removes the supplied dd instance from the supplied group. Executed
1496          * by DragDrop.removeFromGroup, so don't call this function directly.
1497          * @method removeDDFromGroup
1498          * @private
1499          * @static
1500          */
1501         removeDDFromGroup: function(oDD, sGroup) {
1502             if (!this.ids[sGroup]) {
1503                 this.ids[sGroup] = {};
1504             }
1505
1506             var obj = this.ids[sGroup];
1507             if (obj && obj[oDD.id]) {
1508                 delete obj[oDD.id];
1509             }
1510         },
1511
1512         /**
1513          * Unregisters a drag and drop item.  This is executed in
1514          * DragDrop.unreg, use that method instead of calling this directly.
1515          * @method _remove
1516          * @private
1517          * @static
1518          */
1519         _remove: function(oDD) {
1520             for (var g in oDD.groups) {
1521                 if (g && this.ids[g][oDD.id]) {
1522                     delete this.ids[g][oDD.id];
1523                 }
1524             }
1525             delete this.handleIds[oDD.id];
1526         },
1527
1528         /**
1529          * Each DragDrop handle element must be registered.  This is done
1530          * automatically when executing DragDrop.setHandleElId()
1531          * @method regHandle
1532          * @param {String} sDDId the DragDrop id this element is a handle for
1533          * @param {String} sHandleId the id of the element that is the drag
1534          * handle
1535          * @static
1536          */
1537         regHandle: function(sDDId, sHandleId) {
1538             if (!this.handleIds[sDDId]) {
1539                 this.handleIds[sDDId] = {};
1540             }
1541             this.handleIds[sDDId][sHandleId] = sHandleId;
1542         },
1543
1544         /**
1545          * Utility function to determine if a given element has been
1546          * registered as a drag drop item.
1547          * @method isDragDrop
1548          * @param {String} id the element id to check
1549          * @return {boolean} true if this element is a DragDrop item,
1550          * false otherwise
1551          * @static
1552          */
1553         isDragDrop: function(id) {
1554             return ( this.getDDById(id) ) ? true : false;
1555         },
1556
1557         /**
1558          * Returns the drag and drop instances that are in all groups the
1559          * passed in instance belongs to.
1560          * @method getRelated
1561          * @param {DragDrop} p_oDD the obj to get related data for
1562          * @param {boolean} bTargetsOnly if true, only return targetable objs
1563          * @return {DragDrop[]} the related instances
1564          * @static
1565          */
1566         getRelated: function(p_oDD, bTargetsOnly) {
1567             var oDDs = [];
1568             for (var i in p_oDD.groups) {
1569                 for (j in this.ids[i]) {
1570                     var dd = this.ids[i][j];
1571                     if (! this.isTypeOfDD(dd)) {
1572                         continue;
1573                     }
1574                     if (!bTargetsOnly || dd.isTarget) {
1575                         oDDs[oDDs.length] = dd;
1576                     }
1577                 }
1578             }
1579
1580             return oDDs;
1581         },
1582
1583         /**
1584          * Returns true if the specified dd target is a legal target for
1585          * the specifice drag obj
1586          * @method isLegalTarget
1587          * @param {DragDrop} the drag obj
1588          * @param {DragDrop} the target
1589          * @return {boolean} true if the target is a legal target for the
1590          * dd obj
1591          * @static
1592          */
1593         isLegalTarget: function (oDD, oTargetDD) {
1594             var targets = this.getRelated(oDD, true);
1595             for (var i=0, len=targets.length;i<len;++i) {
1596                 if (targets[i].id == oTargetDD.id) {
1597                     return true;
1598                 }
1599             }
1600
1601             return false;
1602         },
1603
1604         /**
1605          * My goal is to be able to transparently determine if an object is
1606          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1607          * returns "object", oDD.constructor.toString() always returns
1608          * "DragDrop" and not the name of the subclass.  So for now it just
1609          * evaluates a well-known variable in DragDrop.
1610          * @method isTypeOfDD
1611          * @param {Object} the object to evaluate
1612          * @return {boolean} true if typeof oDD = DragDrop
1613          * @static
1614          */
1615         isTypeOfDD: function (oDD) {
1616             return (oDD && oDD.__ygDragDrop);
1617         },
1618
1619         /**
1620          * Utility function to determine if a given element has been
1621          * registered as a drag drop handle for the given Drag Drop object.
1622          * @method isHandle
1623          * @param {String} id the element id to check
1624          * @return {boolean} true if this element is a DragDrop handle, false
1625          * otherwise
1626          * @static
1627          */
1628         isHandle: function(sDDId, sHandleId) {
1629             return ( this.handleIds[sDDId] &&
1630                             this.handleIds[sDDId][sHandleId] );
1631         },
1632
1633         /**
1634          * Returns the DragDrop instance for a given id
1635          * @method getDDById
1636          * @param {String} id the id of the DragDrop object
1637          * @return {DragDrop} the drag drop object, null if it is not found
1638          * @static
1639          */
1640         getDDById: function(id) {
1641             for (var i in this.ids) {
1642                 if (this.ids[i][id]) {
1643                     return this.ids[i][id];
1644                 }
1645             }
1646             return null;
1647         },
1648
1649         /**
1650          * Fired after a registered DragDrop object gets the mousedown event.
1651          * Sets up the events required to track the object being dragged
1652          * @method handleMouseDown
1653          * @param {Event} e the event
1654          * @param oDD the DragDrop object being dragged
1655          * @private
1656          * @static
1657          */
1658         handleMouseDown: function(e, oDD) {
1659             if(Roo.QuickTips){
1660                 Roo.QuickTips.disable();
1661             }
1662             this.currentTarget = e.getTarget();
1663
1664             this.dragCurrent = oDD;
1665
1666             var el = oDD.getEl();
1667
1668             // track start position
1669             this.startX = e.getPageX();
1670             this.startY = e.getPageY();
1671
1672             this.deltaX = this.startX - el.offsetLeft;
1673             this.deltaY = this.startY - el.offsetTop;
1674
1675             this.dragThreshMet = false;
1676
1677             this.clickTimeout = setTimeout(
1678                     function() {
1679                         var DDM = Roo.dd.DDM;
1680                         DDM.startDrag(DDM.startX, DDM.startY);
1681                     },
1682                     this.clickTimeThresh );
1683         },
1684
1685         /**
1686          * Fired when either the drag pixel threshol or the mousedown hold
1687          * time threshold has been met.
1688          * @method startDrag
1689          * @param x {int} the X position of the original mousedown
1690          * @param y {int} the Y position of the original mousedown
1691          * @static
1692          */
1693         startDrag: function(x, y) {
1694             clearTimeout(this.clickTimeout);
1695             if (this.dragCurrent) {
1696                 this.dragCurrent.b4StartDrag(x, y);
1697                 this.dragCurrent.startDrag(x, y);
1698             }
1699             this.dragThreshMet = true;
1700         },
1701
1702         /**
1703          * Internal function to handle the mouseup event.  Will be invoked
1704          * from the context of the document.
1705          * @method handleMouseUp
1706          * @param {Event} e the event
1707          * @private
1708          * @static
1709          */
1710         handleMouseUp: function(e) {
1711
1712             if(Roo.QuickTips){
1713                 Roo.QuickTips.enable();
1714             }
1715             if (! this.dragCurrent) {
1716                 return;
1717             }
1718
1719             clearTimeout(this.clickTimeout);
1720
1721             if (this.dragThreshMet) {
1722                 this.fireEvents(e, true);
1723             } else {
1724             }
1725
1726             this.stopDrag(e);
1727
1728             this.stopEvent(e);
1729         },
1730
1731         /**
1732          * Utility to stop event propagation and event default, if these
1733          * features are turned on.
1734          * @method stopEvent
1735          * @param {Event} e the event as returned by this.getEvent()
1736          * @static
1737          */
1738         stopEvent: function(e){
1739             if(this.stopPropagation) {
1740                 e.stopPropagation();
1741             }
1742
1743             if (this.preventDefault) {
1744                 e.preventDefault();
1745             }
1746         },
1747
1748         /**
1749          * Internal function to clean up event handlers after the drag
1750          * operation is complete
1751          * @method stopDrag
1752          * @param {Event} e the event
1753          * @private
1754          * @static
1755          */
1756         stopDrag: function(e) {
1757             // Fire the drag end event for the item that was dragged
1758             if (this.dragCurrent) {
1759                 if (this.dragThreshMet) {
1760                     this.dragCurrent.b4EndDrag(e);
1761                     this.dragCurrent.endDrag(e);
1762                 }
1763
1764                 this.dragCurrent.onMouseUp(e);
1765             }
1766
1767             this.dragCurrent = null;
1768             this.dragOvers = {};
1769         },
1770
1771         /**
1772          * Internal function to handle the mousemove event.  Will be invoked
1773          * from the context of the html element.
1774          *
1775          * @TODO figure out what we can do about mouse events lost when the
1776          * user drags objects beyond the window boundary.  Currently we can
1777          * detect this in internet explorer by verifying that the mouse is
1778          * down during the mousemove event.  Firefox doesn't give us the
1779          * button state on the mousemove event.
1780          * @method handleMouseMove
1781          * @param {Event} e the event
1782          * @private
1783          * @static
1784          */
1785         handleMouseMove: function(e) {
1786             if (! this.dragCurrent) {
1787                 return true;
1788             }
1789
1790             // var button = e.which || e.button;
1791
1792             // check for IE mouseup outside of page boundary
1793             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1794                 this.stopEvent(e);
1795                 return this.handleMouseUp(e);
1796             }
1797
1798             if (!this.dragThreshMet) {
1799                 var diffX = Math.abs(this.startX - e.getPageX());
1800                 var diffY = Math.abs(this.startY - e.getPageY());
1801                 if (diffX > this.clickPixelThresh ||
1802                             diffY > this.clickPixelThresh) {
1803                     this.startDrag(this.startX, this.startY);
1804                 }
1805             }
1806
1807             if (this.dragThreshMet) {
1808                 this.dragCurrent.b4Drag(e);
1809                 this.dragCurrent.onDrag(e);
1810                 if(!this.dragCurrent.moveOnly){
1811                     this.fireEvents(e, false);
1812                 }
1813             }
1814
1815             this.stopEvent(e);
1816
1817             return true;
1818         },
1819
1820         /**
1821          * Iterates over all of the DragDrop elements to find ones we are
1822          * hovering over or dropping on
1823          * @method fireEvents
1824          * @param {Event} e the event
1825          * @param {boolean} isDrop is this a drop op or a mouseover op?
1826          * @private
1827          * @static
1828          */
1829         fireEvents: function(e, isDrop) {
1830             var dc = this.dragCurrent;
1831
1832             // If the user did the mouse up outside of the window, we could
1833             // get here even though we have ended the drag.
1834             if (!dc || dc.isLocked()) {
1835                 return;
1836             }
1837
1838             var pt = e.getPoint();
1839
1840             // cache the previous dragOver array
1841             var oldOvers = [];
1842
1843             var outEvts   = [];
1844             var overEvts  = [];
1845             var dropEvts  = [];
1846             var enterEvts = [];
1847
1848             // Check to see if the object(s) we were hovering over is no longer
1849             // being hovered over so we can fire the onDragOut event
1850             for (var i in this.dragOvers) {
1851
1852                 var ddo = this.dragOvers[i];
1853
1854                 if (! this.isTypeOfDD(ddo)) {
1855                     continue;
1856                 }
1857
1858                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1859                     outEvts.push( ddo );
1860                 }
1861
1862                 oldOvers[i] = true;
1863                 delete this.dragOvers[i];
1864             }
1865
1866             for (var sGroup in dc.groups) {
1867
1868                 if ("string" != typeof sGroup) {
1869                     continue;
1870                 }
1871
1872                 for (i in this.ids[sGroup]) {
1873                     var oDD = this.ids[sGroup][i];
1874                     if (! this.isTypeOfDD(oDD)) {
1875                         continue;
1876                     }
1877
1878                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1879                         if (this.isOverTarget(pt, oDD, this.mode)) {
1880                             // look for drop interactions
1881                             if (isDrop) {
1882                                 dropEvts.push( oDD );
1883                             // look for drag enter and drag over interactions
1884                             } else {
1885
1886                                 // initial drag over: dragEnter fires
1887                                 if (!oldOvers[oDD.id]) {
1888                                     enterEvts.push( oDD );
1889                                 // subsequent drag overs: dragOver fires
1890                                 } else {
1891                                     overEvts.push( oDD );
1892                                 }
1893
1894                                 this.dragOvers[oDD.id] = oDD;
1895                             }
1896                         }
1897                     }
1898                 }
1899             }
1900
1901             if (this.mode) {
1902                 if (outEvts.length) {
1903                     dc.b4DragOut(e, outEvts);
1904                     dc.onDragOut(e, outEvts);
1905                 }
1906
1907                 if (enterEvts.length) {
1908                     dc.onDragEnter(e, enterEvts);
1909                 }
1910
1911                 if (overEvts.length) {
1912                     dc.b4DragOver(e, overEvts);
1913                     dc.onDragOver(e, overEvts);
1914                 }
1915
1916                 if (dropEvts.length) {
1917                     dc.b4DragDrop(e, dropEvts);
1918                     dc.onDragDrop(e, dropEvts);
1919                 }
1920
1921             } else {
1922                 // fire dragout events
1923                 var len = 0;
1924                 for (i=0, len=outEvts.length; i<len; ++i) {
1925                     dc.b4DragOut(e, outEvts[i].id);
1926                     dc.onDragOut(e, outEvts[i].id);
1927                 }
1928
1929                 // fire enter events
1930                 for (i=0,len=enterEvts.length; i<len; ++i) {
1931                     // dc.b4DragEnter(e, oDD.id);
1932                     dc.onDragEnter(e, enterEvts[i].id);
1933                 }
1934
1935                 // fire over events
1936                 for (i=0,len=overEvts.length; i<len; ++i) {
1937                     dc.b4DragOver(e, overEvts[i].id);
1938                     dc.onDragOver(e, overEvts[i].id);
1939                 }
1940
1941                 // fire drop events
1942                 for (i=0, len=dropEvts.length; i<len; ++i) {
1943                     dc.b4DragDrop(e, dropEvts[i].id);
1944                     dc.onDragDrop(e, dropEvts[i].id);
1945                 }
1946
1947             }
1948
1949             // notify about a drop that did not find a target
1950             if (isDrop && !dropEvts.length) {
1951                 dc.onInvalidDrop(e);
1952             }
1953
1954         },
1955
1956         /**
1957          * Helper function for getting the best match from the list of drag
1958          * and drop objects returned by the drag and drop events when we are
1959          * in INTERSECT mode.  It returns either the first object that the
1960          * cursor is over, or the object that has the greatest overlap with
1961          * the dragged element.
1962          * @method getBestMatch
1963          * @param  {DragDrop[]} dds The array of drag and drop objects
1964          * targeted
1965          * @return {DragDrop}       The best single match
1966          * @static
1967          */
1968         getBestMatch: function(dds) {
1969             var winner = null;
1970             // Return null if the input is not what we expect
1971             //if (!dds || !dds.length || dds.length == 0) {
1972                // winner = null;
1973             // If there is only one item, it wins
1974             //} else if (dds.length == 1) {
1975
1976             var len = dds.length;
1977
1978             if (len == 1) {
1979                 winner = dds[0];
1980             } else {
1981                 // Loop through the targeted items
1982                 for (var i=0; i<len; ++i) {
1983                     var dd = dds[i];
1984                     // If the cursor is over the object, it wins.  If the
1985                     // cursor is over multiple matches, the first one we come
1986                     // to wins.
1987                     if (dd.cursorIsOver) {
1988                         winner = dd;
1989                         break;
1990                     // Otherwise the object with the most overlap wins
1991                     } else {
1992                         if (!winner ||
1993                             winner.overlap.getArea() < dd.overlap.getArea()) {
1994                             winner = dd;
1995                         }
1996                     }
1997                 }
1998             }
1999
2000             return winner;
2001         },
2002
2003         /**
2004          * Refreshes the cache of the top-left and bottom-right points of the
2005          * drag and drop objects in the specified group(s).  This is in the
2006          * format that is stored in the drag and drop instance, so typical
2007          * usage is:
2008          * <code>
2009          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2010          * </code>
2011          * Alternatively:
2012          * <code>
2013          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2014          * </code>
2015          * @TODO this really should be an indexed array.  Alternatively this
2016          * method could accept both.
2017          * @method refreshCache
2018          * @param {Object} groups an associative array of groups to refresh
2019          * @static
2020          */
2021         refreshCache: function(groups) {
2022             for (var sGroup in groups) {
2023                 if ("string" != typeof sGroup) {
2024                     continue;
2025                 }
2026                 for (var i in this.ids[sGroup]) {
2027                     var oDD = this.ids[sGroup][i];
2028
2029                     if (this.isTypeOfDD(oDD)) {
2030                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2031                         var loc = this.getLocation(oDD);
2032                         if (loc) {
2033                             this.locationCache[oDD.id] = loc;
2034                         } else {
2035                             delete this.locationCache[oDD.id];
2036                             // this will unregister the drag and drop object if
2037                             // the element is not in a usable state
2038                             // oDD.unreg();
2039                         }
2040                     }
2041                 }
2042             }
2043         },
2044
2045         /**
2046          * This checks to make sure an element exists and is in the DOM.  The
2047          * main purpose is to handle cases where innerHTML is used to remove
2048          * drag and drop objects from the DOM.  IE provides an 'unspecified
2049          * error' when trying to access the offsetParent of such an element
2050          * @method verifyEl
2051          * @param {HTMLElement} el the element to check
2052          * @return {boolean} true if the element looks usable
2053          * @static
2054          */
2055         verifyEl: function(el) {
2056             if (el) {
2057                 var parent;
2058                 if(Roo.isIE){
2059                     try{
2060                         parent = el.offsetParent;
2061                     }catch(e){}
2062                 }else{
2063                     parent = el.offsetParent;
2064                 }
2065                 if (parent) {
2066                     return true;
2067                 }
2068             }
2069
2070             return false;
2071         },
2072
2073         /**
2074          * Returns a Region object containing the drag and drop element's position
2075          * and size, including the padding configured for it
2076          * @method getLocation
2077          * @param {DragDrop} oDD the drag and drop object to get the
2078          *                       location for
2079          * @return {Roo.lib.Region} a Region object representing the total area
2080          *                             the element occupies, including any padding
2081          *                             the instance is configured for.
2082          * @static
2083          */
2084         getLocation: function(oDD) {
2085             if (! this.isTypeOfDD(oDD)) {
2086                 return null;
2087             }
2088
2089             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2090
2091             try {
2092                 pos= Roo.lib.Dom.getXY(el);
2093             } catch (e) { }
2094
2095             if (!pos) {
2096                 return null;
2097             }
2098
2099             x1 = pos[0];
2100             x2 = x1 + el.offsetWidth;
2101             y1 = pos[1];
2102             y2 = y1 + el.offsetHeight;
2103
2104             t = y1 - oDD.padding[0];
2105             r = x2 + oDD.padding[1];
2106             b = y2 + oDD.padding[2];
2107             l = x1 - oDD.padding[3];
2108
2109             return new Roo.lib.Region( t, r, b, l );
2110         },
2111
2112         /**
2113          * Checks the cursor location to see if it over the target
2114          * @method isOverTarget
2115          * @param {Roo.lib.Point} pt The point to evaluate
2116          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2117          * @return {boolean} true if the mouse is over the target
2118          * @private
2119          * @static
2120          */
2121         isOverTarget: function(pt, oTarget, intersect) {
2122             // use cache if available
2123             var loc = this.locationCache[oTarget.id];
2124             if (!loc || !this.useCache) {
2125                 loc = this.getLocation(oTarget);
2126                 this.locationCache[oTarget.id] = loc;
2127
2128             }
2129
2130             if (!loc) {
2131                 return false;
2132             }
2133
2134             oTarget.cursorIsOver = loc.contains( pt );
2135
2136             // DragDrop is using this as a sanity check for the initial mousedown
2137             // in this case we are done.  In POINT mode, if the drag obj has no
2138             // contraints, we are also done. Otherwise we need to evaluate the
2139             // location of the target as related to the actual location of the
2140             // dragged element.
2141             var dc = this.dragCurrent;
2142             if (!dc || !dc.getTargetCoord ||
2143                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2144                 return oTarget.cursorIsOver;
2145             }
2146
2147             oTarget.overlap = null;
2148
2149             // Get the current location of the drag element, this is the
2150             // location of the mouse event less the delta that represents
2151             // where the original mousedown happened on the element.  We
2152             // need to consider constraints and ticks as well.
2153             var pos = dc.getTargetCoord(pt.x, pt.y);
2154
2155             var el = dc.getDragEl();
2156             var curRegion = new Roo.lib.Region( pos.y,
2157                                                    pos.x + el.offsetWidth,
2158                                                    pos.y + el.offsetHeight,
2159                                                    pos.x );
2160
2161             var overlap = curRegion.intersect(loc);
2162
2163             if (overlap) {
2164                 oTarget.overlap = overlap;
2165                 return (intersect) ? true : oTarget.cursorIsOver;
2166             } else {
2167                 return false;
2168             }
2169         },
2170
2171         /**
2172          * unload event handler
2173          * @method _onUnload
2174          * @private
2175          * @static
2176          */
2177         _onUnload: function(e, me) {
2178             Roo.dd.DragDropMgr.unregAll();
2179         },
2180
2181         /**
2182          * Cleans up the drag and drop events and objects.
2183          * @method unregAll
2184          * @private
2185          * @static
2186          */
2187         unregAll: function() {
2188
2189             if (this.dragCurrent) {
2190                 this.stopDrag();
2191                 this.dragCurrent = null;
2192             }
2193
2194             this._execOnAll("unreg", []);
2195
2196             for (i in this.elementCache) {
2197                 delete this.elementCache[i];
2198             }
2199
2200             this.elementCache = {};
2201             this.ids = {};
2202         },
2203
2204         /**
2205          * A cache of DOM elements
2206          * @property elementCache
2207          * @private
2208          * @static
2209          */
2210         elementCache: {},
2211
2212         /**
2213          * Get the wrapper for the DOM element specified
2214          * @method getElWrapper
2215          * @param {String} id the id of the element to get
2216          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2217          * @private
2218          * @deprecated This wrapper isn't that useful
2219          * @static
2220          */
2221         getElWrapper: function(id) {
2222             var oWrapper = this.elementCache[id];
2223             if (!oWrapper || !oWrapper.el) {
2224                 oWrapper = this.elementCache[id] =
2225                     new this.ElementWrapper(Roo.getDom(id));
2226             }
2227             return oWrapper;
2228         },
2229
2230         /**
2231          * Returns the actual DOM element
2232          * @method getElement
2233          * @param {String} id the id of the elment to get
2234          * @return {Object} The element
2235          * @deprecated use Roo.getDom instead
2236          * @static
2237          */
2238         getElement: function(id) {
2239             return Roo.getDom(id);
2240         },
2241
2242         /**
2243          * Returns the style property for the DOM element (i.e.,
2244          * document.getElById(id).style)
2245          * @method getCss
2246          * @param {String} id the id of the elment to get
2247          * @return {Object} The style property of the element
2248          * @deprecated use Roo.getDom instead
2249          * @static
2250          */
2251         getCss: function(id) {
2252             var el = Roo.getDom(id);
2253             return (el) ? el.style : null;
2254         },
2255
2256         /**
2257          * Inner class for cached elements
2258          * @class DragDropMgr.ElementWrapper
2259          * @for DragDropMgr
2260          * @private
2261          * @deprecated
2262          */
2263         ElementWrapper: function(el) {
2264                 /**
2265                  * The element
2266                  * @property el
2267                  */
2268                 this.el = el || null;
2269                 /**
2270                  * The element id
2271                  * @property id
2272                  */
2273                 this.id = this.el && el.id;
2274                 /**
2275                  * A reference to the style property
2276                  * @property css
2277                  */
2278                 this.css = this.el && el.style;
2279             },
2280
2281         /**
2282          * Returns the X position of an html element
2283          * @method getPosX
2284          * @param el the element for which to get the position
2285          * @return {int} the X coordinate
2286          * @for DragDropMgr
2287          * @deprecated use Roo.lib.Dom.getX instead
2288          * @static
2289          */
2290         getPosX: function(el) {
2291             return Roo.lib.Dom.getX(el);
2292         },
2293
2294         /**
2295          * Returns the Y position of an html element
2296          * @method getPosY
2297          * @param el the element for which to get the position
2298          * @return {int} the Y coordinate
2299          * @deprecated use Roo.lib.Dom.getY instead
2300          * @static
2301          */
2302         getPosY: function(el) {
2303             return Roo.lib.Dom.getY(el);
2304         },
2305
2306         /**
2307          * Swap two nodes.  In IE, we use the native method, for others we
2308          * emulate the IE behavior
2309          * @method swapNode
2310          * @param n1 the first node to swap
2311          * @param n2 the other node to swap
2312          * @static
2313          */
2314         swapNode: function(n1, n2) {
2315             if (n1.swapNode) {
2316                 n1.swapNode(n2);
2317             } else {
2318                 var p = n2.parentNode;
2319                 var s = n2.nextSibling;
2320
2321                 if (s == n1) {
2322                     p.insertBefore(n1, n2);
2323                 } else if (n2 == n1.nextSibling) {
2324                     p.insertBefore(n2, n1);
2325                 } else {
2326                     n1.parentNode.replaceChild(n2, n1);
2327                     p.insertBefore(n1, s);
2328                 }
2329             }
2330         },
2331
2332         /**
2333          * Returns the current scroll position
2334          * @method getScroll
2335          * @private
2336          * @static
2337          */
2338         getScroll: function () {
2339             var t, l, dde=document.documentElement, db=document.body;
2340             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2341                 t = dde.scrollTop;
2342                 l = dde.scrollLeft;
2343             } else if (db) {
2344                 t = db.scrollTop;
2345                 l = db.scrollLeft;
2346             } else {
2347
2348             }
2349             return { top: t, left: l };
2350         },
2351
2352         /**
2353          * Returns the specified element style property
2354          * @method getStyle
2355          * @param {HTMLElement} el          the element
2356          * @param {string}      styleProp   the style property
2357          * @return {string} The value of the style property
2358          * @deprecated use Roo.lib.Dom.getStyle
2359          * @static
2360          */
2361         getStyle: function(el, styleProp) {
2362             return Roo.fly(el).getStyle(styleProp);
2363         },
2364
2365         /**
2366          * Gets the scrollTop
2367          * @method getScrollTop
2368          * @return {int} the document's scrollTop
2369          * @static
2370          */
2371         getScrollTop: function () { return this.getScroll().top; },
2372
2373         /**
2374          * Gets the scrollLeft
2375          * @method getScrollLeft
2376          * @return {int} the document's scrollTop
2377          * @static
2378          */
2379         getScrollLeft: function () { return this.getScroll().left; },
2380
2381         /**
2382          * Sets the x/y position of an element to the location of the
2383          * target element.
2384          * @method moveToEl
2385          * @param {HTMLElement} moveEl      The element to move
2386          * @param {HTMLElement} targetEl    The position reference element
2387          * @static
2388          */
2389         moveToEl: function (moveEl, targetEl) {
2390             var aCoord = Roo.lib.Dom.getXY(targetEl);
2391             Roo.lib.Dom.setXY(moveEl, aCoord);
2392         },
2393
2394         /**
2395          * Numeric array sort function
2396          * @method numericSort
2397          * @static
2398          */
2399         numericSort: function(a, b) { return (a - b); },
2400
2401         /**
2402          * Internal counter
2403          * @property _timeoutCount
2404          * @private
2405          * @static
2406          */
2407         _timeoutCount: 0,
2408
2409         /**
2410          * Trying to make the load order less important.  Without this we get
2411          * an error if this file is loaded before the Event Utility.
2412          * @method _addListeners
2413          * @private
2414          * @static
2415          */
2416         _addListeners: function() {
2417             var DDM = Roo.dd.DDM;
2418             if ( Roo.lib.Event && document ) {
2419                 DDM._onLoad();
2420             } else {
2421                 if (DDM._timeoutCount > 2000) {
2422                 } else {
2423                     setTimeout(DDM._addListeners, 10);
2424                     if (document && document.body) {
2425                         DDM._timeoutCount += 1;
2426                     }
2427                 }
2428             }
2429         },
2430
2431         /**
2432          * Recursively searches the immediate parent and all child nodes for
2433          * the handle element in order to determine wheter or not it was
2434          * clicked.
2435          * @method handleWasClicked
2436          * @param node the html element to inspect
2437          * @static
2438          */
2439         handleWasClicked: function(node, id) {
2440             if (this.isHandle(id, node.id)) {
2441                 return true;
2442             } else {
2443                 // check to see if this is a text node child of the one we want
2444                 var p = node.parentNode;
2445
2446                 while (p) {
2447                     if (this.isHandle(id, p.id)) {
2448                         return true;
2449                     } else {
2450                         p = p.parentNode;
2451                     }
2452                 }
2453             }
2454
2455             return false;
2456         }
2457
2458     };
2459
2460 }();
2461
2462 // shorter alias, save a few bytes
2463 Roo.dd.DDM = Roo.dd.DragDropMgr;
2464 Roo.dd.DDM._addListeners();
2465
2466 }/*
2467  * Based on:
2468  * Ext JS Library 1.1.1
2469  * Copyright(c) 2006-2007, Ext JS, LLC.
2470  *
2471  * Originally Released Under LGPL - original licence link has changed is not relivant.
2472  *
2473  * Fork - LGPL
2474  * <script type="text/javascript">
2475  */
2476
2477 /**
2478  * @class Roo.dd.DD
2479  * A DragDrop implementation where the linked element follows the
2480  * mouse cursor during a drag.
2481  * @extends Roo.dd.DragDrop
2482  * @constructor
2483  * @param {String} id the id of the linked element
2484  * @param {String} sGroup the group of related DragDrop items
2485  * @param {object} config an object containing configurable attributes
2486  *                Valid properties for DD:
2487  *                    scroll
2488  */
2489 Roo.dd.DD = function(id, sGroup, config) {
2490     if (id) {
2491         this.init(id, sGroup, config);
2492     }
2493 };
2494
2495 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2496
2497     /**
2498      * When set to true, the utility automatically tries to scroll the browser
2499      * window wehn a drag and drop element is dragged near the viewport boundary.
2500      * Defaults to true.
2501      * @property scroll
2502      * @type boolean
2503      */
2504     scroll: true,
2505
2506     /**
2507      * Sets the pointer offset to the distance between the linked element's top
2508      * left corner and the location the element was clicked
2509      * @method autoOffset
2510      * @param {int} iPageX the X coordinate of the click
2511      * @param {int} iPageY the Y coordinate of the click
2512      */
2513     autoOffset: function(iPageX, iPageY) {
2514         var x = iPageX - this.startPageX;
2515         var y = iPageY - this.startPageY;
2516         this.setDelta(x, y);
2517     },
2518
2519     /**
2520      * Sets the pointer offset.  You can call this directly to force the
2521      * offset to be in a particular location (e.g., pass in 0,0 to set it
2522      * to the center of the object)
2523      * @method setDelta
2524      * @param {int} iDeltaX the distance from the left
2525      * @param {int} iDeltaY the distance from the top
2526      */
2527     setDelta: function(iDeltaX, iDeltaY) {
2528         this.deltaX = iDeltaX;
2529         this.deltaY = iDeltaY;
2530     },
2531
2532     /**
2533      * Sets the drag element to the location of the mousedown or click event,
2534      * maintaining the cursor location relative to the location on the element
2535      * that was clicked.  Override this if you want to place the element in a
2536      * location other than where the cursor is.
2537      * @method setDragElPos
2538      * @param {int} iPageX the X coordinate of the mousedown or drag event
2539      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2540      */
2541     setDragElPos: function(iPageX, iPageY) {
2542         // the first time we do this, we are going to check to make sure
2543         // the element has css positioning
2544
2545         var el = this.getDragEl();
2546         this.alignElWithMouse(el, iPageX, iPageY);
2547     },
2548
2549     /**
2550      * Sets the element to the location of the mousedown or click event,
2551      * maintaining the cursor location relative to the location on the element
2552      * that was clicked.  Override this if you want to place the element in a
2553      * location other than where the cursor is.
2554      * @method alignElWithMouse
2555      * @param {HTMLElement} el the element to move
2556      * @param {int} iPageX the X coordinate of the mousedown or drag event
2557      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2558      */
2559     alignElWithMouse: function(el, iPageX, iPageY) {
2560         var oCoord = this.getTargetCoord(iPageX, iPageY);
2561         var fly = el.dom ? el : Roo.fly(el);
2562         if (!this.deltaSetXY) {
2563             var aCoord = [oCoord.x, oCoord.y];
2564             fly.setXY(aCoord);
2565             var newLeft = fly.getLeft(true);
2566             var newTop  = fly.getTop(true);
2567             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2568         } else {
2569             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2570         }
2571
2572         this.cachePosition(oCoord.x, oCoord.y);
2573         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2574         return oCoord;
2575     },
2576
2577     /**
2578      * Saves the most recent position so that we can reset the constraints and
2579      * tick marks on-demand.  We need to know this so that we can calculate the
2580      * number of pixels the element is offset from its original position.
2581      * @method cachePosition
2582      * @param iPageX the current x position (optional, this just makes it so we
2583      * don't have to look it up again)
2584      * @param iPageY the current y position (optional, this just makes it so we
2585      * don't have to look it up again)
2586      */
2587     cachePosition: function(iPageX, iPageY) {
2588         if (iPageX) {
2589             this.lastPageX = iPageX;
2590             this.lastPageY = iPageY;
2591         } else {
2592             var aCoord = Roo.lib.Dom.getXY(this.getEl());
2593             this.lastPageX = aCoord[0];
2594             this.lastPageY = aCoord[1];
2595         }
2596     },
2597
2598     /**
2599      * Auto-scroll the window if the dragged object has been moved beyond the
2600      * visible window boundary.
2601      * @method autoScroll
2602      * @param {int} x the drag element's x position
2603      * @param {int} y the drag element's y position
2604      * @param {int} h the height of the drag element
2605      * @param {int} w the width of the drag element
2606      * @private
2607      */
2608     autoScroll: function(x, y, h, w) {
2609
2610         if (this.scroll) {
2611             // The client height
2612             var clientH = Roo.lib.Dom.getViewWidth();
2613
2614             // The client width
2615             var clientW = Roo.lib.Dom.getViewHeight();
2616
2617             // The amt scrolled down
2618             var st = this.DDM.getScrollTop();
2619
2620             // The amt scrolled right
2621             var sl = this.DDM.getScrollLeft();
2622
2623             // Location of the bottom of the element
2624             var bot = h + y;
2625
2626             // Location of the right of the element
2627             var right = w + x;
2628
2629             // The distance from the cursor to the bottom of the visible area,
2630             // adjusted so that we don't scroll if the cursor is beyond the
2631             // element drag constraints
2632             var toBot = (clientH + st - y - this.deltaY);
2633
2634             // The distance from the cursor to the right of the visible area
2635             var toRight = (clientW + sl - x - this.deltaX);
2636
2637
2638             // How close to the edge the cursor must be before we scroll
2639             // var thresh = (document.all) ? 100 : 40;
2640             var thresh = 40;
2641
2642             // How many pixels to scroll per autoscroll op.  This helps to reduce
2643             // clunky scrolling. IE is more sensitive about this ... it needs this
2644             // value to be higher.
2645             var scrAmt = (document.all) ? 80 : 30;
2646
2647             // Scroll down if we are near the bottom of the visible page and the
2648             // obj extends below the crease
2649             if ( bot > clientH && toBot < thresh ) {
2650                 window.scrollTo(sl, st + scrAmt);
2651             }
2652
2653             // Scroll up if the window is scrolled down and the top of the object
2654             // goes above the top border
2655             if ( y < st && st > 0 && y - st < thresh ) {
2656                 window.scrollTo(sl, st - scrAmt);
2657             }
2658
2659             // Scroll right if the obj is beyond the right border and the cursor is
2660             // near the border.
2661             if ( right > clientW && toRight < thresh ) {
2662                 window.scrollTo(sl + scrAmt, st);
2663             }
2664
2665             // Scroll left if the window has been scrolled to the right and the obj
2666             // extends past the left border
2667             if ( x < sl && sl > 0 && x - sl < thresh ) {
2668                 window.scrollTo(sl - scrAmt, st);
2669             }
2670         }
2671     },
2672
2673     /**
2674      * Finds the location the element should be placed if we want to move
2675      * it to where the mouse location less the click offset would place us.
2676      * @method getTargetCoord
2677      * @param {int} iPageX the X coordinate of the click
2678      * @param {int} iPageY the Y coordinate of the click
2679      * @return an object that contains the coordinates (Object.x and Object.y)
2680      * @private
2681      */
2682     getTargetCoord: function(iPageX, iPageY) {
2683
2684
2685         var x = iPageX - this.deltaX;
2686         var y = iPageY - this.deltaY;
2687
2688         if (this.constrainX) {
2689             if (x < this.minX) { x = this.minX; }
2690             if (x > this.maxX) { x = this.maxX; }
2691         }
2692
2693         if (this.constrainY) {
2694             if (y < this.minY) { y = this.minY; }
2695             if (y > this.maxY) { y = this.maxY; }
2696         }
2697
2698         x = this.getTick(x, this.xTicks);
2699         y = this.getTick(y, this.yTicks);
2700
2701
2702         return {x:x, y:y};
2703     },
2704
2705     /*
2706      * Sets up config options specific to this class. Overrides
2707      * Roo.dd.DragDrop, but all versions of this method through the
2708      * inheritance chain are called
2709      */
2710     applyConfig: function() {
2711         Roo.dd.DD.superclass.applyConfig.call(this);
2712         this.scroll = (this.config.scroll !== false);
2713     },
2714
2715     /*
2716      * Event that fires prior to the onMouseDown event.  Overrides
2717      * Roo.dd.DragDrop.
2718      */
2719     b4MouseDown: function(e) {
2720         // this.resetConstraints();
2721         this.autoOffset(e.getPageX(),
2722                             e.getPageY());
2723     },
2724
2725     /*
2726      * Event that fires prior to the onDrag event.  Overrides
2727      * Roo.dd.DragDrop.
2728      */
2729     b4Drag: function(e) {
2730         this.setDragElPos(e.getPageX(),
2731                             e.getPageY());
2732     },
2733
2734     toString: function() {
2735         return ("DD " + this.id);
2736     }
2737
2738     //////////////////////////////////////////////////////////////////////////
2739     // Debugging ygDragDrop events that can be overridden
2740     //////////////////////////////////////////////////////////////////////////
2741     /*
2742     startDrag: function(x, y) {
2743     },
2744
2745     onDrag: function(e) {
2746     },
2747
2748     onDragEnter: function(e, id) {
2749     },
2750
2751     onDragOver: function(e, id) {
2752     },
2753
2754     onDragOut: function(e, id) {
2755     },
2756
2757     onDragDrop: function(e, id) {
2758     },
2759
2760     endDrag: function(e) {
2761     }
2762
2763     */
2764
2765 });/*
2766  * Based on:
2767  * Ext JS Library 1.1.1
2768  * Copyright(c) 2006-2007, Ext JS, LLC.
2769  *
2770  * Originally Released Under LGPL - original licence link has changed is not relivant.
2771  *
2772  * Fork - LGPL
2773  * <script type="text/javascript">
2774  */
2775
2776 /**
2777  * @class Roo.dd.DDProxy
2778  * A DragDrop implementation that inserts an empty, bordered div into
2779  * the document that follows the cursor during drag operations.  At the time of
2780  * the click, the frame div is resized to the dimensions of the linked html
2781  * element, and moved to the exact location of the linked element.
2782  *
2783  * References to the "frame" element refer to the single proxy element that
2784  * was created to be dragged in place of all DDProxy elements on the
2785  * page.
2786  *
2787  * @extends Roo.dd.DD
2788  * @constructor
2789  * @param {String} id the id of the linked html element
2790  * @param {String} sGroup the group of related DragDrop objects
2791  * @param {object} config an object containing configurable attributes
2792  *                Valid properties for DDProxy in addition to those in DragDrop:
2793  *                   resizeFrame, centerFrame, dragElId
2794  */
2795 Roo.dd.DDProxy = function(id, sGroup, config) {
2796     if (id) {
2797         this.init(id, sGroup, config);
2798         this.initFrame();
2799     }
2800 };
2801
2802 /**
2803  * The default drag frame div id
2804  * @property Roo.dd.DDProxy.dragElId
2805  * @type String
2806  * @static
2807  */
2808 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2809
2810 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2811
2812     /**
2813      * By default we resize the drag frame to be the same size as the element
2814      * we want to drag (this is to get the frame effect).  We can turn it off
2815      * if we want a different behavior.
2816      * @property resizeFrame
2817      * @type boolean
2818      */
2819     resizeFrame: true,
2820
2821     /**
2822      * By default the frame is positioned exactly where the drag element is, so
2823      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
2824      * you do not have constraints on the obj is to have the drag frame centered
2825      * around the cursor.  Set centerFrame to true for this effect.
2826      * @property centerFrame
2827      * @type boolean
2828      */
2829     centerFrame: false,
2830
2831     /**
2832      * Creates the proxy element if it does not yet exist
2833      * @method createFrame
2834      */
2835     createFrame: function() {
2836         var self = this;
2837         var body = document.body;
2838
2839         if (!body || !body.firstChild) {
2840             setTimeout( function() { self.createFrame(); }, 50 );
2841             return;
2842         }
2843
2844         var div = this.getDragEl();
2845
2846         if (!div) {
2847             div    = document.createElement("div");
2848             div.id = this.dragElId;
2849             var s  = div.style;
2850
2851             s.position   = "absolute";
2852             s.visibility = "hidden";
2853             s.cursor     = "move";
2854             s.border     = "2px solid #aaa";
2855             s.zIndex     = 999;
2856
2857             // appendChild can blow up IE if invoked prior to the window load event
2858             // while rendering a table.  It is possible there are other scenarios
2859             // that would cause this to happen as well.
2860             body.insertBefore(div, body.firstChild);
2861         }
2862     },
2863
2864     /**
2865      * Initialization for the drag frame element.  Must be called in the
2866      * constructor of all subclasses
2867      * @method initFrame
2868      */
2869     initFrame: function() {
2870         this.createFrame();
2871     },
2872
2873     applyConfig: function() {
2874         Roo.dd.DDProxy.superclass.applyConfig.call(this);
2875
2876         this.resizeFrame = (this.config.resizeFrame !== false);
2877         this.centerFrame = (this.config.centerFrame);
2878         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2879     },
2880
2881     /**
2882      * Resizes the drag frame to the dimensions of the clicked object, positions
2883      * it over the object, and finally displays it
2884      * @method showFrame
2885      * @param {int} iPageX X click position
2886      * @param {int} iPageY Y click position
2887      * @private
2888      */
2889     showFrame: function(iPageX, iPageY) {
2890         var el = this.getEl();
2891         var dragEl = this.getDragEl();
2892         var s = dragEl.style;
2893
2894         this._resizeProxy();
2895
2896         if (this.centerFrame) {
2897             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2898                            Math.round(parseInt(s.height, 10)/2) );
2899         }
2900
2901         this.setDragElPos(iPageX, iPageY);
2902
2903         Roo.fly(dragEl).show();
2904     },
2905
2906     /**
2907      * The proxy is automatically resized to the dimensions of the linked
2908      * element when a drag is initiated, unless resizeFrame is set to false
2909      * @method _resizeProxy
2910      * @private
2911      */
2912     _resizeProxy: function() {
2913         if (this.resizeFrame) {
2914             var el = this.getEl();
2915             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2916         }
2917     },
2918
2919     // overrides Roo.dd.DragDrop
2920     b4MouseDown: function(e) {
2921         var x = e.getPageX();
2922         var y = e.getPageY();
2923         this.autoOffset(x, y);
2924         this.setDragElPos(x, y);
2925     },
2926
2927     // overrides Roo.dd.DragDrop
2928     b4StartDrag: function(x, y) {
2929         // show the drag frame
2930         this.showFrame(x, y);
2931     },
2932
2933     // overrides Roo.dd.DragDrop
2934     b4EndDrag: function(e) {
2935         Roo.fly(this.getDragEl()).hide();
2936     },
2937
2938     // overrides Roo.dd.DragDrop
2939     // By default we try to move the element to the last location of the frame.
2940     // This is so that the default behavior mirrors that of Roo.dd.DD.
2941     endDrag: function(e) {
2942
2943         var lel = this.getEl();
2944         var del = this.getDragEl();
2945
2946         // Show the drag frame briefly so we can get its position
2947         del.style.visibility = "";
2948
2949         this.beforeMove();
2950         // Hide the linked element before the move to get around a Safari
2951         // rendering bug.
2952         lel.style.visibility = "hidden";
2953         Roo.dd.DDM.moveToEl(lel, del);
2954         del.style.visibility = "hidden";
2955         lel.style.visibility = "";
2956
2957         this.afterDrag();
2958     },
2959
2960     beforeMove : function(){
2961
2962     },
2963
2964     afterDrag : function(){
2965
2966     },
2967
2968     toString: function() {
2969         return ("DDProxy " + this.id);
2970     }
2971
2972 });
2973 /*
2974  * Based on:
2975  * Ext JS Library 1.1.1
2976  * Copyright(c) 2006-2007, Ext JS, LLC.
2977  *
2978  * Originally Released Under LGPL - original licence link has changed is not relivant.
2979  *
2980  * Fork - LGPL
2981  * <script type="text/javascript">
2982  */
2983
2984  /**
2985  * @class Roo.dd.DDTarget
2986  * A DragDrop implementation that does not move, but can be a drop
2987  * target.  You would get the same result by simply omitting implementation
2988  * for the event callbacks, but this way we reduce the processing cost of the
2989  * event listener and the callbacks.
2990  * @extends Roo.dd.DragDrop
2991  * @constructor
2992  * @param {String} id the id of the element that is a drop target
2993  * @param {String} sGroup the group of related DragDrop objects
2994  * @param {object} config an object containing configurable attributes
2995  *                 Valid properties for DDTarget in addition to those in
2996  *                 DragDrop:
2997  *                    none
2998  */
2999 Roo.dd.DDTarget = function(id, sGroup, config) {
3000     if (id) {
3001         this.initTarget(id, sGroup, config);
3002     }
3003 };
3004
3005 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3006 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3007     toString: function() {
3008         return ("DDTarget " + this.id);
3009     }
3010 });
3011 /*
3012  * Based on:
3013  * Ext JS Library 1.1.1
3014  * Copyright(c) 2006-2007, Ext JS, LLC.
3015  *
3016  * Originally Released Under LGPL - original licence link has changed is not relivant.
3017  *
3018  * Fork - LGPL
3019  * <script type="text/javascript">
3020  */
3021  
3022
3023 /**
3024  * @class Roo.dd.ScrollManager
3025  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3026  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3027  * @singleton
3028  */
3029 Roo.dd.ScrollManager = function(){
3030     var ddm = Roo.dd.DragDropMgr;
3031     var els = {};
3032     var dragEl = null;
3033     var proc = {};
3034     
3035     var onStop = function(e){
3036         dragEl = null;
3037         clearProc();
3038     };
3039     
3040     var triggerRefresh = function(){
3041         if(ddm.dragCurrent){
3042              ddm.refreshCache(ddm.dragCurrent.groups);
3043         }
3044     };
3045     
3046     var doScroll = function(){
3047         if(ddm.dragCurrent){
3048             var dds = Roo.dd.ScrollManager;
3049             if(!dds.animate){
3050                 if(proc.el.scroll(proc.dir, dds.increment)){
3051                     triggerRefresh();
3052                 }
3053             }else{
3054                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3055             }
3056         }
3057     };
3058     
3059     var clearProc = function(){
3060         if(proc.id){
3061             clearInterval(proc.id);
3062         }
3063         proc.id = 0;
3064         proc.el = null;
3065         proc.dir = "";
3066     };
3067     
3068     var startProc = function(el, dir){
3069         clearProc();
3070         proc.el = el;
3071         proc.dir = dir;
3072         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3073     };
3074     
3075     var onFire = function(e, isDrop){
3076         if(isDrop || !ddm.dragCurrent){ return; }
3077         var dds = Roo.dd.ScrollManager;
3078         if(!dragEl || dragEl != ddm.dragCurrent){
3079             dragEl = ddm.dragCurrent;
3080             // refresh regions on drag start
3081             dds.refreshCache();
3082         }
3083         
3084         var xy = Roo.lib.Event.getXY(e);
3085         var pt = new Roo.lib.Point(xy[0], xy[1]);
3086         for(var id in els){
3087             var el = els[id], r = el._region;
3088             if(r && r.contains(pt) && el.isScrollable()){
3089                 if(r.bottom - pt.y <= dds.thresh){
3090                     if(proc.el != el){
3091                         startProc(el, "down");
3092                     }
3093                     return;
3094                 }else if(r.right - pt.x <= dds.thresh){
3095                     if(proc.el != el){
3096                         startProc(el, "left");
3097                     }
3098                     return;
3099                 }else if(pt.y - r.top <= dds.thresh){
3100                     if(proc.el != el){
3101                         startProc(el, "up");
3102                     }
3103                     return;
3104                 }else if(pt.x - r.left <= dds.thresh){
3105                     if(proc.el != el){
3106                         startProc(el, "right");
3107                     }
3108                     return;
3109                 }
3110             }
3111         }
3112         clearProc();
3113     };
3114     
3115     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3116     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3117     
3118     return {
3119         /**
3120          * Registers new overflow element(s) to auto scroll
3121          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3122          */
3123         register : function(el){
3124             if(el instanceof Array){
3125                 for(var i = 0, len = el.length; i < len; i++) {
3126                         this.register(el[i]);
3127                 }
3128             }else{
3129                 el = Roo.get(el);
3130                 els[el.id] = el;
3131             }
3132         },
3133         
3134         /**
3135          * Unregisters overflow element(s) so they are no longer scrolled
3136          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3137          */
3138         unregister : function(el){
3139             if(el instanceof Array){
3140                 for(var i = 0, len = el.length; i < len; i++) {
3141                         this.unregister(el[i]);
3142                 }
3143             }else{
3144                 el = Roo.get(el);
3145                 delete els[el.id];
3146             }
3147         },
3148         
3149         /**
3150          * The number of pixels from the edge of a container the pointer needs to be to 
3151          * trigger scrolling (defaults to 25)
3152          * @type Number
3153          */
3154         thresh : 25,
3155         
3156         /**
3157          * The number of pixels to scroll in each scroll increment (defaults to 50)
3158          * @type Number
3159          */
3160         increment : 100,
3161         
3162         /**
3163          * The frequency of scrolls in milliseconds (defaults to 500)
3164          * @type Number
3165          */
3166         frequency : 500,
3167         
3168         /**
3169          * True to animate the scroll (defaults to true)
3170          * @type Boolean
3171          */
3172         animate: true,
3173         
3174         /**
3175          * The animation duration in seconds - 
3176          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3177          * @type Number
3178          */
3179         animDuration: .4,
3180         
3181         /**
3182          * Manually trigger a cache refresh.
3183          */
3184         refreshCache : function(){
3185             for(var id in els){
3186                 if(typeof els[id] == 'object'){ // for people extending the object prototype
3187                     els[id]._region = els[id].getRegion();
3188                 }
3189             }
3190         }
3191     };
3192 }();/*
3193  * Based on:
3194  * Ext JS Library 1.1.1
3195  * Copyright(c) 2006-2007, Ext JS, LLC.
3196  *
3197  * Originally Released Under LGPL - original licence link has changed is not relivant.
3198  *
3199  * Fork - LGPL
3200  * <script type="text/javascript">
3201  */
3202  
3203
3204 /**
3205  * @class Roo.dd.Registry
3206  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
3207  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3208  * @singleton
3209  */
3210 Roo.dd.Registry = function(){
3211     var elements = {}; 
3212     var handles = {}; 
3213     var autoIdSeed = 0;
3214
3215     var getId = function(el, autogen){
3216         if(typeof el == "string"){
3217             return el;
3218         }
3219         var id = el.id;
3220         if(!id && autogen !== false){
3221             id = "roodd-" + (++autoIdSeed);
3222             el.id = id;
3223         }
3224         return id;
3225     };
3226     
3227     return {
3228     /**
3229      * Register a drag drop element
3230      * @param {String|HTMLElement} element The id or DOM node to register
3231      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3232      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
3233      * knows how to interpret, plus there are some specific properties known to the Registry that should be
3234      * populated in the data object (if applicable):
3235      * <pre>
3236 Value      Description<br />
3237 ---------  ------------------------------------------<br />
3238 handles    Array of DOM nodes that trigger dragging<br />
3239            for the element being registered<br />
3240 isHandle   True if the element passed in triggers<br />
3241            dragging itself, else false
3242 </pre>
3243      */
3244         register : function(el, data){
3245             data = data || {};
3246             if(typeof el == "string"){
3247                 el = document.getElementById(el);
3248             }
3249             data.ddel = el;
3250             elements[getId(el)] = data;
3251             if(data.isHandle !== false){
3252                 handles[data.ddel.id] = data;
3253             }
3254             if(data.handles){
3255                 var hs = data.handles;
3256                 for(var i = 0, len = hs.length; i < len; i++){
3257                         handles[getId(hs[i])] = data;
3258                 }
3259             }
3260         },
3261
3262     /**
3263      * Unregister a drag drop element
3264      * @param {String|HTMLElement}  element The id or DOM node to unregister
3265      */
3266         unregister : function(el){
3267             var id = getId(el, false);
3268             var data = elements[id];
3269             if(data){
3270                 delete elements[id];
3271                 if(data.handles){
3272                     var hs = data.handles;
3273                     for(var i = 0, len = hs.length; i < len; i++){
3274                         delete handles[getId(hs[i], false)];
3275                     }
3276                 }
3277             }
3278         },
3279
3280     /**
3281      * Returns the handle registered for a DOM Node by id
3282      * @param {String|HTMLElement} id The DOM node or id to look up
3283      * @return {Object} handle The custom handle data
3284      */
3285         getHandle : function(id){
3286             if(typeof id != "string"){ // must be element?
3287                 id = id.id;
3288             }
3289             return handles[id];
3290         },
3291
3292     /**
3293      * Returns the handle that is registered for the DOM node that is the target of the event
3294      * @param {Event} e The event
3295      * @return {Object} handle The custom handle data
3296      */
3297         getHandleFromEvent : function(e){
3298             var t = Roo.lib.Event.getTarget(e);
3299             return t ? handles[t.id] : null;
3300         },
3301
3302     /**
3303      * Returns a custom data object that is registered for a DOM node by id
3304      * @param {String|HTMLElement} id The DOM node or id to look up
3305      * @return {Object} data The custom data
3306      */
3307         getTarget : function(id){
3308             if(typeof id != "string"){ // must be element?
3309                 id = id.id;
3310             }
3311             return elements[id];
3312         },
3313
3314     /**
3315      * Returns a custom data object that is registered for the DOM node that is the target of the event
3316      * @param {Event} e The event
3317      * @return {Object} data The custom data
3318      */
3319         getTargetFromEvent : function(e){
3320             var t = Roo.lib.Event.getTarget(e);
3321             return t ? elements[t.id] || handles[t.id] : null;
3322         }
3323     };
3324 }();/*
3325  * Based on:
3326  * Ext JS Library 1.1.1
3327  * Copyright(c) 2006-2007, Ext JS, LLC.
3328  *
3329  * Originally Released Under LGPL - original licence link has changed is not relivant.
3330  *
3331  * Fork - LGPL
3332  * <script type="text/javascript">
3333  */
3334  
3335
3336 /**
3337  * @class Roo.dd.StatusProxy
3338  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
3339  * default drag proxy used by all Roo.dd components.
3340  * @constructor
3341  * @param {Object} config
3342  */
3343 Roo.dd.StatusProxy = function(config){
3344     Roo.apply(this, config);
3345     this.id = this.id || Roo.id();
3346     this.el = new Roo.Layer({
3347         dh: {
3348             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3349                 {tag: "div", cls: "x-dd-drop-icon"},
3350                 {tag: "div", cls: "x-dd-drag-ghost"}
3351             ]
3352         }, 
3353         shadow: !config || config.shadow !== false
3354     });
3355     this.ghost = Roo.get(this.el.dom.childNodes[1]);
3356     this.dropStatus = this.dropNotAllowed;
3357 };
3358
3359 Roo.dd.StatusProxy.prototype = {
3360     /**
3361      * @cfg {String} dropAllowed
3362      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3363      */
3364     dropAllowed : "x-dd-drop-ok",
3365     /**
3366      * @cfg {String} dropNotAllowed
3367      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3368      */
3369     dropNotAllowed : "x-dd-drop-nodrop",
3370
3371     /**
3372      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3373      * over the current target element.
3374      * @param {String} cssClass The css class for the new drop status indicator image
3375      */
3376     setStatus : function(cssClass){
3377         cssClass = cssClass || this.dropNotAllowed;
3378         if(this.dropStatus != cssClass){
3379             this.el.replaceClass(this.dropStatus, cssClass);
3380             this.dropStatus = cssClass;
3381         }
3382     },
3383
3384     /**
3385      * Resets the status indicator to the default dropNotAllowed value
3386      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3387      */
3388     reset : function(clearGhost){
3389         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3390         this.dropStatus = this.dropNotAllowed;
3391         if(clearGhost){
3392             this.ghost.update("");
3393         }
3394     },
3395
3396     /**
3397      * Updates the contents of the ghost element
3398      * @param {String} html The html that will replace the current innerHTML of the ghost element
3399      */
3400     update : function(html){
3401         if(typeof html == "string"){
3402             this.ghost.update(html);
3403         }else{
3404             this.ghost.update("");
3405             html.style.margin = "0";
3406             this.ghost.dom.appendChild(html);
3407         }
3408         // ensure float = none set?? cant remember why though.
3409         var el = this.ghost.dom.firstChild;
3410                 if(el){
3411                         Roo.fly(el).setStyle('float', 'none');
3412                 }
3413     },
3414     
3415     /**
3416      * Returns the underlying proxy {@link Roo.Layer}
3417      * @return {Roo.Layer} el
3418     */
3419     getEl : function(){
3420         return this.el;
3421     },
3422
3423     /**
3424      * Returns the ghost element
3425      * @return {Roo.Element} el
3426      */
3427     getGhost : function(){
3428         return this.ghost;
3429     },
3430
3431     /**
3432      * Hides the proxy
3433      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3434      */
3435     hide : function(clear){
3436         this.el.hide();
3437         if(clear){
3438             this.reset(true);
3439         }
3440     },
3441
3442     /**
3443      * Stops the repair animation if it's currently running
3444      */
3445     stop : function(){
3446         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3447             this.anim.stop();
3448         }
3449     },
3450
3451     /**
3452      * Displays this proxy
3453      */
3454     show : function(){
3455         this.el.show();
3456     },
3457
3458     /**
3459      * Force the Layer to sync its shadow and shim positions to the element
3460      */
3461     sync : function(){
3462         this.el.sync();
3463     },
3464
3465     /**
3466      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
3467      * invalid drop operation by the item being dragged.
3468      * @param {Array} xy The XY position of the element ([x, y])
3469      * @param {Function} callback The function to call after the repair is complete
3470      * @param {Object} scope The scope in which to execute the callback
3471      */
3472     repair : function(xy, callback, scope){
3473         this.callback = callback;
3474         this.scope = scope;
3475         if(xy && this.animRepair !== false){
3476             this.el.addClass("x-dd-drag-repair");
3477             this.el.hideUnders(true);
3478             this.anim = this.el.shift({
3479                 duration: this.repairDuration || .5,
3480                 easing: 'easeOut',
3481                 xy: xy,
3482                 stopFx: true,
3483                 callback: this.afterRepair,
3484                 scope: this
3485             });
3486         }else{
3487             this.afterRepair();
3488         }
3489     },
3490
3491     // private
3492     afterRepair : function(){
3493         this.hide(true);
3494         if(typeof this.callback == "function"){
3495             this.callback.call(this.scope || this);
3496         }
3497         this.callback = null;
3498         this.scope = null;
3499     }
3500 };/*
3501  * Based on:
3502  * Ext JS Library 1.1.1
3503  * Copyright(c) 2006-2007, Ext JS, LLC.
3504  *
3505  * Originally Released Under LGPL - original licence link has changed is not relivant.
3506  *
3507  * Fork - LGPL
3508  * <script type="text/javascript">
3509  */
3510
3511 /**
3512  * @class Roo.dd.DragSource
3513  * @extends Roo.dd.DDProxy
3514  * A simple class that provides the basic implementation needed to make any element draggable.
3515  * @constructor
3516  * @param {String/HTMLElement/Element} el The container element
3517  * @param {Object} config
3518  */
3519 Roo.dd.DragSource = function(el, config){
3520     this.el = Roo.get(el);
3521     this.dragData = {};
3522     
3523     Roo.apply(this, config);
3524     
3525     if(!this.proxy){
3526         this.proxy = new Roo.dd.StatusProxy();
3527     }
3528
3529     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3530           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3531     
3532     this.dragging = false;
3533 };
3534
3535 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3536     /**
3537      * @cfg {String} dropAllowed
3538      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3539      */
3540     dropAllowed : "x-dd-drop-ok",
3541     /**
3542      * @cfg {String} dropNotAllowed
3543      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3544      */
3545     dropNotAllowed : "x-dd-drop-nodrop",
3546
3547     /**
3548      * Returns the data object associated with this drag source
3549      * @return {Object} data An object containing arbitrary data
3550      */
3551     getDragData : function(e){
3552         return this.dragData;
3553     },
3554
3555     // private
3556     onDragEnter : function(e, id){
3557         var target = Roo.dd.DragDropMgr.getDDById(id);
3558         this.cachedTarget = target;
3559         if(this.beforeDragEnter(target, e, id) !== false){
3560             if(target.isNotifyTarget){
3561                 var status = target.notifyEnter(this, e, this.dragData);
3562                 this.proxy.setStatus(status);
3563             }else{
3564                 this.proxy.setStatus(this.dropAllowed);
3565             }
3566             
3567             if(this.afterDragEnter){
3568                 /**
3569                  * An empty function by default, but provided so that you can perform a custom action
3570                  * when the dragged item enters the drop target by providing an implementation.
3571                  * @param {Roo.dd.DragDrop} target The drop target
3572                  * @param {Event} e The event object
3573                  * @param {String} id The id of the dragged element
3574                  * @method afterDragEnter
3575                  */
3576                 this.afterDragEnter(target, e, id);
3577             }
3578         }
3579     },
3580
3581     /**
3582      * An empty function by default, but provided so that you can perform a custom action
3583      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3584      * @param {Roo.dd.DragDrop} target The drop target
3585      * @param {Event} e The event object
3586      * @param {String} id The id of the dragged element
3587      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3588      */
3589     beforeDragEnter : function(target, e, id){
3590         return true;
3591     },
3592
3593     // private
3594     alignElWithMouse: function() {
3595         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3596         this.proxy.sync();
3597     },
3598
3599     // private
3600     onDragOver : function(e, id){
3601         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3602         if(this.beforeDragOver(target, e, id) !== false){
3603             if(target.isNotifyTarget){
3604                 var status = target.notifyOver(this, e, this.dragData);
3605                 this.proxy.setStatus(status);
3606             }
3607
3608             if(this.afterDragOver){
3609                 /**
3610                  * An empty function by default, but provided so that you can perform a custom action
3611                  * while the dragged item is over the drop target by providing an implementation.
3612                  * @param {Roo.dd.DragDrop} target The drop target
3613                  * @param {Event} e The event object
3614                  * @param {String} id The id of the dragged element
3615                  * @method afterDragOver
3616                  */
3617                 this.afterDragOver(target, e, id);
3618             }
3619         }
3620     },
3621
3622     /**
3623      * An empty function by default, but provided so that you can perform a custom action
3624      * while the dragged item is over the drop target and optionally cancel the onDragOver.
3625      * @param {Roo.dd.DragDrop} target The drop target
3626      * @param {Event} e The event object
3627      * @param {String} id The id of the dragged element
3628      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3629      */
3630     beforeDragOver : function(target, e, id){
3631         return true;
3632     },
3633
3634     // private
3635     onDragOut : function(e, id){
3636         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3637         if(this.beforeDragOut(target, e, id) !== false){
3638             if(target.isNotifyTarget){
3639                 target.notifyOut(this, e, this.dragData);
3640             }
3641             this.proxy.reset();
3642             if(this.afterDragOut){
3643                 /**
3644                  * An empty function by default, but provided so that you can perform a custom action
3645                  * after the dragged item is dragged out of the target without dropping.
3646                  * @param {Roo.dd.DragDrop} target The drop target
3647                  * @param {Event} e The event object
3648                  * @param {String} id The id of the dragged element
3649                  * @method afterDragOut
3650                  */
3651                 this.afterDragOut(target, e, id);
3652             }
3653         }
3654         this.cachedTarget = null;
3655     },
3656
3657     /**
3658      * An empty function by default, but provided so that you can perform a custom action before the dragged
3659      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3660      * @param {Roo.dd.DragDrop} target The drop target
3661      * @param {Event} e The event object
3662      * @param {String} id The id of the dragged element
3663      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3664      */
3665     beforeDragOut : function(target, e, id){
3666         return true;
3667     },
3668     
3669     // private
3670     onDragDrop : function(e, id){
3671         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3672         if(this.beforeDragDrop(target, e, id) !== false){
3673             if(target.isNotifyTarget){
3674                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3675                     this.onValidDrop(target, e, id);
3676                 }else{
3677                     this.onInvalidDrop(target, e, id);
3678                 }
3679             }else{
3680                 this.onValidDrop(target, e, id);
3681             }
3682             
3683             if(this.afterDragDrop){
3684                 /**
3685                  * An empty function by default, but provided so that you can perform a custom action
3686                  * after a valid drag drop has occurred by providing an implementation.
3687                  * @param {Roo.dd.DragDrop} target The drop target
3688                  * @param {Event} e The event object
3689                  * @param {String} id The id of the dropped element
3690                  * @method afterDragDrop
3691                  */
3692                 this.afterDragDrop(target, e, id);
3693             }
3694         }
3695         delete this.cachedTarget;
3696     },
3697
3698     /**
3699      * An empty function by default, but provided so that you can perform a custom action before the dragged
3700      * item is dropped onto the target and optionally cancel the onDragDrop.
3701      * @param {Roo.dd.DragDrop} target The drop target
3702      * @param {Event} e The event object
3703      * @param {String} id The id of the dragged element
3704      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3705      */
3706     beforeDragDrop : function(target, e, id){
3707         return true;
3708     },
3709
3710     // private
3711     onValidDrop : function(target, e, id){
3712         this.hideProxy();
3713         if(this.afterValidDrop){
3714             /**
3715              * An empty function by default, but provided so that you can perform a custom action
3716              * after a valid drop has occurred by providing an implementation.
3717              * @param {Object} target The target DD 
3718              * @param {Event} e The event object
3719              * @param {String} id The id of the dropped element
3720              * @method afterInvalidDrop
3721              */
3722             this.afterValidDrop(target, e, id);
3723         }
3724     },
3725
3726     // private
3727     getRepairXY : function(e, data){
3728         return this.el.getXY();  
3729     },
3730
3731     // private
3732     onInvalidDrop : function(target, e, id){
3733         this.beforeInvalidDrop(target, e, id);
3734         if(this.cachedTarget){
3735             if(this.cachedTarget.isNotifyTarget){
3736                 this.cachedTarget.notifyOut(this, e, this.dragData);
3737             }
3738             this.cacheTarget = null;
3739         }
3740         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3741
3742         if(this.afterInvalidDrop){
3743             /**
3744              * An empty function by default, but provided so that you can perform a custom action
3745              * after an invalid drop has occurred by providing an implementation.
3746              * @param {Event} e The event object
3747              * @param {String} id The id of the dropped element
3748              * @method afterInvalidDrop
3749              */
3750             this.afterInvalidDrop(e, id);
3751         }
3752     },
3753
3754     // private
3755     afterRepair : function(){
3756         if(Roo.enableFx){
3757             this.el.highlight(this.hlColor || "c3daf9");
3758         }
3759         this.dragging = false;
3760     },
3761
3762     /**
3763      * An empty function by default, but provided so that you can perform a custom action after an invalid
3764      * drop has occurred.
3765      * @param {Roo.dd.DragDrop} target The drop target
3766      * @param {Event} e The event object
3767      * @param {String} id The id of the dragged element
3768      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3769      */
3770     beforeInvalidDrop : function(target, e, id){
3771         return true;
3772     },
3773
3774     // private
3775     handleMouseDown : function(e){
3776         if(this.dragging) {
3777             return;
3778         }
3779         var data = this.getDragData(e);
3780         if(data && this.onBeforeDrag(data, e) !== false){
3781             this.dragData = data;
3782             this.proxy.stop();
3783             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3784         } 
3785     },
3786
3787     /**
3788      * An empty function by default, but provided so that you can perform a custom action before the initial
3789      * drag event begins and optionally cancel it.
3790      * @param {Object} data An object containing arbitrary data to be shared with drop targets
3791      * @param {Event} e The event object
3792      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3793      */
3794     onBeforeDrag : function(data, e){
3795         return true;
3796     },
3797
3798     /**
3799      * An empty function by default, but provided so that you can perform a custom action once the initial
3800      * drag event has begun.  The drag cannot be canceled from this function.
3801      * @param {Number} x The x position of the click on the dragged object
3802      * @param {Number} y The y position of the click on the dragged object
3803      */
3804     onStartDrag : Roo.emptyFn,
3805
3806     // private - YUI override
3807     startDrag : function(x, y){
3808         this.proxy.reset();
3809         this.dragging = true;
3810         this.proxy.update("");
3811         this.onInitDrag(x, y);
3812         this.proxy.show();
3813     },
3814
3815     // private
3816     onInitDrag : function(x, y){
3817         var clone = this.el.dom.cloneNode(true);
3818         clone.id = Roo.id(); // prevent duplicate ids
3819         this.proxy.update(clone);
3820         this.onStartDrag(x, y);
3821         return true;
3822     },
3823
3824     /**
3825      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3826      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3827      */
3828     getProxy : function(){
3829         return this.proxy;  
3830     },
3831
3832     /**
3833      * Hides the drag source's {@link Roo.dd.StatusProxy}
3834      */
3835     hideProxy : function(){
3836         this.proxy.hide();  
3837         this.proxy.reset(true);
3838         this.dragging = false;
3839     },
3840
3841     // private
3842     triggerCacheRefresh : function(){
3843         Roo.dd.DDM.refreshCache(this.groups);
3844     },
3845
3846     // private - override to prevent hiding
3847     b4EndDrag: function(e) {
3848     },
3849
3850     // private - override to prevent moving
3851     endDrag : function(e){
3852         this.onEndDrag(this.dragData, e);
3853     },
3854
3855     // private
3856     onEndDrag : function(data, e){
3857     },
3858     
3859     // private - pin to cursor
3860     autoOffset : function(x, y) {
3861         this.setDelta(-12, -20);
3862     }    
3863 });/*
3864  * Based on:
3865  * Ext JS Library 1.1.1
3866  * Copyright(c) 2006-2007, Ext JS, LLC.
3867  *
3868  * Originally Released Under LGPL - original licence link has changed is not relivant.
3869  *
3870  * Fork - LGPL
3871  * <script type="text/javascript">
3872  */
3873
3874
3875 /**
3876  * @class Roo.dd.DropTarget
3877  * @extends Roo.dd.DDTarget
3878  * A simple class that provides the basic implementation needed to make any element a drop target that can have
3879  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
3880  * @constructor
3881  * @param {String/HTMLElement/Element} el The container element
3882  * @param {Object} config
3883  */
3884 Roo.dd.DropTarget = function(el, config){
3885     this.el = Roo.get(el);
3886     
3887     Roo.apply(this, config);
3888     
3889     if(this.containerScroll){
3890         Roo.dd.ScrollManager.register(this.el);
3891     }
3892     
3893     Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, 
3894           {isTarget: true});
3895
3896 };
3897
3898 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3899     /**
3900      * @cfg {String} overClass
3901      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3902      */
3903     /**
3904      * @cfg {String} dropAllowed
3905      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3906      */
3907     dropAllowed : "x-dd-drop-ok",
3908     /**
3909      * @cfg {String} dropNotAllowed
3910      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3911      */
3912     dropNotAllowed : "x-dd-drop-nodrop",
3913
3914     // private
3915     isTarget : true,
3916
3917     // private
3918     isNotifyTarget : true,
3919
3920     /**
3921      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3922      * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
3923      * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
3924      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3925      * @param {Event} e The event
3926      * @param {Object} data An object containing arbitrary data supplied by the drag source
3927      * @return {String} status The CSS class that communicates the drop status back to the source so that the
3928      * underlying {@link Roo.dd.StatusProxy} can be updated
3929      */
3930     notifyEnter : function(dd, e, data){
3931         if(this.overClass){
3932             this.el.addClass(this.overClass);
3933         }
3934         return this.dropAllowed;
3935     },
3936
3937     /**
3938      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3939      * This method will be called on every mouse movement while the drag source is over the drop target.
3940      * This default implementation simply returns the dropAllowed config value.
3941      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3942      * @param {Event} e The event
3943      * @param {Object} data An object containing arbitrary data supplied by the drag source
3944      * @return {String} status The CSS class that communicates the drop status back to the source so that the
3945      * underlying {@link Roo.dd.StatusProxy} can be updated
3946      */
3947     notifyOver : function(dd, e, data){
3948         return this.dropAllowed;
3949     },
3950
3951     /**
3952      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3953      * out of the target without dropping.  This default implementation simply removes the CSS class specified by
3954      * overClass (if any) from the drop element.
3955      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3956      * @param {Event} e The event
3957      * @param {Object} data An object containing arbitrary data supplied by the drag source
3958      */
3959     notifyOut : function(dd, e, data){
3960         if(this.overClass){
3961             this.el.removeClass(this.overClass);
3962         }
3963     },
3964
3965     /**
3966      * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3967      * been dropped on it.  This method has no default implementation and returns false, so you must provide an
3968      * implementation that does something to process the drop event and returns true so that the drag source's
3969      * repair action does not run.
3970      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3971      * @param {Event} e The event
3972      * @param {Object} data An object containing arbitrary data supplied by the drag source
3973      * @return {Boolean} True if the drop was valid, else false
3974      */
3975     notifyDrop : function(dd, e, data){
3976         return false;
3977     }
3978 });/*
3979  * Based on:
3980  * Ext JS Library 1.1.1
3981  * Copyright(c) 2006-2007, Ext JS, LLC.
3982  *
3983  * Originally Released Under LGPL - original licence link has changed is not relivant.
3984  *
3985  * Fork - LGPL
3986  * <script type="text/javascript">
3987  */
3988
3989
3990 /**
3991  * @class Roo.dd.DragZone
3992  * @extends Roo.dd.DragSource
3993  * This class provides a container DD instance that proxies for multiple child node sources.<br />
3994  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
3995  * @constructor
3996  * @param {String/HTMLElement/Element} el The container element
3997  * @param {Object} config
3998  */
3999 Roo.dd.DragZone = function(el, config){
4000     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4001     if(this.containerScroll){
4002         Roo.dd.ScrollManager.register(this.el);
4003     }
4004 };
4005
4006 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4007     /**
4008      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4009      * for auto scrolling during drag operations.
4010      */
4011     /**
4012      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4013      * method after a failed drop (defaults to "c3daf9" - light blue)
4014      */
4015
4016     /**
4017      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4018      * for a valid target to drag based on the mouse down. Override this method
4019      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4020      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4021      * @param {EventObject} e The mouse down event
4022      * @return {Object} The dragData
4023      */
4024     getDragData : function(e){
4025         return Roo.dd.Registry.getHandleFromEvent(e);
4026     },
4027     
4028     /**
4029      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4030      * this.dragData.ddel
4031      * @param {Number} x The x position of the click on the dragged object
4032      * @param {Number} y The y position of the click on the dragged object
4033      * @return {Boolean} true to continue the drag, false to cancel
4034      */
4035     onInitDrag : function(x, y){
4036         this.proxy.update(this.dragData.ddel.cloneNode(true));
4037         this.onStartDrag(x, y);
4038         return true;
4039     },
4040     
4041     /**
4042      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4043      */
4044     afterRepair : function(){
4045         if(Roo.enableFx){
4046             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4047         }
4048         this.dragging = false;
4049     },
4050
4051     /**
4052      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4053      * the XY of this.dragData.ddel
4054      * @param {EventObject} e The mouse up event
4055      * @return {Array} The xy location (e.g. [100, 200])
4056      */
4057     getRepairXY : function(e){
4058         return Roo.Element.fly(this.dragData.ddel).getXY();  
4059     }
4060 });/*
4061  * Based on:
4062  * Ext JS Library 1.1.1
4063  * Copyright(c) 2006-2007, Ext JS, LLC.
4064  *
4065  * Originally Released Under LGPL - original licence link has changed is not relivant.
4066  *
4067  * Fork - LGPL
4068  * <script type="text/javascript">
4069  */
4070 /**
4071  * @class Roo.dd.DropZone
4072  * @extends Roo.dd.DropTarget
4073  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4074  * By default, this class requires that child nodes accepting drop 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.DropZone = function(el, config){
4080     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4081 };
4082
4083 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4084     /**
4085      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4086      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4087      * provide your own custom lookup.
4088      * @param {Event} e The event
4089      * @return {Object} data The custom data
4090      */
4091     getTargetFromEvent : function(e){
4092         return Roo.dd.Registry.getTargetFromEvent(e);
4093     },
4094
4095     /**
4096      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4097      * that it has registered.  This method has no default implementation and should be overridden to provide
4098      * node-specific processing if necessary.
4099      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4100      * {@link #getTargetFromEvent} for this node)
4101      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4102      * @param {Event} e The event
4103      * @param {Object} data An object containing arbitrary data supplied by the drag source
4104      */
4105     onNodeEnter : function(n, dd, e, data){
4106         
4107     },
4108
4109     /**
4110      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4111      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4112      * overridden to provide the proper feedback.
4113      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4114      * {@link #getTargetFromEvent} for this node)
4115      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4116      * @param {Event} e The event
4117      * @param {Object} data An object containing arbitrary data supplied by the drag source
4118      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4119      * underlying {@link Roo.dd.StatusProxy} can be updated
4120      */
4121     onNodeOver : function(n, dd, e, data){
4122         return this.dropAllowed;
4123     },
4124
4125     /**
4126      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4127      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4128      * node-specific processing if necessary.
4129      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4130      * {@link #getTargetFromEvent} for this node)
4131      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4132      * @param {Event} e The event
4133      * @param {Object} data An object containing arbitrary data supplied by the drag source
4134      */
4135     onNodeOut : function(n, dd, e, data){
4136         
4137     },
4138
4139     /**
4140      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4141      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4142      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4143      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4144      * {@link #getTargetFromEvent} for this node)
4145      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4146      * @param {Event} e The event
4147      * @param {Object} data An object containing arbitrary data supplied by the drag source
4148      * @return {Boolean} True if the drop was valid, else false
4149      */
4150     onNodeDrop : function(n, dd, e, data){
4151         return false;
4152     },
4153
4154     /**
4155      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4156      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4157      * it should be overridden to provide the proper feedback if necessary.
4158      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4159      * @param {Event} e The event
4160      * @param {Object} data An object containing arbitrary data supplied by the drag source
4161      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4162      * underlying {@link Roo.dd.StatusProxy} can be updated
4163      */
4164     onContainerOver : function(dd, e, data){
4165         return this.dropNotAllowed;
4166     },
4167
4168     /**
4169      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4170      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4171      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4172      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4173      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4174      * @param {Event} e The event
4175      * @param {Object} data An object containing arbitrary data supplied by the drag source
4176      * @return {Boolean} True if the drop was valid, else false
4177      */
4178     onContainerDrop : function(dd, e, data){
4179         return false;
4180     },
4181
4182     /**
4183      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4184      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4185      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4186      * you should override this method and provide a custom implementation.
4187      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4188      * @param {Event} e The event
4189      * @param {Object} data An object containing arbitrary data supplied by the drag source
4190      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4191      * underlying {@link Roo.dd.StatusProxy} can be updated
4192      */
4193     notifyEnter : function(dd, e, data){
4194         return this.dropNotAllowed;
4195     },
4196
4197     /**
4198      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4199      * This method will be called on every mouse movement while the drag source is over the drop zone.
4200      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4201      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4202      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4203      * registered node, it will call {@link #onContainerOver}.
4204      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4205      * @param {Event} e The event
4206      * @param {Object} data An object containing arbitrary data supplied by the drag source
4207      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4208      * underlying {@link Roo.dd.StatusProxy} can be updated
4209      */
4210     notifyOver : function(dd, e, data){
4211         var n = this.getTargetFromEvent(e);
4212         if(!n){ // not over valid drop target
4213             if(this.lastOverNode){
4214                 this.onNodeOut(this.lastOverNode, dd, e, data);
4215                 this.lastOverNode = null;
4216             }
4217             return this.onContainerOver(dd, e, data);
4218         }
4219         if(this.lastOverNode != n){
4220             if(this.lastOverNode){
4221                 this.onNodeOut(this.lastOverNode, dd, e, data);
4222             }
4223             this.onNodeEnter(n, dd, e, data);
4224             this.lastOverNode = n;
4225         }
4226         return this.onNodeOver(n, dd, e, data);
4227     },
4228
4229     /**
4230      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4231      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4232      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4233      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4234      * @param {Event} e The event
4235      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4236      */
4237     notifyOut : function(dd, e, data){
4238         if(this.lastOverNode){
4239             this.onNodeOut(this.lastOverNode, dd, e, data);
4240             this.lastOverNode = null;
4241         }
4242     },
4243
4244     /**
4245      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4246      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4247      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4248      * otherwise it will call {@link #onContainerDrop}.
4249      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4250      * @param {Event} e The event
4251      * @param {Object} data An object containing arbitrary data supplied by the drag source
4252      * @return {Boolean} True if the drop was valid, else false
4253      */
4254     notifyDrop : function(dd, e, data){
4255         if(this.lastOverNode){
4256             this.onNodeOut(this.lastOverNode, dd, e, data);
4257             this.lastOverNode = null;
4258         }
4259         var n = this.getTargetFromEvent(e);
4260         return n ?
4261             this.onNodeDrop(n, dd, e, data) :
4262             this.onContainerDrop(dd, e, data);
4263     },
4264
4265     // private
4266     triggerCacheRefresh : function(){
4267         Roo.dd.DDM.refreshCache(this.groups);
4268     }  
4269 });/*
4270  * Based on:
4271  * Ext JS Library 1.1.1
4272  * Copyright(c) 2006-2007, Ext JS, LLC.
4273  *
4274  * Originally Released Under LGPL - original licence link has changed is not relivant.
4275  *
4276  * Fork - LGPL
4277  * <script type="text/javascript">
4278  */
4279
4280
4281 /**
4282  * @class Roo.data.SortTypes
4283  * @singleton
4284  * Defines the default sorting (casting?) comparison functions used when sorting data.
4285  */
4286 Roo.data.SortTypes = {
4287     /**
4288      * Default sort that does nothing
4289      * @param {Mixed} s The value being converted
4290      * @return {Mixed} The comparison value
4291      */
4292     none : function(s){
4293         return s;
4294     },
4295     
4296     /**
4297      * The regular expression used to strip tags
4298      * @type {RegExp}
4299      * @property
4300      */
4301     stripTagsRE : /<\/?[^>]+>/gi,
4302     
4303     /**
4304      * Strips all HTML tags to sort on text only
4305      * @param {Mixed} s The value being converted
4306      * @return {String} The comparison value
4307      */
4308     asText : function(s){
4309         return String(s).replace(this.stripTagsRE, "");
4310     },
4311     
4312     /**
4313      * Strips all HTML tags to sort on text only - Case insensitive
4314      * @param {Mixed} s The value being converted
4315      * @return {String} The comparison value
4316      */
4317     asUCText : function(s){
4318         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4319     },
4320     
4321     /**
4322      * Case insensitive string
4323      * @param {Mixed} s The value being converted
4324      * @return {String} The comparison value
4325      */
4326     asUCString : function(s) {
4327         return String(s).toUpperCase();
4328     },
4329     
4330     /**
4331      * Date sorting
4332      * @param {Mixed} s The value being converted
4333      * @return {Number} The comparison value
4334      */
4335     asDate : function(s) {
4336         if(!s){
4337             return 0;
4338         }
4339         if(s instanceof Date){
4340             return s.getTime();
4341         }
4342         return Date.parse(String(s));
4343     },
4344     
4345     /**
4346      * Float sorting
4347      * @param {Mixed} s The value being converted
4348      * @return {Float} The comparison value
4349      */
4350     asFloat : function(s) {
4351         var val = parseFloat(String(s).replace(/,/g, ""));
4352         if(isNaN(val)) val = 0;
4353         return val;
4354     },
4355     
4356     /**
4357      * Integer sorting
4358      * @param {Mixed} s The value being converted
4359      * @return {Number} The comparison value
4360      */
4361     asInt : function(s) {
4362         var val = parseInt(String(s).replace(/,/g, ""));
4363         if(isNaN(val)) val = 0;
4364         return val;
4365     }
4366 };/*
4367  * Based on:
4368  * Ext JS Library 1.1.1
4369  * Copyright(c) 2006-2007, Ext JS, LLC.
4370  *
4371  * Originally Released Under LGPL - original licence link has changed is not relivant.
4372  *
4373  * Fork - LGPL
4374  * <script type="text/javascript">
4375  */
4376
4377 /**
4378 * @class Roo.data.Record
4379  * Instances of this class encapsulate both record <em>definition</em> information, and record
4380  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4381  * to access Records cached in an {@link Roo.data.Store} object.<br>
4382  * <p>
4383  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4384  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4385  * objects.<br>
4386  * <p>
4387  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4388  * @constructor
4389  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4390  * {@link #create}. The parameters are the same.
4391  * @param {Array} data An associative Array of data values keyed by the field name.
4392  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4393  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4394  * not specified an integer id is generated.
4395  */
4396 Roo.data.Record = function(data, id){
4397     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4398     this.data = data;
4399 };
4400
4401 /**
4402  * Generate a constructor for a specific record layout.
4403  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4404  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4405  * Each field definition object may contain the following properties: <ul>
4406  * <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,
4407  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4408  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4409  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4410  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4411  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4412  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4413  * this may be omitted.</p></li>
4414  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4415  * <ul><li>auto (Default, implies no conversion)</li>
4416  * <li>string</li>
4417  * <li>int</li>
4418  * <li>float</li>
4419  * <li>boolean</li>
4420  * <li>date</li></ul></p></li>
4421  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4422  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4423  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4424  * by the Reader into an object that will be stored in the Record. It is passed the
4425  * following parameters:<ul>
4426  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4427  * </ul></p></li>
4428  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4429  * </ul>
4430  * <br>usage:<br><pre><code>
4431 var TopicRecord = Roo.data.Record.create(
4432     {name: 'title', mapping: 'topic_title'},
4433     {name: 'author', mapping: 'username'},
4434     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4435     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4436     {name: 'lastPoster', mapping: 'user2'},
4437     {name: 'excerpt', mapping: 'post_text'}
4438 );
4439
4440 var myNewRecord = new TopicRecord({
4441     title: 'Do my job please',
4442     author: 'noobie',
4443     totalPosts: 1,
4444     lastPost: new Date(),
4445     lastPoster: 'Animal',
4446     excerpt: 'No way dude!'
4447 });
4448 myStore.add(myNewRecord);
4449 </code></pre>
4450  * @method create
4451  * @static
4452  */
4453 Roo.data.Record.create = function(o){
4454     var f = function(){
4455         f.superclass.constructor.apply(this, arguments);
4456     };
4457     Roo.extend(f, Roo.data.Record);
4458     var p = f.prototype;
4459     p.fields = new Roo.util.MixedCollection(false, function(field){
4460         return field.name;
4461     });
4462     for(var i = 0, len = o.length; i < len; i++){
4463         p.fields.add(new Roo.data.Field(o[i]));
4464     }
4465     f.getField = function(name){
4466         return p.fields.get(name);  
4467     };
4468     return f;
4469 };
4470
4471 Roo.data.Record.AUTO_ID = 1000;
4472 Roo.data.Record.EDIT = 'edit';
4473 Roo.data.Record.REJECT = 'reject';
4474 Roo.data.Record.COMMIT = 'commit';
4475
4476 Roo.data.Record.prototype = {
4477     /**
4478      * Readonly flag - true if this record has been modified.
4479      * @type Boolean
4480      */
4481     dirty : false,
4482     editing : false,
4483     error: null,
4484     modified: null,
4485
4486     // private
4487     join : function(store){
4488         this.store = store;
4489     },
4490
4491     /**
4492      * Set the named field to the specified value.
4493      * @param {String} name The name of the field to set.
4494      * @param {Object} value The value to set the field to.
4495      */
4496     set : function(name, value){
4497         if(this.data[name] == value){
4498             return;
4499         }
4500         this.dirty = true;
4501         if(!this.modified){
4502             this.modified = {};
4503         }
4504         if(typeof this.modified[name] == 'undefined'){
4505             this.modified[name] = this.data[name];
4506         }
4507         this.data[name] = value;
4508         if(!this.editing){
4509             this.store.afterEdit(this);
4510         }       
4511     },
4512
4513     /**
4514      * Get the value of the named field.
4515      * @param {String} name The name of the field to get the value of.
4516      * @return {Object} The value of the field.
4517      */
4518     get : function(name){
4519         return this.data[name]; 
4520     },
4521
4522     // private
4523     beginEdit : function(){
4524         this.editing = true;
4525         this.modified = {}; 
4526     },
4527
4528     // private
4529     cancelEdit : function(){
4530         this.editing = false;
4531         delete this.modified;
4532     },
4533
4534     // private
4535     endEdit : function(){
4536         this.editing = false;
4537         if(this.dirty && this.store){
4538             this.store.afterEdit(this);
4539         }
4540     },
4541
4542     /**
4543      * Usually called by the {@link Roo.data.Store} which owns the Record.
4544      * Rejects all changes made to the Record since either creation, or the last commit operation.
4545      * Modified fields are reverted to their original values.
4546      * <p>
4547      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4548      * of reject operations.
4549      */
4550     reject : function(){
4551         var m = this.modified;
4552         for(var n in m){
4553             if(typeof m[n] != "function"){
4554                 this.data[n] = m[n];
4555             }
4556         }
4557         this.dirty = false;
4558         delete this.modified;
4559         this.editing = false;
4560         if(this.store){
4561             this.store.afterReject(this);
4562         }
4563     },
4564
4565     /**
4566      * Usually called by the {@link Roo.data.Store} which owns the Record.
4567      * Commits all changes made to the Record since either creation, or the last commit operation.
4568      * <p>
4569      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4570      * of commit operations.
4571      */
4572     commit : function(){
4573         this.dirty = false;
4574         delete this.modified;
4575         this.editing = false;
4576         if(this.store){
4577             this.store.afterCommit(this);
4578         }
4579     },
4580
4581     // private
4582     hasError : function(){
4583         return this.error != null;
4584     },
4585
4586     // private
4587     clearError : function(){
4588         this.error = null;
4589     },
4590
4591     /**
4592      * Creates a copy of this record.
4593      * @param {String} id (optional) A new record id if you don't want to use this record's id
4594      * @return {Record}
4595      */
4596     copy : function(newId) {
4597         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4598     }
4599 };/*
4600  * Based on:
4601  * Ext JS Library 1.1.1
4602  * Copyright(c) 2006-2007, Ext JS, LLC.
4603  *
4604  * Originally Released Under LGPL - original licence link has changed is not relivant.
4605  *
4606  * Fork - LGPL
4607  * <script type="text/javascript">
4608  */
4609
4610
4611
4612 /**
4613  * @class Roo.data.Store
4614  * @extends Roo.util.Observable
4615  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4616  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4617  * <p>
4618  * 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
4619  * has no knowledge of the format of the data returned by the Proxy.<br>
4620  * <p>
4621  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4622  * instances from the data object. These records are cached and made available through accessor functions.
4623  * @constructor
4624  * Creates a new Store.
4625  * @param {Object} config A config object containing the objects needed for the Store to access data,
4626  * and read the data into Records.
4627  */
4628 Roo.data.Store = function(config){
4629     this.data = new Roo.util.MixedCollection(false);
4630     this.data.getKey = function(o){
4631         return o.id;
4632     };
4633     this.baseParams = {};
4634     // private
4635     this.paramNames = {
4636         "start" : "start",
4637         "limit" : "limit",
4638         "sort" : "sort",
4639         "dir" : "dir"
4640     };
4641
4642     if(config && config.data){
4643         this.inlineData = config.data;
4644         delete config.data;
4645     }
4646
4647     Roo.apply(this, config);
4648     
4649     if(this.reader){ // reader passed
4650         this.reader = Roo.factory(this.reader, Roo.data);
4651         this.reader.xmodule = this.xmodule || false;
4652         if(!this.recordType){
4653             this.recordType = this.reader.recordType;
4654         }
4655         if(this.reader.onMetaChange){
4656             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4657         }
4658     }
4659
4660     if(this.recordType){
4661         this.fields = this.recordType.prototype.fields;
4662     }
4663     this.modified = [];
4664
4665     this.addEvents({
4666         /**
4667          * @event datachanged
4668          * Fires when the data cache has changed, and a widget which is using this Store
4669          * as a Record cache should refresh its view.
4670          * @param {Store} this
4671          */
4672         datachanged : true,
4673         /**
4674          * @event metachange
4675          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4676          * @param {Store} this
4677          * @param {Object} meta The JSON metadata
4678          */
4679         metachange : true,
4680         /**
4681          * @event add
4682          * Fires when Records have been added to the Store
4683          * @param {Store} this
4684          * @param {Roo.data.Record[]} records The array of Records added
4685          * @param {Number} index The index at which the record(s) were added
4686          */
4687         add : true,
4688         /**
4689          * @event remove
4690          * Fires when a Record has been removed from the Store
4691          * @param {Store} this
4692          * @param {Roo.data.Record} record The Record that was removed
4693          * @param {Number} index The index at which the record was removed
4694          */
4695         remove : true,
4696         /**
4697          * @event update
4698          * Fires when a Record has been updated
4699          * @param {Store} this
4700          * @param {Roo.data.Record} record The Record that was updated
4701          * @param {String} operation The update operation being performed.  Value may be one of:
4702          * <pre><code>
4703  Roo.data.Record.EDIT
4704  Roo.data.Record.REJECT
4705  Roo.data.Record.COMMIT
4706          * </code></pre>
4707          */
4708         update : true,
4709         /**
4710          * @event clear
4711          * Fires when the data cache has been cleared.
4712          * @param {Store} this
4713          */
4714         clear : true,
4715         /**
4716          * @event beforeload
4717          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4718          * the load action will be canceled.
4719          * @param {Store} this
4720          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4721          */
4722         beforeload : true,
4723         /**
4724          * @event load
4725          * Fires after a new set of Records has been loaded.
4726          * @param {Store} this
4727          * @param {Roo.data.Record[]} records The Records that were loaded
4728          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4729          */
4730         load : true,
4731         /**
4732          * @event loadexception
4733          * Fires if an exception occurs in the Proxy during loading.
4734          * Called with the signature of the Proxy's "loadexception" event.
4735          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4736          * 
4737          * @param {Proxy} 
4738          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4739          * @param {Object} load options 
4740          * @param {Object} jsonData from your request (normally this contains the Exception)
4741          */
4742         loadexception : true
4743     });
4744     
4745     if(this.proxy){
4746         this.proxy = Roo.factory(this.proxy, Roo.data);
4747         this.proxy.xmodule = this.xmodule || false;
4748         this.relayEvents(this.proxy,  ["loadexception"]);
4749     }
4750     this.sortToggle = {};
4751
4752     Roo.data.Store.superclass.constructor.call(this);
4753
4754     if(this.inlineData){
4755         this.loadData(this.inlineData);
4756         delete this.inlineData;
4757     }
4758 };
4759 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4760      /**
4761     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4762     * without a remote query - used by combo/forms at present.
4763     */
4764     
4765     /**
4766     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4767     */
4768     /**
4769     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4770     */
4771     /**
4772     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4773     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4774     */
4775     /**
4776     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4777     * on any HTTP request
4778     */
4779     /**
4780     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4781     */
4782     /**
4783     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4784     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4785     */
4786     remoteSort : false,
4787
4788     /**
4789     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4790      * loaded or when a record is removed. (defaults to false).
4791     */
4792     pruneModifiedRecords : false,
4793
4794     // private
4795     lastOptions : null,
4796
4797     /**
4798      * Add Records to the Store and fires the add event.
4799      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4800      */
4801     add : function(records){
4802         records = [].concat(records);
4803         for(var i = 0, len = records.length; i < len; i++){
4804             records[i].join(this);
4805         }
4806         var index = this.data.length;
4807         this.data.addAll(records);
4808         this.fireEvent("add", this, records, index);
4809     },
4810
4811     /**
4812      * Remove a Record from the Store and fires the remove event.
4813      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4814      */
4815     remove : function(record){
4816         var index = this.data.indexOf(record);
4817         this.data.removeAt(index);
4818         if(this.pruneModifiedRecords){
4819             this.modified.remove(record);
4820         }
4821         this.fireEvent("remove", this, record, index);
4822     },
4823
4824     /**
4825      * Remove all Records from the Store and fires the clear event.
4826      */
4827     removeAll : function(){
4828         this.data.clear();
4829         if(this.pruneModifiedRecords){
4830             this.modified = [];
4831         }
4832         this.fireEvent("clear", this);
4833     },
4834
4835     /**
4836      * Inserts Records to the Store at the given index and fires the add event.
4837      * @param {Number} index The start index at which to insert the passed Records.
4838      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4839      */
4840     insert : function(index, records){
4841         records = [].concat(records);
4842         for(var i = 0, len = records.length; i < len; i++){
4843             this.data.insert(index, records[i]);
4844             records[i].join(this);
4845         }
4846         this.fireEvent("add", this, records, index);
4847     },
4848
4849     /**
4850      * Get the index within the cache of the passed Record.
4851      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4852      * @return {Number} The index of the passed Record. Returns -1 if not found.
4853      */
4854     indexOf : function(record){
4855         return this.data.indexOf(record);
4856     },
4857
4858     /**
4859      * Get the index within the cache of the Record with the passed id.
4860      * @param {String} id The id of the Record to find.
4861      * @return {Number} The index of the Record. Returns -1 if not found.
4862      */
4863     indexOfId : function(id){
4864         return this.data.indexOfKey(id);
4865     },
4866
4867     /**
4868      * Get the Record with the specified id.
4869      * @param {String} id The id of the Record to find.
4870      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4871      */
4872     getById : function(id){
4873         return this.data.key(id);
4874     },
4875
4876     /**
4877      * Get the Record at the specified index.
4878      * @param {Number} index The index of the Record to find.
4879      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4880      */
4881     getAt : function(index){
4882         return this.data.itemAt(index);
4883     },
4884
4885     /**
4886      * Returns a range of Records between specified indices.
4887      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4888      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4889      * @return {Roo.data.Record[]} An array of Records
4890      */
4891     getRange : function(start, end){
4892         return this.data.getRange(start, end);
4893     },
4894
4895     // private
4896     storeOptions : function(o){
4897         o = Roo.apply({}, o);
4898         delete o.callback;
4899         delete o.scope;
4900         this.lastOptions = o;
4901     },
4902
4903     /**
4904      * Loads the Record cache from the configured Proxy using the configured Reader.
4905      * <p>
4906      * If using remote paging, then the first load call must specify the <em>start</em>
4907      * and <em>limit</em> properties in the options.params property to establish the initial
4908      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4909      * <p>
4910      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4911      * and this call will return before the new data has been loaded. Perform any post-processing
4912      * in a callback function, or in a "load" event handler.</strong>
4913      * <p>
4914      * @param {Object} options An object containing properties which control loading options:<ul>
4915      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4916      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4917      * passed the following arguments:<ul>
4918      * <li>r : Roo.data.Record[]</li>
4919      * <li>options: Options object from the load call</li>
4920      * <li>success: Boolean success indicator</li></ul></li>
4921      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4922      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4923      * </ul>
4924      */
4925     load : function(options){
4926         options = options || {};
4927         if(this.fireEvent("beforeload", this, options) !== false){
4928             this.storeOptions(options);
4929             var p = Roo.apply(options.params || {}, this.baseParams);
4930             if(this.sortInfo && this.remoteSort){
4931                 var pn = this.paramNames;
4932                 p[pn["sort"]] = this.sortInfo.field;
4933                 p[pn["dir"]] = this.sortInfo.direction;
4934             }
4935             this.proxy.load(p, this.reader, this.loadRecords, this, options);
4936         }
4937     },
4938
4939     /**
4940      * Reloads the Record cache from the configured Proxy using the configured Reader and
4941      * the options from the last load operation performed.
4942      * @param {Object} options (optional) An object containing properties which may override the options
4943      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4944      * the most recently used options are reused).
4945      */
4946     reload : function(options){
4947         this.load(Roo.applyIf(options||{}, this.lastOptions));
4948     },
4949
4950     // private
4951     // Called as a callback by the Reader during a load operation.
4952     loadRecords : function(o, options, success){
4953         if(!o || success === false){
4954             if(success !== false){
4955                 this.fireEvent("load", this, [], options);
4956             }
4957             if(options.callback){
4958                 options.callback.call(options.scope || this, [], options, false);
4959             }
4960             return;
4961         }
4962         // if data returned failure - throw an exception.
4963         if (o.success === false) {
4964             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
4965             return;
4966         }
4967         var r = o.records, t = o.totalRecords || r.length;
4968         if(!options || options.add !== true){
4969             if(this.pruneModifiedRecords){
4970                 this.modified = [];
4971             }
4972             for(var i = 0, len = r.length; i < len; i++){
4973                 r[i].join(this);
4974             }
4975             if(this.snapshot){
4976                 this.data = this.snapshot;
4977                 delete this.snapshot;
4978             }
4979             this.data.clear();
4980             this.data.addAll(r);
4981             this.totalLength = t;
4982             this.applySort();
4983             this.fireEvent("datachanged", this);
4984         }else{
4985             this.totalLength = Math.max(t, this.data.length+r.length);
4986             this.add(r);
4987         }
4988         this.fireEvent("load", this, r, options);
4989         if(options.callback){
4990             options.callback.call(options.scope || this, r, options, true);
4991         }
4992     },
4993
4994     /**
4995      * Loads data from a passed data block. A Reader which understands the format of the data
4996      * must have been configured in the constructor.
4997      * @param {Object} data The data block from which to read the Records.  The format of the data expected
4998      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4999      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5000      */
5001     loadData : function(o, append){
5002         var r = this.reader.readRecords(o);
5003         this.loadRecords(r, {add: append}, true);
5004     },
5005
5006     /**
5007      * Gets the number of cached records.
5008      * <p>
5009      * <em>If using paging, this may not be the total size of the dataset. If the data object
5010      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5011      * the data set size</em>
5012      */
5013     getCount : function(){
5014         return this.data.length || 0;
5015     },
5016
5017     /**
5018      * Gets the total number of records in the dataset as returned by the server.
5019      * <p>
5020      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5021      * the dataset size</em>
5022      */
5023     getTotalCount : function(){
5024         return this.totalLength || 0;
5025     },
5026
5027     /**
5028      * Returns the sort state of the Store as an object with two properties:
5029      * <pre><code>
5030  field {String} The name of the field by which the Records are sorted
5031  direction {String} The sort order, "ASC" or "DESC"
5032      * </code></pre>
5033      */
5034     getSortState : function(){
5035         return this.sortInfo;
5036     },
5037
5038     // private
5039     applySort : function(){
5040         if(this.sortInfo && !this.remoteSort){
5041             var s = this.sortInfo, f = s.field;
5042             var st = this.fields.get(f).sortType;
5043             var fn = function(r1, r2){
5044                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5045                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5046             };
5047             this.data.sort(s.direction, fn);
5048             if(this.snapshot && this.snapshot != this.data){
5049                 this.snapshot.sort(s.direction, fn);
5050             }
5051         }
5052     },
5053
5054     /**
5055      * Sets the default sort column and order to be used by the next load operation.
5056      * @param {String} fieldName The name of the field to sort by.
5057      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5058      */
5059     setDefaultSort : function(field, dir){
5060         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5061     },
5062
5063     /**
5064      * Sort the Records.
5065      * If remote sorting is used, the sort is performed on the server, and the cache is
5066      * reloaded. If local sorting is used, the cache is sorted internally.
5067      * @param {String} fieldName The name of the field to sort by.
5068      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5069      */
5070     sort : function(fieldName, dir){
5071         var f = this.fields.get(fieldName);
5072         if(!dir){
5073             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5074                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5075             }else{
5076                 dir = f.sortDir;
5077             }
5078         }
5079         this.sortToggle[f.name] = dir;
5080         this.sortInfo = {field: f.name, direction: dir};
5081         if(!this.remoteSort){
5082             this.applySort();
5083             this.fireEvent("datachanged", this);
5084         }else{
5085             this.load(this.lastOptions);
5086         }
5087     },
5088
5089     /**
5090      * Calls the specified function for each of the Records in the cache.
5091      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5092      * Returning <em>false</em> aborts and exits the iteration.
5093      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5094      */
5095     each : function(fn, scope){
5096         this.data.each(fn, scope);
5097     },
5098
5099     /**
5100      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5101      * (e.g., during paging).
5102      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5103      */
5104     getModifiedRecords : function(){
5105         return this.modified;
5106     },
5107
5108     // private
5109     createFilterFn : function(property, value, anyMatch){
5110         if(!value.exec){ // not a regex
5111             value = String(value);
5112             if(value.length == 0){
5113                 return false;
5114             }
5115             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5116         }
5117         return function(r){
5118             return value.test(r.data[property]);
5119         };
5120     },
5121
5122     /**
5123      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5124      * @param {String} property A field on your records
5125      * @param {Number} start The record index to start at (defaults to 0)
5126      * @param {Number} end The last record index to include (defaults to length - 1)
5127      * @return {Number} The sum
5128      */
5129     sum : function(property, start, end){
5130         var rs = this.data.items, v = 0;
5131         start = start || 0;
5132         end = (end || end === 0) ? end : rs.length-1;
5133
5134         for(var i = start; i <= end; i++){
5135             v += (rs[i].data[property] || 0);
5136         }
5137         return v;
5138     },
5139
5140     /**
5141      * Filter the records by a specified property.
5142      * @param {String} field A field on your records
5143      * @param {String/RegExp} value Either a string that the field
5144      * should start with or a RegExp to test against the field
5145      * @param {Boolean} anyMatch True to match any part not just the beginning
5146      */
5147     filter : function(property, value, anyMatch){
5148         var fn = this.createFilterFn(property, value, anyMatch);
5149         return fn ? this.filterBy(fn) : this.clearFilter();
5150     },
5151
5152     /**
5153      * Filter by a function. The specified function will be called with each
5154      * record in this data source. If the function returns true the record is included,
5155      * otherwise it is filtered.
5156      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5157      * @param {Object} scope (optional) The scope of the function (defaults to this)
5158      */
5159     filterBy : function(fn, scope){
5160         this.snapshot = this.snapshot || this.data;
5161         this.data = this.queryBy(fn, scope||this);
5162         this.fireEvent("datachanged", this);
5163     },
5164
5165     /**
5166      * Query the records by a specified property.
5167      * @param {String} field A field on your records
5168      * @param {String/RegExp} value Either a string that the field
5169      * should start with or a RegExp to test against the field
5170      * @param {Boolean} anyMatch True to match any part not just the beginning
5171      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5172      */
5173     query : function(property, value, anyMatch){
5174         var fn = this.createFilterFn(property, value, anyMatch);
5175         return fn ? this.queryBy(fn) : this.data.clone();
5176     },
5177
5178     /**
5179      * Query by a function. The specified function will be called with each
5180      * record in this data source. If the function returns true the record is included
5181      * in the results.
5182      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5183      * @param {Object} scope (optional) The scope of the function (defaults to this)
5184       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5185      **/
5186     queryBy : function(fn, scope){
5187         var data = this.snapshot || this.data;
5188         return data.filterBy(fn, scope||this);
5189     },
5190
5191     /**
5192      * Collects unique values for a particular dataIndex from this store.
5193      * @param {String} dataIndex The property to collect
5194      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5195      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5196      * @return {Array} An array of the unique values
5197      **/
5198     collect : function(dataIndex, allowNull, bypassFilter){
5199         var d = (bypassFilter === true && this.snapshot) ?
5200                 this.snapshot.items : this.data.items;
5201         var v, sv, r = [], l = {};
5202         for(var i = 0, len = d.length; i < len; i++){
5203             v = d[i].data[dataIndex];
5204             sv = String(v);
5205             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5206                 l[sv] = true;
5207                 r[r.length] = v;
5208             }
5209         }
5210         return r;
5211     },
5212
5213     /**
5214      * Revert to a view of the Record cache with no filtering applied.
5215      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5216      */
5217     clearFilter : function(suppressEvent){
5218         if(this.snapshot && this.snapshot != this.data){
5219             this.data = this.snapshot;
5220             delete this.snapshot;
5221             if(suppressEvent !== true){
5222                 this.fireEvent("datachanged", this);
5223             }
5224         }
5225     },
5226
5227     // private
5228     afterEdit : function(record){
5229         if(this.modified.indexOf(record) == -1){
5230             this.modified.push(record);
5231         }
5232         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5233     },
5234
5235     // private
5236     afterReject : function(record){
5237         this.modified.remove(record);
5238         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5239     },
5240
5241     // private
5242     afterCommit : function(record){
5243         this.modified.remove(record);
5244         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5245     },
5246
5247     /**
5248      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5249      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5250      */
5251     commitChanges : function(){
5252         var m = this.modified.slice(0);
5253         this.modified = [];
5254         for(var i = 0, len = m.length; i < len; i++){
5255             m[i].commit();
5256         }
5257     },
5258
5259     /**
5260      * Cancel outstanding changes on all changed records.
5261      */
5262     rejectChanges : function(){
5263         var m = this.modified.slice(0);
5264         this.modified = [];
5265         for(var i = 0, len = m.length; i < len; i++){
5266             m[i].reject();
5267         }
5268     },
5269
5270     onMetaChange : function(meta, rtype, o){
5271         this.recordType = rtype;
5272         this.fields = rtype.prototype.fields;
5273         delete this.snapshot;
5274         this.sortInfo = meta.sortInfo;
5275         this.modified = [];
5276         this.fireEvent('metachange', this, this.reader.meta);
5277     }
5278 });/*
5279  * Based on:
5280  * Ext JS Library 1.1.1
5281  * Copyright(c) 2006-2007, Ext JS, LLC.
5282  *
5283  * Originally Released Under LGPL - original licence link has changed is not relivant.
5284  *
5285  * Fork - LGPL
5286  * <script type="text/javascript">
5287  */
5288
5289 /**
5290  * @class Roo.data.SimpleStore
5291  * @extends Roo.data.Store
5292  * Small helper class to make creating Stores from Array data easier.
5293  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5294  * @cfg {Array} fields An array of field definition objects, or field name strings.
5295  * @cfg {Array} data The multi-dimensional array of data
5296  * @constructor
5297  * @param {Object} config
5298  */
5299 Roo.data.SimpleStore = function(config){
5300     Roo.data.SimpleStore.superclass.constructor.call(this, {
5301         isLocal : true,
5302         reader: new Roo.data.ArrayReader({
5303                 id: config.id
5304             },
5305             Roo.data.Record.create(config.fields)
5306         ),
5307         proxy : new Roo.data.MemoryProxy(config.data)
5308     });
5309     this.load();
5310 };
5311 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5312  * Based on:
5313  * Ext JS Library 1.1.1
5314  * Copyright(c) 2006-2007, Ext JS, LLC.
5315  *
5316  * Originally Released Under LGPL - original licence link has changed is not relivant.
5317  *
5318  * Fork - LGPL
5319  * <script type="text/javascript">
5320  */
5321
5322 /**
5323 /**
5324  * @extends Roo.data.Store
5325  * @class Roo.data.JsonStore
5326  * Small helper class to make creating Stores for JSON data easier. <br/>
5327 <pre><code>
5328 var store = new Roo.data.JsonStore({
5329     url: 'get-images.php',
5330     root: 'images',
5331     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5332 });
5333 </code></pre>
5334  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5335  * JsonReader and HttpProxy (unless inline data is provided).</b>
5336  * @cfg {Array} fields An array of field definition objects, or field name strings.
5337  * @constructor
5338  * @param {Object} config
5339  */
5340 Roo.data.JsonStore = function(c){
5341     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5342         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5343         reader: new Roo.data.JsonReader(c, c.fields)
5344     }));
5345 };
5346 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5347  * Based on:
5348  * Ext JS Library 1.1.1
5349  * Copyright(c) 2006-2007, Ext JS, LLC.
5350  *
5351  * Originally Released Under LGPL - original licence link has changed is not relivant.
5352  *
5353  * Fork - LGPL
5354  * <script type="text/javascript">
5355  */
5356
5357  
5358 Roo.data.Field = function(config){
5359     if(typeof config == "string"){
5360         config = {name: config};
5361     }
5362     Roo.apply(this, config);
5363     
5364     if(!this.type){
5365         this.type = "auto";
5366     }
5367     
5368     var st = Roo.data.SortTypes;
5369     // named sortTypes are supported, here we look them up
5370     if(typeof this.sortType == "string"){
5371         this.sortType = st[this.sortType];
5372     }
5373     
5374     // set default sortType for strings and dates
5375     if(!this.sortType){
5376         switch(this.type){
5377             case "string":
5378                 this.sortType = st.asUCString;
5379                 break;
5380             case "date":
5381                 this.sortType = st.asDate;
5382                 break;
5383             default:
5384                 this.sortType = st.none;
5385         }
5386     }
5387
5388     // define once
5389     var stripRe = /[\$,%]/g;
5390
5391     // prebuilt conversion function for this field, instead of
5392     // switching every time we're reading a value
5393     if(!this.convert){
5394         var cv, dateFormat = this.dateFormat;
5395         switch(this.type){
5396             case "":
5397             case "auto":
5398             case undefined:
5399                 cv = function(v){ return v; };
5400                 break;
5401             case "string":
5402                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5403                 break;
5404             case "int":
5405                 cv = function(v){
5406                     return v !== undefined && v !== null && v !== '' ?
5407                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5408                     };
5409                 break;
5410             case "float":
5411                 cv = function(v){
5412                     return v !== undefined && v !== null && v !== '' ?
5413                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5414                     };
5415                 break;
5416             case "bool":
5417             case "boolean":
5418                 cv = function(v){ return v === true || v === "true" || v == 1; };
5419                 break;
5420             case "date":
5421                 cv = function(v){
5422                     if(!v){
5423                         return '';
5424                     }
5425                     if(v instanceof Date){
5426                         return v;
5427                     }
5428                     if(dateFormat){
5429                         if(dateFormat == "timestamp"){
5430                             return new Date(v*1000);
5431                         }
5432                         return Date.parseDate(v, dateFormat);
5433                     }
5434                     var parsed = Date.parse(v);
5435                     return parsed ? new Date(parsed) : null;
5436                 };
5437              break;
5438             
5439         }
5440         this.convert = cv;
5441     }
5442 };
5443
5444 Roo.data.Field.prototype = {
5445     dateFormat: null,
5446     defaultValue: "",
5447     mapping: null,
5448     sortType : null,
5449     sortDir : "ASC"
5450 };/*
5451  * Based on:
5452  * Ext JS Library 1.1.1
5453  * Copyright(c) 2006-2007, Ext JS, LLC.
5454  *
5455  * Originally Released Under LGPL - original licence link has changed is not relivant.
5456  *
5457  * Fork - LGPL
5458  * <script type="text/javascript">
5459  */
5460  
5461 // Base class for reading structured data from a data source.  This class is intended to be
5462 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5463
5464 /**
5465  * @class Roo.data.DataReader
5466  * Base class for reading structured data from a data source.  This class is intended to be
5467  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5468  */
5469
5470 Roo.data.DataReader = function(meta, recordType){
5471     
5472     this.meta = meta;
5473     
5474     this.recordType = recordType instanceof Array ? 
5475         Roo.data.Record.create(recordType) : recordType;
5476 };
5477
5478 Roo.data.DataReader.prototype = {
5479      /**
5480      * Create an empty record
5481      * @param {Object} data (optional) - overlay some values
5482      * @return {Roo.data.Record} record created.
5483      */
5484     newRow :  function(d) {
5485         var da =  {};
5486         this.recordType.prototype.fields.each(function(c) {
5487             switch( c.type) {
5488                 case 'int' : da[c.name] = 0; break;
5489                 case 'date' : da[c.name] = new Date(); break;
5490                 case 'float' : da[c.name] = 0.0; break;
5491                 case 'boolean' : da[c.name] = false; break;
5492                 default : da[c.name] = ""; break;
5493             }
5494             
5495         });
5496         return new this.recordType(Roo.apply(da, d));
5497     }
5498     
5499 };/*
5500  * Based on:
5501  * Ext JS Library 1.1.1
5502  * Copyright(c) 2006-2007, Ext JS, LLC.
5503  *
5504  * Originally Released Under LGPL - original licence link has changed is not relivant.
5505  *
5506  * Fork - LGPL
5507  * <script type="text/javascript">
5508  */
5509
5510 /**
5511  * @class Roo.data.DataProxy
5512  * @extends Roo.data.Observable
5513  * This class is an abstract base class for implementations which provide retrieval of
5514  * unformatted data objects.<br>
5515  * <p>
5516  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5517  * (of the appropriate type which knows how to parse the data object) to provide a block of
5518  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5519  * <p>
5520  * Custom implementations must implement the load method as described in
5521  * {@link Roo.data.HttpProxy#load}.
5522  */
5523 Roo.data.DataProxy = function(){
5524     this.addEvents({
5525         /**
5526          * @event beforeload
5527          * Fires before a network request is made to retrieve a data object.
5528          * @param {Object} This DataProxy object.
5529          * @param {Object} params The params parameter to the load function.
5530          */
5531         beforeload : true,
5532         /**
5533          * @event load
5534          * Fires before the load method's callback is called.
5535          * @param {Object} This DataProxy object.
5536          * @param {Object} o The data object.
5537          * @param {Object} arg The callback argument object passed to the load function.
5538          */
5539         load : true,
5540         /**
5541          * @event loadexception
5542          * Fires if an Exception occurs during data retrieval.
5543          * @param {Object} This DataProxy object.
5544          * @param {Object} o The data object.
5545          * @param {Object} arg The callback argument object passed to the load function.
5546          * @param {Object} e The Exception.
5547          */
5548         loadexception : true
5549     });
5550     Roo.data.DataProxy.superclass.constructor.call(this);
5551 };
5552
5553 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5554
5555     /**
5556      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5557      */
5558 /*
5559  * Based on:
5560  * Ext JS Library 1.1.1
5561  * Copyright(c) 2006-2007, Ext JS, LLC.
5562  *
5563  * Originally Released Under LGPL - original licence link has changed is not relivant.
5564  *
5565  * Fork - LGPL
5566  * <script type="text/javascript">
5567  */
5568 /**
5569  * @class Roo.data.MemoryProxy
5570  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5571  * to the Reader when its load method is called.
5572  * @constructor
5573  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5574  */
5575 Roo.data.MemoryProxy = function(data){
5576     if (data.data) {
5577         data = data.data;
5578     }
5579     Roo.data.MemoryProxy.superclass.constructor.call(this);
5580     this.data = data;
5581 };
5582
5583 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5584     /**
5585      * Load data from the requested source (in this case an in-memory
5586      * data object passed to the constructor), read the data object into
5587      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5588      * process that block using the passed callback.
5589      * @param {Object} params This parameter is not used by the MemoryProxy class.
5590      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5591      * object into a block of Roo.data.Records.
5592      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5593      * The function must be passed <ul>
5594      * <li>The Record block object</li>
5595      * <li>The "arg" argument from the load function</li>
5596      * <li>A boolean success indicator</li>
5597      * </ul>
5598      * @param {Object} scope The scope in which to call the callback
5599      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5600      */
5601     load : function(params, reader, callback, scope, arg){
5602         params = params || {};
5603         var result;
5604         try {
5605             result = reader.readRecords(this.data);
5606         }catch(e){
5607             this.fireEvent("loadexception", this, arg, null, e);
5608             callback.call(scope, null, arg, false);
5609             return;
5610         }
5611         callback.call(scope, result, arg, true);
5612     },
5613     
5614     // private
5615     update : function(params, records){
5616         
5617     }
5618 });/*
5619  * Based on:
5620  * Ext JS Library 1.1.1
5621  * Copyright(c) 2006-2007, Ext JS, LLC.
5622  *
5623  * Originally Released Under LGPL - original licence link has changed is not relivant.
5624  *
5625  * Fork - LGPL
5626  * <script type="text/javascript">
5627  */
5628 /**
5629  * @class Roo.data.HttpProxy
5630  * @extends Roo.data.DataProxy
5631  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5632  * configured to reference a certain URL.<br><br>
5633  * <p>
5634  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5635  * from which the running page was served.<br><br>
5636  * <p>
5637  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5638  * <p>
5639  * Be aware that to enable the browser to parse an XML document, the server must set
5640  * the Content-Type header in the HTTP response to "text/xml".
5641  * @constructor
5642  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5643  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5644  * will be used to make the request.
5645  */
5646 Roo.data.HttpProxy = function(conn){
5647     Roo.data.HttpProxy.superclass.constructor.call(this);
5648     // is conn a conn config or a real conn?
5649     this.conn = conn;
5650     this.useAjax = !conn || !conn.events;
5651   
5652 };
5653
5654 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5655     // thse are take from connection...
5656     
5657     /**
5658      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5659      */
5660     /**
5661      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5662      * extra parameters to each request made by this object. (defaults to undefined)
5663      */
5664     /**
5665      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5666      *  to each request made by this object. (defaults to undefined)
5667      */
5668     /**
5669      * @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)
5670      */
5671     /**
5672      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5673      */
5674      /**
5675      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5676      * @type Boolean
5677      */
5678   
5679
5680     /**
5681      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5682      * @type Boolean
5683      */
5684     /**
5685      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5686      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5687      * a finer-grained basis than the DataProxy events.
5688      */
5689     getConnection : function(){
5690         return this.useAjax ? Roo.Ajax : this.conn;
5691     },
5692
5693     /**
5694      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5695      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5696      * process that block using the passed callback.
5697      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5698      * for the request to the remote server.
5699      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5700      * object into a block of Roo.data.Records.
5701      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5702      * The function must be passed <ul>
5703      * <li>The Record block object</li>
5704      * <li>The "arg" argument from the load function</li>
5705      * <li>A boolean success indicator</li>
5706      * </ul>
5707      * @param {Object} scope The scope in which to call the callback
5708      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5709      */
5710     load : function(params, reader, callback, scope, arg){
5711         if(this.fireEvent("beforeload", this, params) !== false){
5712             var  o = {
5713                 params : params || {},
5714                 request: {
5715                     callback : callback,
5716                     scope : scope,
5717                     arg : arg
5718                 },
5719                 reader: reader,
5720                 callback : this.loadResponse,
5721                 scope: this
5722             };
5723             if(this.useAjax){
5724                 Roo.applyIf(o, this.conn);
5725                 if(this.activeRequest){
5726                     Roo.Ajax.abort(this.activeRequest);
5727                 }
5728                 this.activeRequest = Roo.Ajax.request(o);
5729             }else{
5730                 this.conn.request(o);
5731             }
5732         }else{
5733             callback.call(scope||this, null, arg, false);
5734         }
5735     },
5736
5737     // private
5738     loadResponse : function(o, success, response){
5739         delete this.activeRequest;
5740         if(!success){
5741             this.fireEvent("loadexception", this, o, response);
5742             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5743             return;
5744         }
5745         var result;
5746         try {
5747             result = o.reader.read(response);
5748         }catch(e){
5749             this.fireEvent("loadexception", this, o, response, e);
5750             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5751             return;
5752         }
5753         
5754         this.fireEvent("load", this, o, o.request.arg);
5755         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5756     },
5757
5758     // private
5759     update : function(dataSet){
5760
5761     },
5762
5763     // private
5764     updateResponse : function(dataSet){
5765
5766     }
5767 });/*
5768  * Based on:
5769  * Ext JS Library 1.1.1
5770  * Copyright(c) 2006-2007, Ext JS, LLC.
5771  *
5772  * Originally Released Under LGPL - original licence link has changed is not relivant.
5773  *
5774  * Fork - LGPL
5775  * <script type="text/javascript">
5776  */
5777
5778 /**
5779  * @class Roo.data.ScriptTagProxy
5780  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5781  * other than the originating domain of the running page.<br><br>
5782  * <p>
5783  * <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
5784  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5785  * <p>
5786  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5787  * source code that is used as the source inside a &lt;script> tag.<br><br>
5788  * <p>
5789  * In order for the browser to process the returned data, the server must wrap the data object
5790  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5791  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5792  * depending on whether the callback name was passed:
5793  * <p>
5794  * <pre><code>
5795 boolean scriptTag = false;
5796 String cb = request.getParameter("callback");
5797 if (cb != null) {
5798     scriptTag = true;
5799     response.setContentType("text/javascript");
5800 } else {
5801     response.setContentType("application/x-json");
5802 }
5803 Writer out = response.getWriter();
5804 if (scriptTag) {
5805     out.write(cb + "(");
5806 }
5807 out.print(dataBlock.toJsonString());
5808 if (scriptTag) {
5809     out.write(");");
5810 }
5811 </pre></code>
5812  *
5813  * @constructor
5814  * @param {Object} config A configuration object.
5815  */
5816 Roo.data.ScriptTagProxy = function(config){
5817     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5818     Roo.apply(this, config);
5819     this.head = document.getElementsByTagName("head")[0];
5820 };
5821
5822 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5823
5824 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5825     /**
5826      * @cfg {String} url The URL from which to request the data object.
5827      */
5828     /**
5829      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5830      */
5831     timeout : 30000,
5832     /**
5833      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5834      * the server the name of the callback function set up by the load call to process the returned data object.
5835      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5836      * javascript output which calls this named function passing the data object as its only parameter.
5837      */
5838     callbackParam : "callback",
5839     /**
5840      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5841      * name to the request.
5842      */
5843     nocache : true,
5844
5845     /**
5846      * Load data from the configured URL, read the data object into
5847      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5848      * process that block using the passed callback.
5849      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5850      * for the request to the remote server.
5851      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5852      * object into a block of Roo.data.Records.
5853      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5854      * The function must be passed <ul>
5855      * <li>The Record block object</li>
5856      * <li>The "arg" argument from the load function</li>
5857      * <li>A boolean success indicator</li>
5858      * </ul>
5859      * @param {Object} scope The scope in which to call the callback
5860      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5861      */
5862     load : function(params, reader, callback, scope, arg){
5863         if(this.fireEvent("beforeload", this, params) !== false){
5864
5865             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5866
5867             var url = this.url;
5868             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5869             if(this.nocache){
5870                 url += "&_dc=" + (new Date().getTime());
5871             }
5872             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5873             var trans = {
5874                 id : transId,
5875                 cb : "stcCallback"+transId,
5876                 scriptId : "stcScript"+transId,
5877                 params : params,
5878                 arg : arg,
5879                 url : url,
5880                 callback : callback,
5881                 scope : scope,
5882                 reader : reader
5883             };
5884             var conn = this;
5885
5886             window[trans.cb] = function(o){
5887                 conn.handleResponse(o, trans);
5888             };
5889
5890             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5891
5892             if(this.autoAbort !== false){
5893                 this.abort();
5894             }
5895
5896             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5897
5898             var script = document.createElement("script");
5899             script.setAttribute("src", url);
5900             script.setAttribute("type", "text/javascript");
5901             script.setAttribute("id", trans.scriptId);
5902             this.head.appendChild(script);
5903
5904             this.trans = trans;
5905         }else{
5906             callback.call(scope||this, null, arg, false);
5907         }
5908     },
5909
5910     // private
5911     isLoading : function(){
5912         return this.trans ? true : false;
5913     },
5914
5915     /**
5916      * Abort the current server request.
5917      */
5918     abort : function(){
5919         if(this.isLoading()){
5920             this.destroyTrans(this.trans);
5921         }
5922     },
5923
5924     // private
5925     destroyTrans : function(trans, isLoaded){
5926         this.head.removeChild(document.getElementById(trans.scriptId));
5927         clearTimeout(trans.timeoutId);
5928         if(isLoaded){
5929             window[trans.cb] = undefined;
5930             try{
5931                 delete window[trans.cb];
5932             }catch(e){}
5933         }else{
5934             // if hasn't been loaded, wait for load to remove it to prevent script error
5935             window[trans.cb] = function(){
5936                 window[trans.cb] = undefined;
5937                 try{
5938                     delete window[trans.cb];
5939                 }catch(e){}
5940             };
5941         }
5942     },
5943
5944     // private
5945     handleResponse : function(o, trans){
5946         this.trans = false;
5947         this.destroyTrans(trans, true);
5948         var result;
5949         try {
5950             result = trans.reader.readRecords(o);
5951         }catch(e){
5952             this.fireEvent("loadexception", this, o, trans.arg, e);
5953             trans.callback.call(trans.scope||window, null, trans.arg, false);
5954             return;
5955         }
5956         this.fireEvent("load", this, o, trans.arg);
5957         trans.callback.call(trans.scope||window, result, trans.arg, true);
5958     },
5959
5960     // private
5961     handleFailure : function(trans){
5962         this.trans = false;
5963         this.destroyTrans(trans, false);
5964         this.fireEvent("loadexception", this, null, trans.arg);
5965         trans.callback.call(trans.scope||window, null, trans.arg, false);
5966     }
5967 });/*
5968  * Based on:
5969  * Ext JS Library 1.1.1
5970  * Copyright(c) 2006-2007, Ext JS, LLC.
5971  *
5972  * Originally Released Under LGPL - original licence link has changed is not relivant.
5973  *
5974  * Fork - LGPL
5975  * <script type="text/javascript">
5976  */
5977
5978 /**
5979  * @class Roo.data.JsonReader
5980  * @extends Roo.data.DataReader
5981  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5982  * based on mappings in a provided Roo.data.Record constructor.
5983  * <p>
5984  * Example code:
5985  * <pre><code>
5986 var RecordDef = Roo.data.Record.create([
5987     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
5988     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
5989 ]);
5990 var myReader = new Roo.data.JsonReader({
5991     totalProperty: "results",    // The property which contains the total dataset size (optional)
5992     root: "rows",                // The property which contains an Array of row objects
5993     id: "id"                     // The property within each row object that provides an ID for the record (optional)
5994 }, RecordDef);
5995 </code></pre>
5996  * <p>
5997  * This would consume a JSON file like this:
5998  * <pre><code>
5999 { 'results': 2, 'rows': [
6000     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6001     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6002 }
6003 </code></pre>
6004  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6005  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6006  * paged from the remote server.
6007  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6008  * @cfg {String} root name of the property which contains the Array of row objects.
6009  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6010  * @constructor
6011  * Create a new JsonReader
6012  * @param {Object} meta Metadata configuration options
6013  * @param {Object} recordType Either an Array of field definition objects,
6014  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6015  */
6016 Roo.data.JsonReader = function(meta, recordType){
6017     
6018     meta = meta || {};
6019     // set some defaults:
6020     Roo.applyIf(meta, {
6021         totalProperty: 'total',
6022         successProperty : 'success',
6023         root : 'data',
6024         id : 'id'
6025     });
6026     
6027     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6028 };
6029 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6030     /**
6031      * This method is only used by a DataProxy which has retrieved data from a remote server.
6032      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6033      * @return {Object} data A data block which is used by an Roo.data.Store object as
6034      * a cache of Roo.data.Records.
6035      */
6036     read : function(response){
6037         var json = response.responseText;
6038         /* eval:var:o */
6039         var o = eval("("+json+")");
6040         if(!o) {
6041             throw {message: "JsonReader.read: Json object not found"};
6042         }
6043         
6044         if(o.metaData){
6045             delete this.ef;
6046             this.meta = o.metaData;
6047             this.recordType = Roo.data.Record.create(o.metaData.fields);
6048             this.onMetaChange(this.meta, this.recordType, o);
6049         }
6050         return this.readRecords(o);
6051     },
6052
6053     // private function a store will implement
6054     onMetaChange : function(meta, recordType, o){
6055
6056     },
6057
6058     /**
6059          * @ignore
6060          */
6061     simpleAccess: function(obj, subsc) {
6062         return obj[subsc];
6063     },
6064
6065         /**
6066          * @ignore
6067          */
6068     getJsonAccessor: function(){
6069         var re = /[\[\.]/;
6070         return function(expr) {
6071             try {
6072                 return(re.test(expr))
6073                     ? new Function("obj", "return obj." + expr)
6074                     : function(obj){
6075                         return obj[expr];
6076                     };
6077             } catch(e){}
6078             return Roo.emptyFn;
6079         };
6080     }(),
6081
6082     /**
6083      * Create a data block containing Roo.data.Records from an XML document.
6084      * @param {Object} o An object which contains an Array of row objects in the property specified
6085      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6086      * which contains the total size of the dataset.
6087      * @return {Object} data A data block which is used by an Roo.data.Store object as
6088      * a cache of Roo.data.Records.
6089      */
6090     readRecords : function(o){
6091         /**
6092          * After any data loads, the raw JSON data is available for further custom processing.
6093          * @type Object
6094          */
6095         this.jsonData = o;
6096         var s = this.meta, Record = this.recordType,
6097             f = Record.prototype.fields, fi = f.items, fl = f.length;
6098
6099 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6100         if (!this.ef) {
6101             if(s.totalProperty) {
6102                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6103                 }
6104                 if(s.successProperty) {
6105                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6106                 }
6107                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6108                 if (s.id) {
6109                         var g = this.getJsonAccessor(s.id);
6110                         this.getId = function(rec) {
6111                                 var r = g(rec);
6112                                 return (r === undefined || r === "") ? null : r;
6113                         };
6114                 } else {
6115                         this.getId = function(){return null;};
6116                 }
6117             this.ef = [];
6118             for(var i = 0; i < fl; i++){
6119                 f = fi[i];
6120                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6121                 this.ef[i] = this.getJsonAccessor(map);
6122             }
6123         }
6124
6125         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6126         if(s.totalProperty){
6127             var v = parseInt(this.getTotal(o), 10);
6128             if(!isNaN(v)){
6129                 totalRecords = v;
6130             }
6131         }
6132         if(s.successProperty){
6133             var v = this.getSuccess(o);
6134             if(v === false || v === 'false'){
6135                 success = false;
6136             }
6137         }
6138         var records = [];
6139             for(var i = 0; i < c; i++){
6140                     var n = root[i];
6141                 var values = {};
6142                 var id = this.getId(n);
6143                 for(var j = 0; j < fl; j++){
6144                     f = fi[j];
6145                 var v = this.ef[j](n);
6146                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6147                 }
6148                 var record = new Record(values, id);
6149                 record.json = n;
6150                 records[i] = record;
6151             }
6152             return {
6153                 success : success,
6154                 records : records,
6155                 totalRecords : totalRecords
6156             };
6157     }
6158 });/*
6159  * Based on:
6160  * Ext JS Library 1.1.1
6161  * Copyright(c) 2006-2007, Ext JS, LLC.
6162  *
6163  * Originally Released Under LGPL - original licence link has changed is not relivant.
6164  *
6165  * Fork - LGPL
6166  * <script type="text/javascript">
6167  */
6168
6169 /**
6170  * @class Roo.data.XmlReader
6171  * @extends Roo.data.DataReader
6172  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6173  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6174  * <p>
6175  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6176  * header in the HTTP response must be set to "text/xml".</em>
6177  * <p>
6178  * Example code:
6179  * <pre><code>
6180 var RecordDef = Roo.data.Record.create([
6181    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6182    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6183 ]);
6184 var myReader = new Roo.data.XmlReader({
6185    totalRecords: "results", // The element which contains the total dataset size (optional)
6186    record: "row",           // The repeated element which contains row information
6187    id: "id"                 // The element within the row that provides an ID for the record (optional)
6188 }, RecordDef);
6189 </code></pre>
6190  * <p>
6191  * This would consume an XML file like this:
6192  * <pre><code>
6193 &lt;?xml?>
6194 &lt;dataset>
6195  &lt;results>2&lt;/results>
6196  &lt;row>
6197    &lt;id>1&lt;/id>
6198    &lt;name>Bill&lt;/name>
6199    &lt;occupation>Gardener&lt;/occupation>
6200  &lt;/row>
6201  &lt;row>
6202    &lt;id>2&lt;/id>
6203    &lt;name>Ben&lt;/name>
6204    &lt;occupation>Horticulturalist&lt;/occupation>
6205  &lt;/row>
6206 &lt;/dataset>
6207 </code></pre>
6208  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6209  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6210  * paged from the remote server.
6211  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6212  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6213  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6214  * a record identifier value.
6215  * @constructor
6216  * Create a new XmlReader
6217  * @param {Object} meta Metadata configuration options
6218  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6219  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6220  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6221  */
6222 Roo.data.XmlReader = function(meta, recordType){
6223     meta = meta || {};
6224     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6225 };
6226 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6227     /**
6228      * This method is only used by a DataProxy which has retrieved data from a remote server.
6229          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6230          * to contain a method called 'responseXML' that returns an XML document object.
6231      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6232      * a cache of Roo.data.Records.
6233      */
6234     read : function(response){
6235         var doc = response.responseXML;
6236         if(!doc) {
6237             throw {message: "XmlReader.read: XML Document not available"};
6238         }
6239         return this.readRecords(doc);
6240     },
6241
6242     /**
6243      * Create a data block containing Roo.data.Records from an XML document.
6244          * @param {Object} doc A parsed XML document.
6245      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6246      * a cache of Roo.data.Records.
6247      */
6248     readRecords : function(doc){
6249         /**
6250          * After any data loads/reads, the raw XML Document is available for further custom processing.
6251          * @type XMLDocument
6252          */
6253         this.xmlData = doc;
6254         var root = doc.documentElement || doc;
6255         var q = Roo.DomQuery;
6256         var recordType = this.recordType, fields = recordType.prototype.fields;
6257         var sid = this.meta.id;
6258         var totalRecords = 0, success = true;
6259         if(this.meta.totalRecords){
6260             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6261         }
6262         
6263         if(this.meta.success){
6264             var sv = q.selectValue(this.meta.success, root, true);
6265             success = sv !== false && sv !== 'false';
6266         }
6267         var records = [];
6268         var ns = q.select(this.meta.record, root);
6269         for(var i = 0, len = ns.length; i < len; i++) {
6270                 var n = ns[i];
6271                 var values = {};
6272                 var id = sid ? q.selectValue(sid, n) : undefined;
6273                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6274                     var f = fields.items[j];
6275                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6276                     v = f.convert(v);
6277                     values[f.name] = v;
6278                 }
6279                 var record = new recordType(values, id);
6280                 record.node = n;
6281                 records[records.length] = record;
6282             }
6283
6284             return {
6285                 success : success,
6286                 records : records,
6287                 totalRecords : totalRecords || records.length
6288             };
6289     }
6290 });/*
6291  * Based on:
6292  * Ext JS Library 1.1.1
6293  * Copyright(c) 2006-2007, Ext JS, LLC.
6294  *
6295  * Originally Released Under LGPL - original licence link has changed is not relivant.
6296  *
6297  * Fork - LGPL
6298  * <script type="text/javascript">
6299  */
6300
6301 /**
6302  * @class Roo.data.ArrayReader
6303  * @extends Roo.data.DataReader
6304  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6305  * Each element of that Array represents a row of data fields. The
6306  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6307  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6308  * <p>
6309  * Example code:.
6310  * <pre><code>
6311 var RecordDef = Roo.data.Record.create([
6312     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6313     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6314 ]);
6315 var myReader = new Roo.data.ArrayReader({
6316     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6317 }, RecordDef);
6318 </code></pre>
6319  * <p>
6320  * This would consume an Array like this:
6321  * <pre><code>
6322 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6323   </code></pre>
6324  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6325  * @constructor
6326  * Create a new JsonReader
6327  * @param {Object} meta Metadata configuration options.
6328  * @param {Object} recordType Either an Array of field definition objects
6329  * as specified to {@link Roo.data.Record#create},
6330  * or an {@link Roo.data.Record} object
6331  * created using {@link Roo.data.Record#create}.
6332  */
6333 Roo.data.ArrayReader = function(meta, recordType){
6334     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6335 };
6336
6337 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6338     /**
6339      * Create a data block containing Roo.data.Records from an XML document.
6340      * @param {Object} o An Array of row objects which represents the dataset.
6341      * @return {Object} data A data block which is used by an Roo.data.Store object as
6342      * a cache of Roo.data.Records.
6343      */
6344     readRecords : function(o){
6345         var sid = this.meta ? this.meta.id : null;
6346         var recordType = this.recordType, fields = recordType.prototype.fields;
6347         var records = [];
6348         var root = o;
6349             for(var i = 0; i < root.length; i++){
6350                     var n = root[i];
6351                 var values = {};
6352                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6353                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6354                 var f = fields.items[j];
6355                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6356                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6357                 v = f.convert(v);
6358                 values[f.name] = v;
6359             }
6360                 var record = new recordType(values, id);
6361                 record.json = n;
6362                 records[records.length] = record;
6363             }
6364             return {
6365                 records : records,
6366                 totalRecords : records.length
6367             };
6368     }
6369 });/*
6370  * Based on:
6371  * Ext JS Library 1.1.1
6372  * Copyright(c) 2006-2007, Ext JS, LLC.
6373  *
6374  * Originally Released Under LGPL - original licence link has changed is not relivant.
6375  *
6376  * Fork - LGPL
6377  * <script type="text/javascript">
6378  */
6379
6380
6381 /**
6382  * @class Roo.data.Tree
6383  * @extends Roo.util.Observable
6384  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6385  * in the tree have most standard DOM functionality.
6386  * @constructor
6387  * @param {Node} root (optional) The root node
6388  */
6389 Roo.data.Tree = function(root){
6390    this.nodeHash = {};
6391    /**
6392     * The root node for this tree
6393     * @type Node
6394     */
6395    this.root = null;
6396    if(root){
6397        this.setRootNode(root);
6398    }
6399    this.addEvents({
6400        /**
6401         * @event append
6402         * Fires when a new child node is appended to a node in this tree.
6403         * @param {Tree} tree The owner tree
6404         * @param {Node} parent The parent node
6405         * @param {Node} node The newly appended node
6406         * @param {Number} index The index of the newly appended node
6407         */
6408        "append" : true,
6409        /**
6410         * @event remove
6411         * Fires when a child node is removed from a node in this tree.
6412         * @param {Tree} tree The owner tree
6413         * @param {Node} parent The parent node
6414         * @param {Node} node The child node removed
6415         */
6416        "remove" : true,
6417        /**
6418         * @event move
6419         * Fires when a node is moved to a new location in the tree
6420         * @param {Tree} tree The owner tree
6421         * @param {Node} node The node moved
6422         * @param {Node} oldParent The old parent of this node
6423         * @param {Node} newParent The new parent of this node
6424         * @param {Number} index The index it was moved to
6425         */
6426        "move" : true,
6427        /**
6428         * @event insert
6429         * Fires when a new child node is inserted in a node in this tree.
6430         * @param {Tree} tree The owner tree
6431         * @param {Node} parent The parent node
6432         * @param {Node} node The child node inserted
6433         * @param {Node} refNode The child node the node was inserted before
6434         */
6435        "insert" : true,
6436        /**
6437         * @event beforeappend
6438         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6439         * @param {Tree} tree The owner tree
6440         * @param {Node} parent The parent node
6441         * @param {Node} node The child node to be appended
6442         */
6443        "beforeappend" : true,
6444        /**
6445         * @event beforeremove
6446         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6447         * @param {Tree} tree The owner tree
6448         * @param {Node} parent The parent node
6449         * @param {Node} node The child node to be removed
6450         */
6451        "beforeremove" : true,
6452        /**
6453         * @event beforemove
6454         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6455         * @param {Tree} tree The owner tree
6456         * @param {Node} node The node being moved
6457         * @param {Node} oldParent The parent of the node
6458         * @param {Node} newParent The new parent the node is moving to
6459         * @param {Number} index The index it is being moved to
6460         */
6461        "beforemove" : true,
6462        /**
6463         * @event beforeinsert
6464         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6465         * @param {Tree} tree The owner tree
6466         * @param {Node} parent The parent node
6467         * @param {Node} node The child node to be inserted
6468         * @param {Node} refNode The child node the node is being inserted before
6469         */
6470        "beforeinsert" : true
6471    });
6472
6473     Roo.data.Tree.superclass.constructor.call(this);
6474 };
6475
6476 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6477     pathSeparator: "/",
6478
6479     proxyNodeEvent : function(){
6480         return this.fireEvent.apply(this, arguments);
6481     },
6482
6483     /**
6484      * Returns the root node for this tree.
6485      * @return {Node}
6486      */
6487     getRootNode : function(){
6488         return this.root;
6489     },
6490
6491     /**
6492      * Sets the root node for this tree.
6493      * @param {Node} node
6494      * @return {Node}
6495      */
6496     setRootNode : function(node){
6497         this.root = node;
6498         node.ownerTree = this;
6499         node.isRoot = true;
6500         this.registerNode(node);
6501         return node;
6502     },
6503
6504     /**
6505      * Gets a node in this tree by its id.
6506      * @param {String} id
6507      * @return {Node}
6508      */
6509     getNodeById : function(id){
6510         return this.nodeHash[id];
6511     },
6512
6513     registerNode : function(node){
6514         this.nodeHash[node.id] = node;
6515     },
6516
6517     unregisterNode : function(node){
6518         delete this.nodeHash[node.id];
6519     },
6520
6521     toString : function(){
6522         return "[Tree"+(this.id?" "+this.id:"")+"]";
6523     }
6524 });
6525
6526 /**
6527  * @class Roo.data.Node
6528  * @extends Roo.util.Observable
6529  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6530  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6531  * @constructor
6532  * @param {Object} attributes The attributes/config for the node
6533  */
6534 Roo.data.Node = function(attributes){
6535     /**
6536      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6537      * @type {Object}
6538      */
6539     this.attributes = attributes || {};
6540     this.leaf = this.attributes.leaf;
6541     /**
6542      * The node id. @type String
6543      */
6544     this.id = this.attributes.id;
6545     if(!this.id){
6546         this.id = Roo.id(null, "ynode-");
6547         this.attributes.id = this.id;
6548     }
6549     /**
6550      * All child nodes of this node. @type Array
6551      */
6552     this.childNodes = [];
6553     if(!this.childNodes.indexOf){ // indexOf is a must
6554         this.childNodes.indexOf = function(o){
6555             for(var i = 0, len = this.length; i < len; i++){
6556                 if(this[i] == o) return i;
6557             }
6558             return -1;
6559         };
6560     }
6561     /**
6562      * The parent node for this node. @type Node
6563      */
6564     this.parentNode = null;
6565     /**
6566      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6567      */
6568     this.firstChild = null;
6569     /**
6570      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6571      */
6572     this.lastChild = null;
6573     /**
6574      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6575      */
6576     this.previousSibling = null;
6577     /**
6578      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6579      */
6580     this.nextSibling = null;
6581
6582     this.addEvents({
6583        /**
6584         * @event append
6585         * Fires when a new child node is appended
6586         * @param {Tree} tree The owner tree
6587         * @param {Node} this This node
6588         * @param {Node} node The newly appended node
6589         * @param {Number} index The index of the newly appended node
6590         */
6591        "append" : true,
6592        /**
6593         * @event remove
6594         * Fires when a child node is removed
6595         * @param {Tree} tree The owner tree
6596         * @param {Node} this This node
6597         * @param {Node} node The removed node
6598         */
6599        "remove" : true,
6600        /**
6601         * @event move
6602         * Fires when this node is moved to a new location in the tree
6603         * @param {Tree} tree The owner tree
6604         * @param {Node} this This node
6605         * @param {Node} oldParent The old parent of this node
6606         * @param {Node} newParent The new parent of this node
6607         * @param {Number} index The index it was moved to
6608         */
6609        "move" : true,
6610        /**
6611         * @event insert
6612         * Fires when a new child node is inserted.
6613         * @param {Tree} tree The owner tree
6614         * @param {Node} this This node
6615         * @param {Node} node The child node inserted
6616         * @param {Node} refNode The child node the node was inserted before
6617         */
6618        "insert" : true,
6619        /**
6620         * @event beforeappend
6621         * Fires before a new child is appended, return false to cancel the append.
6622         * @param {Tree} tree The owner tree
6623         * @param {Node} this This node
6624         * @param {Node} node The child node to be appended
6625         */
6626        "beforeappend" : true,
6627        /**
6628         * @event beforeremove
6629         * Fires before a child is removed, return false to cancel the remove.
6630         * @param {Tree} tree The owner tree
6631         * @param {Node} this This node
6632         * @param {Node} node The child node to be removed
6633         */
6634        "beforeremove" : true,
6635        /**
6636         * @event beforemove
6637         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6638         * @param {Tree} tree The owner tree
6639         * @param {Node} this This node
6640         * @param {Node} oldParent The parent of this node
6641         * @param {Node} newParent The new parent this node is moving to
6642         * @param {Number} index The index it is being moved to
6643         */
6644        "beforemove" : true,
6645        /**
6646         * @event beforeinsert
6647         * Fires before a new child is inserted, return false to cancel the insert.
6648         * @param {Tree} tree The owner tree
6649         * @param {Node} this This node
6650         * @param {Node} node The child node to be inserted
6651         * @param {Node} refNode The child node the node is being inserted before
6652         */
6653        "beforeinsert" : true
6654    });
6655     this.listeners = this.attributes.listeners;
6656     Roo.data.Node.superclass.constructor.call(this);
6657 };
6658
6659 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6660     fireEvent : function(evtName){
6661         // first do standard event for this node
6662         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6663             return false;
6664         }
6665         // then bubble it up to the tree if the event wasn't cancelled
6666         var ot = this.getOwnerTree();
6667         if(ot){
6668             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6669                 return false;
6670             }
6671         }
6672         return true;
6673     },
6674
6675     /**
6676      * Returns true if this node is a leaf
6677      * @return {Boolean}
6678      */
6679     isLeaf : function(){
6680         return this.leaf === true;
6681     },
6682
6683     // private
6684     setFirstChild : function(node){
6685         this.firstChild = node;
6686     },
6687
6688     //private
6689     setLastChild : function(node){
6690         this.lastChild = node;
6691     },
6692
6693
6694     /**
6695      * Returns true if this node is the last child of its parent
6696      * @return {Boolean}
6697      */
6698     isLast : function(){
6699        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6700     },
6701
6702     /**
6703      * Returns true if this node is the first child of its parent
6704      * @return {Boolean}
6705      */
6706     isFirst : function(){
6707        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6708     },
6709
6710     hasChildNodes : function(){
6711         return !this.isLeaf() && this.childNodes.length > 0;
6712     },
6713
6714     /**
6715      * Insert node(s) as the last child node of this node.
6716      * @param {Node/Array} node The node or Array of nodes to append
6717      * @return {Node} The appended node if single append, or null if an array was passed
6718      */
6719     appendChild : function(node){
6720         var multi = false;
6721         if(node instanceof Array){
6722             multi = node;
6723         }else if(arguments.length > 1){
6724             multi = arguments;
6725         }
6726         // if passed an array or multiple args do them one by one
6727         if(multi){
6728             for(var i = 0, len = multi.length; i < len; i++) {
6729                 this.appendChild(multi[i]);
6730             }
6731         }else{
6732             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6733                 return false;
6734             }
6735             var index = this.childNodes.length;
6736             var oldParent = node.parentNode;
6737             // it's a move, make sure we move it cleanly
6738             if(oldParent){
6739                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6740                     return false;
6741                 }
6742                 oldParent.removeChild(node);
6743             }
6744             index = this.childNodes.length;
6745             if(index == 0){
6746                 this.setFirstChild(node);
6747             }
6748             this.childNodes.push(node);
6749             node.parentNode = this;
6750             var ps = this.childNodes[index-1];
6751             if(ps){
6752                 node.previousSibling = ps;
6753                 ps.nextSibling = node;
6754             }else{
6755                 node.previousSibling = null;
6756             }
6757             node.nextSibling = null;
6758             this.setLastChild(node);
6759             node.setOwnerTree(this.getOwnerTree());
6760             this.fireEvent("append", this.ownerTree, this, node, index);
6761             if(oldParent){
6762                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6763             }
6764             return node;
6765         }
6766     },
6767
6768     /**
6769      * Removes a child node from this node.
6770      * @param {Node} node The node to remove
6771      * @return {Node} The removed node
6772      */
6773     removeChild : function(node){
6774         var index = this.childNodes.indexOf(node);
6775         if(index == -1){
6776             return false;
6777         }
6778         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6779             return false;
6780         }
6781
6782         // remove it from childNodes collection
6783         this.childNodes.splice(index, 1);
6784
6785         // update siblings
6786         if(node.previousSibling){
6787             node.previousSibling.nextSibling = node.nextSibling;
6788         }
6789         if(node.nextSibling){
6790             node.nextSibling.previousSibling = node.previousSibling;
6791         }
6792
6793         // update child refs
6794         if(this.firstChild == node){
6795             this.setFirstChild(node.nextSibling);
6796         }
6797         if(this.lastChild == node){
6798             this.setLastChild(node.previousSibling);
6799         }
6800
6801         node.setOwnerTree(null);
6802         // clear any references from the node
6803         node.parentNode = null;
6804         node.previousSibling = null;
6805         node.nextSibling = null;
6806         this.fireEvent("remove", this.ownerTree, this, node);
6807         return node;
6808     },
6809
6810     /**
6811      * Inserts the first node before the second node in this nodes childNodes collection.
6812      * @param {Node} node The node to insert
6813      * @param {Node} refNode The node to insert before (if null the node is appended)
6814      * @return {Node} The inserted node
6815      */
6816     insertBefore : function(node, refNode){
6817         if(!refNode){ // like standard Dom, refNode can be null for append
6818             return this.appendChild(node);
6819         }
6820         // nothing to do
6821         if(node == refNode){
6822             return false;
6823         }
6824
6825         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6826             return false;
6827         }
6828         var index = this.childNodes.indexOf(refNode);
6829         var oldParent = node.parentNode;
6830         var refIndex = index;
6831
6832         // when moving internally, indexes will change after remove
6833         if(oldParent == this && this.childNodes.indexOf(node) < index){
6834             refIndex--;
6835         }
6836
6837         // it's a move, make sure we move it cleanly
6838         if(oldParent){
6839             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6840                 return false;
6841             }
6842             oldParent.removeChild(node);
6843         }
6844         if(refIndex == 0){
6845             this.setFirstChild(node);
6846         }
6847         this.childNodes.splice(refIndex, 0, node);
6848         node.parentNode = this;
6849         var ps = this.childNodes[refIndex-1];
6850         if(ps){
6851             node.previousSibling = ps;
6852             ps.nextSibling = node;
6853         }else{
6854             node.previousSibling = null;
6855         }
6856         node.nextSibling = refNode;
6857         refNode.previousSibling = node;
6858         node.setOwnerTree(this.getOwnerTree());
6859         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6860         if(oldParent){
6861             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6862         }
6863         return node;
6864     },
6865
6866     /**
6867      * Returns the child node at the specified index.
6868      * @param {Number} index
6869      * @return {Node}
6870      */
6871     item : function(index){
6872         return this.childNodes[index];
6873     },
6874
6875     /**
6876      * Replaces one child node in this node with another.
6877      * @param {Node} newChild The replacement node
6878      * @param {Node} oldChild The node to replace
6879      * @return {Node} The replaced node
6880      */
6881     replaceChild : function(newChild, oldChild){
6882         this.insertBefore(newChild, oldChild);
6883         this.removeChild(oldChild);
6884         return oldChild;
6885     },
6886
6887     /**
6888      * Returns the index of a child node
6889      * @param {Node} node
6890      * @return {Number} The index of the node or -1 if it was not found
6891      */
6892     indexOf : function(child){
6893         return this.childNodes.indexOf(child);
6894     },
6895
6896     /**
6897      * Returns the tree this node is in.
6898      * @return {Tree}
6899      */
6900     getOwnerTree : function(){
6901         // if it doesn't have one, look for one
6902         if(!this.ownerTree){
6903             var p = this;
6904             while(p){
6905                 if(p.ownerTree){
6906                     this.ownerTree = p.ownerTree;
6907                     break;
6908                 }
6909                 p = p.parentNode;
6910             }
6911         }
6912         return this.ownerTree;
6913     },
6914
6915     /**
6916      * Returns depth of this node (the root node has a depth of 0)
6917      * @return {Number}
6918      */
6919     getDepth : function(){
6920         var depth = 0;
6921         var p = this;
6922         while(p.parentNode){
6923             ++depth;
6924             p = p.parentNode;
6925         }
6926         return depth;
6927     },
6928
6929     // private
6930     setOwnerTree : function(tree){
6931         // if it's move, we need to update everyone
6932         if(tree != this.ownerTree){
6933             if(this.ownerTree){
6934                 this.ownerTree.unregisterNode(this);
6935             }
6936             this.ownerTree = tree;
6937             var cs = this.childNodes;
6938             for(var i = 0, len = cs.length; i < len; i++) {
6939                 cs[i].setOwnerTree(tree);
6940             }
6941             if(tree){
6942                 tree.registerNode(this);
6943             }
6944         }
6945     },
6946
6947     /**
6948      * Returns the path for this node. The path can be used to expand or select this node programmatically.
6949      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
6950      * @return {String} The path
6951      */
6952     getPath : function(attr){
6953         attr = attr || "id";
6954         var p = this.parentNode;
6955         var b = [this.attributes[attr]];
6956         while(p){
6957             b.unshift(p.attributes[attr]);
6958             p = p.parentNode;
6959         }
6960         var sep = this.getOwnerTree().pathSeparator;
6961         return sep + b.join(sep);
6962     },
6963
6964     /**
6965      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
6966      * function call will be the scope provided or the current node. The arguments to the function
6967      * will be the args provided or the current node. If the function returns false at any point,
6968      * the bubble is stopped.
6969      * @param {Function} fn The function to call
6970      * @param {Object} scope (optional) The scope of the function (defaults to current node)
6971      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
6972      */
6973     bubble : function(fn, scope, args){
6974         var p = this;
6975         while(p){
6976             if(fn.call(scope || p, args || p) === false){
6977                 break;
6978             }
6979             p = p.parentNode;
6980         }
6981     },
6982
6983     /**
6984      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
6985      * function call will be the scope provided or the current node. The arguments to the function
6986      * will be the args provided or the current node. If the function returns false at any point,
6987      * the cascade is stopped on that branch.
6988      * @param {Function} fn The function to call
6989      * @param {Object} scope (optional) The scope of the function (defaults to current node)
6990      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
6991      */
6992     cascade : function(fn, scope, args){
6993         if(fn.call(scope || this, args || this) !== false){
6994             var cs = this.childNodes;
6995             for(var i = 0, len = cs.length; i < len; i++) {
6996                 cs[i].cascade(fn, scope, args);
6997             }
6998         }
6999     },
7000
7001     /**
7002      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7003      * function call will be the scope provided or the current node. The arguments to the function
7004      * will be the args provided or the current node. If the function returns false at any point,
7005      * the iteration stops.
7006      * @param {Function} fn The function to call
7007      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7008      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7009      */
7010     eachChild : function(fn, scope, args){
7011         var cs = this.childNodes;
7012         for(var i = 0, len = cs.length; i < len; i++) {
7013                 if(fn.call(scope || this, args || cs[i]) === false){
7014                     break;
7015                 }
7016         }
7017     },
7018
7019     /**
7020      * Finds the first child that has the attribute with the specified value.
7021      * @param {String} attribute The attribute name
7022      * @param {Mixed} value The value to search for
7023      * @return {Node} The found child or null if none was found
7024      */
7025     findChild : function(attribute, value){
7026         var cs = this.childNodes;
7027         for(var i = 0, len = cs.length; i < len; i++) {
7028                 if(cs[i].attributes[attribute] == value){
7029                     return cs[i];
7030                 }
7031         }
7032         return null;
7033     },
7034
7035     /**
7036      * Finds the first child by a custom function. The child matches if the function passed
7037      * returns true.
7038      * @param {Function} fn
7039      * @param {Object} scope (optional)
7040      * @return {Node} The found child or null if none was found
7041      */
7042     findChildBy : function(fn, scope){
7043         var cs = this.childNodes;
7044         for(var i = 0, len = cs.length; i < len; i++) {
7045                 if(fn.call(scope||cs[i], cs[i]) === true){
7046                     return cs[i];
7047                 }
7048         }
7049         return null;
7050     },
7051
7052     /**
7053      * Sorts this nodes children using the supplied sort function
7054      * @param {Function} fn
7055      * @param {Object} scope (optional)
7056      */
7057     sort : function(fn, scope){
7058         var cs = this.childNodes;
7059         var len = cs.length;
7060         if(len > 0){
7061             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7062             cs.sort(sortFn);
7063             for(var i = 0; i < len; i++){
7064                 var n = cs[i];
7065                 n.previousSibling = cs[i-1];
7066                 n.nextSibling = cs[i+1];
7067                 if(i == 0){
7068                     this.setFirstChild(n);
7069                 }
7070                 if(i == len-1){
7071                     this.setLastChild(n);
7072                 }
7073             }
7074         }
7075     },
7076
7077     /**
7078      * Returns true if this node is an ancestor (at any point) of the passed node.
7079      * @param {Node} node
7080      * @return {Boolean}
7081      */
7082     contains : function(node){
7083         return node.isAncestor(this);
7084     },
7085
7086     /**
7087      * Returns true if the passed node is an ancestor (at any point) of this node.
7088      * @param {Node} node
7089      * @return {Boolean}
7090      */
7091     isAncestor : function(node){
7092         var p = this.parentNode;
7093         while(p){
7094             if(p == node){
7095                 return true;
7096             }
7097             p = p.parentNode;
7098         }
7099         return false;
7100     },
7101
7102     toString : function(){
7103         return "[Node"+(this.id?" "+this.id:"")+"]";
7104     }
7105 });/*
7106  * Based on:
7107  * Ext JS Library 1.1.1
7108  * Copyright(c) 2006-2007, Ext JS, LLC.
7109  *
7110  * Originally Released Under LGPL - original licence link has changed is not relivant.
7111  *
7112  * Fork - LGPL
7113  * <script type="text/javascript">
7114  */
7115  
7116
7117 /**
7118  * @class Roo.ComponentMgr
7119  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7120  * @singleton
7121  */
7122 Roo.ComponentMgr = function(){
7123     var all = new Roo.util.MixedCollection();
7124
7125     return {
7126         /**
7127          * Registers a component.
7128          * @param {Roo.Component} c The component
7129          */
7130         register : function(c){
7131             all.add(c);
7132         },
7133
7134         /**
7135          * Unregisters a component.
7136          * @param {Roo.Component} c The component
7137          */
7138         unregister : function(c){
7139             all.remove(c);
7140         },
7141
7142         /**
7143          * Returns a component by id
7144          * @param {String} id The component id
7145          */
7146         get : function(id){
7147             return all.get(id);
7148         },
7149
7150         /**
7151          * Registers a function that will be called when a specified component is added to ComponentMgr
7152          * @param {String} id The component id
7153          * @param {Funtction} fn The callback function
7154          * @param {Object} scope The scope of the callback
7155          */
7156         onAvailable : function(id, fn, scope){
7157             all.on("add", function(index, o){
7158                 if(o.id == id){
7159                     fn.call(scope || o, o);
7160                     all.un("add", fn, scope);
7161                 }
7162             });
7163         }
7164     };
7165 }();/*
7166  * Based on:
7167  * Ext JS Library 1.1.1
7168  * Copyright(c) 2006-2007, Ext JS, LLC.
7169  *
7170  * Originally Released Under LGPL - original licence link has changed is not relivant.
7171  *
7172  * Fork - LGPL
7173  * <script type="text/javascript">
7174  */
7175  
7176 /**
7177  * @class Roo.Component
7178  * @extends Roo.util.Observable
7179  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7180  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7181  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7182  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7183  * All visual components (widgets) that require rendering into a layout should subclass Component.
7184  * @constructor
7185  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7186  * 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
7187  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7188  */
7189 Roo.Component = function(config){
7190     config = config || {};
7191     if(config.tagName || config.dom || typeof config == "string"){ // element object
7192         config = {el: config, id: config.id || config};
7193     }
7194     this.initialConfig = config;
7195
7196     Roo.apply(this, config);
7197     this.addEvents({
7198         /**
7199          * @event disable
7200          * Fires after the component is disabled.
7201              * @param {Roo.Component} this
7202              */
7203         disable : true,
7204         /**
7205          * @event enable
7206          * Fires after the component is enabled.
7207              * @param {Roo.Component} this
7208              */
7209         enable : true,
7210         /**
7211          * @event beforeshow
7212          * Fires before the component is shown.  Return false to stop the show.
7213              * @param {Roo.Component} this
7214              */
7215         beforeshow : true,
7216         /**
7217          * @event show
7218          * Fires after the component is shown.
7219              * @param {Roo.Component} this
7220              */
7221         show : true,
7222         /**
7223          * @event beforehide
7224          * Fires before the component is hidden. Return false to stop the hide.
7225              * @param {Roo.Component} this
7226              */
7227         beforehide : true,
7228         /**
7229          * @event hide
7230          * Fires after the component is hidden.
7231              * @param {Roo.Component} this
7232              */
7233         hide : true,
7234         /**
7235          * @event beforerender
7236          * Fires before the component is rendered. Return false to stop the render.
7237              * @param {Roo.Component} this
7238              */
7239         beforerender : true,
7240         /**
7241          * @event render
7242          * Fires after the component is rendered.
7243              * @param {Roo.Component} this
7244              */
7245         render : true,
7246         /**
7247          * @event beforedestroy
7248          * Fires before the component is destroyed. Return false to stop the destroy.
7249              * @param {Roo.Component} this
7250              */
7251         beforedestroy : true,
7252         /**
7253          * @event destroy
7254          * Fires after the component is destroyed.
7255              * @param {Roo.Component} this
7256              */
7257         destroy : true
7258     });
7259     if(!this.id){
7260         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7261     }
7262     Roo.ComponentMgr.register(this);
7263     Roo.Component.superclass.constructor.call(this);
7264     this.initComponent();
7265     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7266         this.render(this.renderTo);
7267         delete this.renderTo;
7268     }
7269 };
7270
7271 // private
7272 Roo.Component.AUTO_ID = 1000;
7273
7274 Roo.extend(Roo.Component, Roo.util.Observable, {
7275     /**
7276      * @property {Boolean} hidden
7277      * true if this component is hidden. Read-only.
7278      */
7279     hidden : false,
7280     /**
7281      * true if this component is disabled. Read-only.
7282      */
7283     disabled : false,
7284     /**
7285      * true if this component has been rendered. Read-only.
7286      */
7287     rendered : false,
7288     
7289     /** @cfg {String} disableClass
7290      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7291      */
7292     disabledClass : "x-item-disabled",
7293         /** @cfg {Boolean} allowDomMove
7294          * Whether the component can move the Dom node when rendering (defaults to true).
7295          */
7296     allowDomMove : true,
7297     /** @cfg {String} hideMode
7298      * How this component should hidden. Supported values are
7299      * "visibility" (css visibility), "offsets" (negative offset position) and
7300      * "display" (css display) - defaults to "display".
7301      */
7302     hideMode: 'display',
7303
7304     // private
7305     ctype : "Roo.Component",
7306
7307     /** @cfg {String} actionMode 
7308      * which property holds the element that used for  hide() / show() / disable() / enable()
7309      * default is 'el' 
7310      */
7311     actionMode : "el",
7312
7313     // private
7314     getActionEl : function(){
7315         return this[this.actionMode];
7316     },
7317
7318     initComponent : Roo.emptyFn,
7319     /**
7320      * If this is a lazy rendering component, render it to its container element.
7321      * @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.
7322      */
7323     render : function(container, position){
7324         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7325             if(!container && this.el){
7326                 this.el = Roo.get(this.el);
7327                 container = this.el.dom.parentNode;
7328                 this.allowDomMove = false;
7329             }
7330             this.container = Roo.get(container);
7331             this.rendered = true;
7332             if(position !== undefined){
7333                 if(typeof position == 'number'){
7334                     position = this.container.dom.childNodes[position];
7335                 }else{
7336                     position = Roo.getDom(position);
7337                 }
7338             }
7339             this.onRender(this.container, position || null);
7340             if(this.cls){
7341                 this.el.addClass(this.cls);
7342                 delete this.cls;
7343             }
7344             if(this.style){
7345                 this.el.applyStyles(this.style);
7346                 delete this.style;
7347             }
7348             this.fireEvent("render", this);
7349             this.afterRender(this.container);
7350             if(this.hidden){
7351                 this.hide();
7352             }
7353             if(this.disabled){
7354                 this.disable();
7355             }
7356         }
7357         return this;
7358     },
7359
7360     // private
7361     // default function is not really useful
7362     onRender : function(ct, position){
7363         if(this.el){
7364             this.el = Roo.get(this.el);
7365             if(this.allowDomMove !== false){
7366                 ct.dom.insertBefore(this.el.dom, position);
7367             }
7368         }
7369     },
7370
7371     // private
7372     getAutoCreate : function(){
7373         var cfg = typeof this.autoCreate == "object" ?
7374                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7375         if(this.id && !cfg.id){
7376             cfg.id = this.id;
7377         }
7378         return cfg;
7379     },
7380
7381     // private
7382     afterRender : Roo.emptyFn,
7383
7384     /**
7385      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7386      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7387      */
7388     destroy : function(){
7389         if(this.fireEvent("beforedestroy", this) !== false){
7390             this.purgeListeners();
7391             this.beforeDestroy();
7392             if(this.rendered){
7393                 this.el.removeAllListeners();
7394                 this.el.remove();
7395                 if(this.actionMode == "container"){
7396                     this.container.remove();
7397                 }
7398             }
7399             this.onDestroy();
7400             Roo.ComponentMgr.unregister(this);
7401             this.fireEvent("destroy", this);
7402         }
7403     },
7404
7405         // private
7406     beforeDestroy : function(){
7407
7408     },
7409
7410         // private
7411         onDestroy : function(){
7412
7413     },
7414
7415     /**
7416      * Returns the underlying {@link Roo.Element}.
7417      * @return {Roo.Element} The element
7418      */
7419     getEl : function(){
7420         return this.el;
7421     },
7422
7423     /**
7424      * Returns the id of this component.
7425      * @return {String}
7426      */
7427     getId : function(){
7428         return this.id;
7429     },
7430
7431     /**
7432      * Try to focus this component.
7433      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7434      * @return {Roo.Component} this
7435      */
7436     focus : function(selectText){
7437         if(this.rendered){
7438             this.el.focus();
7439             if(selectText === true){
7440                 this.el.dom.select();
7441             }
7442         }
7443         return this;
7444     },
7445
7446     // private
7447     blur : function(){
7448         if(this.rendered){
7449             this.el.blur();
7450         }
7451         return this;
7452     },
7453
7454     /**
7455      * Disable this component.
7456      * @return {Roo.Component} this
7457      */
7458     disable : function(){
7459         if(this.rendered){
7460             this.onDisable();
7461         }
7462         this.disabled = true;
7463         this.fireEvent("disable", this);
7464         return this;
7465     },
7466
7467         // private
7468     onDisable : function(){
7469         this.getActionEl().addClass(this.disabledClass);
7470         this.el.dom.disabled = true;
7471     },
7472
7473     /**
7474      * Enable this component.
7475      * @return {Roo.Component} this
7476      */
7477     enable : function(){
7478         if(this.rendered){
7479             this.onEnable();
7480         }
7481         this.disabled = false;
7482         this.fireEvent("enable", this);
7483         return this;
7484     },
7485
7486         // private
7487     onEnable : function(){
7488         this.getActionEl().removeClass(this.disabledClass);
7489         this.el.dom.disabled = false;
7490     },
7491
7492     /**
7493      * Convenience function for setting disabled/enabled by boolean.
7494      * @param {Boolean} disabled
7495      */
7496     setDisabled : function(disabled){
7497         this[disabled ? "disable" : "enable"]();
7498     },
7499
7500     /**
7501      * Show this component.
7502      * @return {Roo.Component} this
7503      */
7504     show: function(){
7505         if(this.fireEvent("beforeshow", this) !== false){
7506             this.hidden = false;
7507             if(this.rendered){
7508                 this.onShow();
7509             }
7510             this.fireEvent("show", this);
7511         }
7512         return this;
7513     },
7514
7515     // private
7516     onShow : function(){
7517         var ae = this.getActionEl();
7518         if(this.hideMode == 'visibility'){
7519             ae.dom.style.visibility = "visible";
7520         }else if(this.hideMode == 'offsets'){
7521             ae.removeClass('x-hidden');
7522         }else{
7523             ae.dom.style.display = "";
7524         }
7525     },
7526
7527     /**
7528      * Hide this component.
7529      * @return {Roo.Component} this
7530      */
7531     hide: function(){
7532         if(this.fireEvent("beforehide", this) !== false){
7533             this.hidden = true;
7534             if(this.rendered){
7535                 this.onHide();
7536             }
7537             this.fireEvent("hide", this);
7538         }
7539         return this;
7540     },
7541
7542     // private
7543     onHide : function(){
7544         var ae = this.getActionEl();
7545         if(this.hideMode == 'visibility'){
7546             ae.dom.style.visibility = "hidden";
7547         }else if(this.hideMode == 'offsets'){
7548             ae.addClass('x-hidden');
7549         }else{
7550             ae.dom.style.display = "none";
7551         }
7552     },
7553
7554     /**
7555      * Convenience function to hide or show this component by boolean.
7556      * @param {Boolean} visible True to show, false to hide
7557      * @return {Roo.Component} this
7558      */
7559     setVisible: function(visible){
7560         if(visible) {
7561             this.show();
7562         }else{
7563             this.hide();
7564         }
7565         return this;
7566     },
7567
7568     /**
7569      * Returns true if this component is visible.
7570      */
7571     isVisible : function(){
7572         return this.getActionEl().isVisible();
7573     },
7574
7575     cloneConfig : function(overrides){
7576         overrides = overrides || {};
7577         var id = overrides.id || Roo.id();
7578         var cfg = Roo.applyIf(overrides, this.initialConfig);
7579         cfg.id = id; // prevent dup id
7580         return new this.constructor(cfg);
7581     }
7582 });/*
7583  * Based on:
7584  * Ext JS Library 1.1.1
7585  * Copyright(c) 2006-2007, Ext JS, LLC.
7586  *
7587  * Originally Released Under LGPL - original licence link has changed is not relivant.
7588  *
7589  * Fork - LGPL
7590  * <script type="text/javascript">
7591  */
7592  (function(){ 
7593 /**
7594  * @class Roo.Layer
7595  * @extends Roo.Element
7596  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7597  * automatic maintaining of shadow/shim positions.
7598  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7599  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7600  * you can pass a string with a CSS class name. False turns off the shadow.
7601  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7602  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7603  * @cfg {String} cls CSS class to add to the element
7604  * @cfg {Number} zindex Starting z-index (defaults to 11000)
7605  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7606  * @constructor
7607  * @param {Object} config An object with config options.
7608  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7609  */
7610
7611 Roo.Layer = function(config, existingEl){
7612     config = config || {};
7613     var dh = Roo.DomHelper;
7614     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7615     if(existingEl){
7616         this.dom = Roo.getDom(existingEl);
7617     }
7618     if(!this.dom){
7619         var o = config.dh || {tag: "div", cls: "x-layer"};
7620         this.dom = dh.append(pel, o);
7621     }
7622     if(config.cls){
7623         this.addClass(config.cls);
7624     }
7625     this.constrain = config.constrain !== false;
7626     this.visibilityMode = Roo.Element.VISIBILITY;
7627     if(config.id){
7628         this.id = this.dom.id = config.id;
7629     }else{
7630         this.id = Roo.id(this.dom);
7631     }
7632     this.zindex = config.zindex || this.getZIndex();
7633     this.position("absolute", this.zindex);
7634     if(config.shadow){
7635         this.shadowOffset = config.shadowOffset || 4;
7636         this.shadow = new Roo.Shadow({
7637             offset : this.shadowOffset,
7638             mode : config.shadow
7639         });
7640     }else{
7641         this.shadowOffset = 0;
7642     }
7643     this.useShim = config.shim !== false && Roo.useShims;
7644     this.useDisplay = config.useDisplay;
7645     this.hide();
7646 };
7647
7648 var supr = Roo.Element.prototype;
7649
7650 // shims are shared among layer to keep from having 100 iframes
7651 var shims = [];
7652
7653 Roo.extend(Roo.Layer, Roo.Element, {
7654
7655     getZIndex : function(){
7656         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7657     },
7658
7659     getShim : function(){
7660         if(!this.useShim){
7661             return null;
7662         }
7663         if(this.shim){
7664             return this.shim;
7665         }
7666         var shim = shims.shift();
7667         if(!shim){
7668             shim = this.createShim();
7669             shim.enableDisplayMode('block');
7670             shim.dom.style.display = 'none';
7671             shim.dom.style.visibility = 'visible';
7672         }
7673         var pn = this.dom.parentNode;
7674         if(shim.dom.parentNode != pn){
7675             pn.insertBefore(shim.dom, this.dom);
7676         }
7677         shim.setStyle('z-index', this.getZIndex()-2);
7678         this.shim = shim;
7679         return shim;
7680     },
7681
7682     hideShim : function(){
7683         if(this.shim){
7684             this.shim.setDisplayed(false);
7685             shims.push(this.shim);
7686             delete this.shim;
7687         }
7688     },
7689
7690     disableShadow : function(){
7691         if(this.shadow){
7692             this.shadowDisabled = true;
7693             this.shadow.hide();
7694             this.lastShadowOffset = this.shadowOffset;
7695             this.shadowOffset = 0;
7696         }
7697     },
7698
7699     enableShadow : function(show){
7700         if(this.shadow){
7701             this.shadowDisabled = false;
7702             this.shadowOffset = this.lastShadowOffset;
7703             delete this.lastShadowOffset;
7704             if(show){
7705                 this.sync(true);
7706             }
7707         }
7708     },
7709
7710     // private
7711     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7712     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7713     sync : function(doShow){
7714         var sw = this.shadow;
7715         if(!this.updating && this.isVisible() && (sw || this.useShim)){
7716             var sh = this.getShim();
7717
7718             var w = this.getWidth(),
7719                 h = this.getHeight();
7720
7721             var l = this.getLeft(true),
7722                 t = this.getTop(true);
7723
7724             if(sw && !this.shadowDisabled){
7725                 if(doShow && !sw.isVisible()){
7726                     sw.show(this);
7727                 }else{
7728                     sw.realign(l, t, w, h);
7729                 }
7730                 if(sh){
7731                     if(doShow){
7732                        sh.show();
7733                     }
7734                     // fit the shim behind the shadow, so it is shimmed too
7735                     var a = sw.adjusts, s = sh.dom.style;
7736                     s.left = (Math.min(l, l+a.l))+"px";
7737                     s.top = (Math.min(t, t+a.t))+"px";
7738                     s.width = (w+a.w)+"px";
7739                     s.height = (h+a.h)+"px";
7740                 }
7741             }else if(sh){
7742                 if(doShow){
7743                    sh.show();
7744                 }
7745                 sh.setSize(w, h);
7746                 sh.setLeftTop(l, t);
7747             }
7748             
7749         }
7750     },
7751
7752     // private
7753     destroy : function(){
7754         this.hideShim();
7755         if(this.shadow){
7756             this.shadow.hide();
7757         }
7758         this.removeAllListeners();
7759         var pn = this.dom.parentNode;
7760         if(pn){
7761             pn.removeChild(this.dom);
7762         }
7763         Roo.Element.uncache(this.id);
7764     },
7765
7766     remove : function(){
7767         this.destroy();
7768     },
7769
7770     // private
7771     beginUpdate : function(){
7772         this.updating = true;
7773     },
7774
7775     // private
7776     endUpdate : function(){
7777         this.updating = false;
7778         this.sync(true);
7779     },
7780
7781     // private
7782     hideUnders : function(negOffset){
7783         if(this.shadow){
7784             this.shadow.hide();
7785         }
7786         this.hideShim();
7787     },
7788
7789     // private
7790     constrainXY : function(){
7791         if(this.constrain){
7792             var vw = Roo.lib.Dom.getViewWidth(),
7793                 vh = Roo.lib.Dom.getViewHeight();
7794             var s = Roo.get(document).getScroll();
7795
7796             var xy = this.getXY();
7797             var x = xy[0], y = xy[1];   
7798             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7799             // only move it if it needs it
7800             var moved = false;
7801             // first validate right/bottom
7802             if((x + w) > vw+s.left){
7803                 x = vw - w - this.shadowOffset;
7804                 moved = true;
7805             }
7806             if((y + h) > vh+s.top){
7807                 y = vh - h - this.shadowOffset;
7808                 moved = true;
7809             }
7810             // then make sure top/left isn't negative
7811             if(x < s.left){
7812                 x = s.left;
7813                 moved = true;
7814             }
7815             if(y < s.top){
7816                 y = s.top;
7817                 moved = true;
7818             }
7819             if(moved){
7820                 if(this.avoidY){
7821                     var ay = this.avoidY;
7822                     if(y <= ay && (y+h) >= ay){
7823                         y = ay-h-5;   
7824                     }
7825                 }
7826                 xy = [x, y];
7827                 this.storeXY(xy);
7828                 supr.setXY.call(this, xy);
7829                 this.sync();
7830             }
7831         }
7832     },
7833
7834     isVisible : function(){
7835         return this.visible;    
7836     },
7837
7838     // private
7839     showAction : function(){
7840         this.visible = true; // track visibility to prevent getStyle calls
7841         if(this.useDisplay === true){
7842             this.setDisplayed("");
7843         }else if(this.lastXY){
7844             supr.setXY.call(this, this.lastXY);
7845         }else if(this.lastLT){
7846             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7847         }
7848     },
7849
7850     // private
7851     hideAction : function(){
7852         this.visible = false;
7853         if(this.useDisplay === true){
7854             this.setDisplayed(false);
7855         }else{
7856             this.setLeftTop(-10000,-10000);
7857         }
7858     },
7859
7860     // overridden Element method
7861     setVisible : function(v, a, d, c, e){
7862         if(v){
7863             this.showAction();
7864         }
7865         if(a && v){
7866             var cb = function(){
7867                 this.sync(true);
7868                 if(c){
7869                     c();
7870                 }
7871             }.createDelegate(this);
7872             supr.setVisible.call(this, true, true, d, cb, e);
7873         }else{
7874             if(!v){
7875                 this.hideUnders(true);
7876             }
7877             var cb = c;
7878             if(a){
7879                 cb = function(){
7880                     this.hideAction();
7881                     if(c){
7882                         c();
7883                     }
7884                 }.createDelegate(this);
7885             }
7886             supr.setVisible.call(this, v, a, d, cb, e);
7887             if(v){
7888                 this.sync(true);
7889             }else if(!a){
7890                 this.hideAction();
7891             }
7892         }
7893     },
7894
7895     storeXY : function(xy){
7896         delete this.lastLT;
7897         this.lastXY = xy;
7898     },
7899
7900     storeLeftTop : function(left, top){
7901         delete this.lastXY;
7902         this.lastLT = [left, top];
7903     },
7904
7905     // private
7906     beforeFx : function(){
7907         this.beforeAction();
7908         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
7909     },
7910
7911     // private
7912     afterFx : function(){
7913         Roo.Layer.superclass.afterFx.apply(this, arguments);
7914         this.sync(this.isVisible());
7915     },
7916
7917     // private
7918     beforeAction : function(){
7919         if(!this.updating && this.shadow){
7920             this.shadow.hide();
7921         }
7922     },
7923
7924     // overridden Element method
7925     setLeft : function(left){
7926         this.storeLeftTop(left, this.getTop(true));
7927         supr.setLeft.apply(this, arguments);
7928         this.sync();
7929     },
7930
7931     setTop : function(top){
7932         this.storeLeftTop(this.getLeft(true), top);
7933         supr.setTop.apply(this, arguments);
7934         this.sync();
7935     },
7936
7937     setLeftTop : function(left, top){
7938         this.storeLeftTop(left, top);
7939         supr.setLeftTop.apply(this, arguments);
7940         this.sync();
7941     },
7942
7943     setXY : function(xy, a, d, c, e){
7944         this.fixDisplay();
7945         this.beforeAction();
7946         this.storeXY(xy);
7947         var cb = this.createCB(c);
7948         supr.setXY.call(this, xy, a, d, cb, e);
7949         if(!a){
7950             cb();
7951         }
7952     },
7953
7954     // private
7955     createCB : function(c){
7956         var el = this;
7957         return function(){
7958             el.constrainXY();
7959             el.sync(true);
7960             if(c){
7961                 c();
7962             }
7963         };
7964     },
7965
7966     // overridden Element method
7967     setX : function(x, a, d, c, e){
7968         this.setXY([x, this.getY()], a, d, c, e);
7969     },
7970
7971     // overridden Element method
7972     setY : function(y, a, d, c, e){
7973         this.setXY([this.getX(), y], a, d, c, e);
7974     },
7975
7976     // overridden Element method
7977     setSize : function(w, h, a, d, c, e){
7978         this.beforeAction();
7979         var cb = this.createCB(c);
7980         supr.setSize.call(this, w, h, a, d, cb, e);
7981         if(!a){
7982             cb();
7983         }
7984     },
7985
7986     // overridden Element method
7987     setWidth : function(w, a, d, c, e){
7988         this.beforeAction();
7989         var cb = this.createCB(c);
7990         supr.setWidth.call(this, w, a, d, cb, e);
7991         if(!a){
7992             cb();
7993         }
7994     },
7995
7996     // overridden Element method
7997     setHeight : function(h, a, d, c, e){
7998         this.beforeAction();
7999         var cb = this.createCB(c);
8000         supr.setHeight.call(this, h, a, d, cb, e);
8001         if(!a){
8002             cb();
8003         }
8004     },
8005
8006     // overridden Element method
8007     setBounds : function(x, y, w, h, a, d, c, e){
8008         this.beforeAction();
8009         var cb = this.createCB(c);
8010         if(!a){
8011             this.storeXY([x, y]);
8012             supr.setXY.call(this, [x, y]);
8013             supr.setSize.call(this, w, h, a, d, cb, e);
8014             cb();
8015         }else{
8016             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8017         }
8018         return this;
8019     },
8020     
8021     /**
8022      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8023      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8024      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8025      * @param {Number} zindex The new z-index to set
8026      * @return {this} The Layer
8027      */
8028     setZIndex : function(zindex){
8029         this.zindex = zindex;
8030         this.setStyle("z-index", zindex + 2);
8031         if(this.shadow){
8032             this.shadow.setZIndex(zindex + 1);
8033         }
8034         if(this.shim){
8035             this.shim.setStyle("z-index", zindex);
8036         }
8037     }
8038 });
8039 })();/*
8040  * Based on:
8041  * Ext JS Library 1.1.1
8042  * Copyright(c) 2006-2007, Ext JS, LLC.
8043  *
8044  * Originally Released Under LGPL - original licence link has changed is not relivant.
8045  *
8046  * Fork - LGPL
8047  * <script type="text/javascript">
8048  */
8049
8050
8051 /**
8052  * @class Roo.Shadow
8053  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
8054  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
8055  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8056  * @constructor
8057  * Create a new Shadow
8058  * @param {Object} config The config object
8059  */
8060 Roo.Shadow = function(config){
8061     Roo.apply(this, config);
8062     if(typeof this.mode != "string"){
8063         this.mode = this.defaultMode;
8064     }
8065     var o = this.offset, a = {h: 0};
8066     var rad = Math.floor(this.offset/2);
8067     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8068         case "drop":
8069             a.w = 0;
8070             a.l = a.t = o;
8071             a.t -= 1;
8072             if(Roo.isIE){
8073                 a.l -= this.offset + rad;
8074                 a.t -= this.offset + rad;
8075                 a.w -= rad;
8076                 a.h -= rad;
8077                 a.t += 1;
8078             }
8079         break;
8080         case "sides":
8081             a.w = (o*2);
8082             a.l = -o;
8083             a.t = o-1;
8084             if(Roo.isIE){
8085                 a.l -= (this.offset - rad);
8086                 a.t -= this.offset + rad;
8087                 a.l += 1;
8088                 a.w -= (this.offset - rad)*2;
8089                 a.w -= rad + 1;
8090                 a.h -= 1;
8091             }
8092         break;
8093         case "frame":
8094             a.w = a.h = (o*2);
8095             a.l = a.t = -o;
8096             a.t += 1;
8097             a.h -= 2;
8098             if(Roo.isIE){
8099                 a.l -= (this.offset - rad);
8100                 a.t -= (this.offset - rad);
8101                 a.l += 1;
8102                 a.w -= (this.offset + rad + 1);
8103                 a.h -= (this.offset + rad);
8104                 a.h += 1;
8105             }
8106         break;
8107     };
8108
8109     this.adjusts = a;
8110 };
8111
8112 Roo.Shadow.prototype = {
8113     /**
8114      * @cfg {String} mode
8115      * The shadow display mode.  Supports the following options:<br />
8116      * sides: Shadow displays on both sides and bottom only<br />
8117      * frame: Shadow displays equally on all four sides<br />
8118      * drop: Traditional bottom-right drop shadow (default)
8119      */
8120     /**
8121      * @cfg {String} offset
8122      * The number of pixels to offset the shadow from the element (defaults to 4)
8123      */
8124     offset: 4,
8125
8126     // private
8127     defaultMode: "drop",
8128
8129     /**
8130      * Displays the shadow under the target element
8131      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8132      */
8133     show : function(target){
8134         target = Roo.get(target);
8135         if(!this.el){
8136             this.el = Roo.Shadow.Pool.pull();
8137             if(this.el.dom.nextSibling != target.dom){
8138                 this.el.insertBefore(target);
8139             }
8140         }
8141         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8142         if(Roo.isIE){
8143             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8144         }
8145         this.realign(
8146             target.getLeft(true),
8147             target.getTop(true),
8148             target.getWidth(),
8149             target.getHeight()
8150         );
8151         this.el.dom.style.display = "block";
8152     },
8153
8154     /**
8155      * Returns true if the shadow is visible, else false
8156      */
8157     isVisible : function(){
8158         return this.el ? true : false;  
8159     },
8160
8161     /**
8162      * Direct alignment when values are already available. Show must be called at least once before
8163      * calling this method to ensure it is initialized.
8164      * @param {Number} left The target element left position
8165      * @param {Number} top The target element top position
8166      * @param {Number} width The target element width
8167      * @param {Number} height The target element height
8168      */
8169     realign : function(l, t, w, h){
8170         if(!this.el){
8171             return;
8172         }
8173         var a = this.adjusts, d = this.el.dom, s = d.style;
8174         var iea = 0;
8175         s.left = (l+a.l)+"px";
8176         s.top = (t+a.t)+"px";
8177         var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8178         if(s.width != sws || s.height != shs){
8179             s.width = sws;
8180             s.height = shs;
8181             if(!Roo.isIE){
8182                 var cn = d.childNodes;
8183                 var sww = Math.max(0, (sw-12))+"px";
8184                 cn[0].childNodes[1].style.width = sww;
8185                 cn[1].childNodes[1].style.width = sww;
8186                 cn[2].childNodes[1].style.width = sww;
8187                 cn[1].style.height = Math.max(0, (sh-12))+"px";
8188             }
8189         }
8190     },
8191
8192     /**
8193      * Hides this shadow
8194      */
8195     hide : function(){
8196         if(this.el){
8197             this.el.dom.style.display = "none";
8198             Roo.Shadow.Pool.push(this.el);
8199             delete this.el;
8200         }
8201     },
8202
8203     /**
8204      * Adjust the z-index of this shadow
8205      * @param {Number} zindex The new z-index
8206      */
8207     setZIndex : function(z){
8208         this.zIndex = z;
8209         if(this.el){
8210             this.el.setStyle("z-index", z);
8211         }
8212     }
8213 };
8214
8215 // Private utility class that manages the internal Shadow cache
8216 Roo.Shadow.Pool = function(){
8217     var p = [];
8218     var markup = Roo.isIE ?
8219                  '<div class="x-ie-shadow"></div>' :
8220                  '<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>';
8221     return {
8222         pull : function(){
8223             var sh = p.shift();
8224             if(!sh){
8225                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8226                 sh.autoBoxAdjust = false;
8227             }
8228             return sh;
8229         },
8230
8231         push : function(sh){
8232             p.push(sh);
8233         }
8234     };
8235 }();/*
8236  * Based on:
8237  * Ext JS Library 1.1.1
8238  * Copyright(c) 2006-2007, Ext JS, LLC.
8239  *
8240  * Originally Released Under LGPL - original licence link has changed is not relivant.
8241  *
8242  * Fork - LGPL
8243  * <script type="text/javascript">
8244  */
8245
8246 /**
8247  * @class Roo.BoxComponent
8248  * @extends Roo.Component
8249  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
8250  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
8251  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8252  * layout containers.
8253  * @constructor
8254  * @param {Roo.Element/String/Object} config The configuration options.
8255  */
8256 Roo.BoxComponent = function(config){
8257     Roo.Component.call(this, config);
8258     this.addEvents({
8259         /**
8260          * @event resize
8261          * Fires after the component is resized.
8262              * @param {Roo.Component} this
8263              * @param {Number} adjWidth The box-adjusted width that was set
8264              * @param {Number} adjHeight The box-adjusted height that was set
8265              * @param {Number} rawWidth The width that was originally specified
8266              * @param {Number} rawHeight The height that was originally specified
8267              */
8268         resize : true,
8269         /**
8270          * @event move
8271          * Fires after the component is moved.
8272              * @param {Roo.Component} this
8273              * @param {Number} x The new x position
8274              * @param {Number} y The new y position
8275              */
8276         move : true
8277     });
8278 };
8279
8280 Roo.extend(Roo.BoxComponent, Roo.Component, {
8281     // private, set in afterRender to signify that the component has been rendered
8282     boxReady : false,
8283     // private, used to defer height settings to subclasses
8284     deferHeight: false,
8285     /** @cfg {Number} width
8286      * width (optional) size of component
8287      */
8288      /** @cfg {Number} height
8289      * height (optional) size of component
8290      */
8291      
8292     /**
8293      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
8294      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8295      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8296      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8297      * @return {Roo.BoxComponent} this
8298      */
8299     setSize : function(w, h){
8300         // support for standard size objects
8301         if(typeof w == 'object'){
8302             h = w.height;
8303             w = w.width;
8304         }
8305         // not rendered
8306         if(!this.boxReady){
8307             this.width = w;
8308             this.height = h;
8309             return this;
8310         }
8311
8312         // prevent recalcs when not needed
8313         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8314             return this;
8315         }
8316         this.lastSize = {width: w, height: h};
8317
8318         var adj = this.adjustSize(w, h);
8319         var aw = adj.width, ah = adj.height;
8320         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8321             var rz = this.getResizeEl();
8322             if(!this.deferHeight && aw !== undefined && ah !== undefined){
8323                 rz.setSize(aw, ah);
8324             }else if(!this.deferHeight && ah !== undefined){
8325                 rz.setHeight(ah);
8326             }else if(aw !== undefined){
8327                 rz.setWidth(aw);
8328             }
8329             this.onResize(aw, ah, w, h);
8330             this.fireEvent('resize', this, aw, ah, w, h);
8331         }
8332         return this;
8333     },
8334
8335     /**
8336      * Gets the current size of the component's underlying element.
8337      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8338      */
8339     getSize : function(){
8340         return this.el.getSize();
8341     },
8342
8343     /**
8344      * Gets the current XY position of the component's underlying element.
8345      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8346      * @return {Array} The XY position of the element (e.g., [100, 200])
8347      */
8348     getPosition : function(local){
8349         if(local === true){
8350             return [this.el.getLeft(true), this.el.getTop(true)];
8351         }
8352         return this.xy || this.el.getXY();
8353     },
8354
8355     /**
8356      * Gets the current box measurements of the component's underlying element.
8357      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8358      * @returns {Object} box An object in the format {x, y, width, height}
8359      */
8360     getBox : function(local){
8361         var s = this.el.getSize();
8362         if(local){
8363             s.x = this.el.getLeft(true);
8364             s.y = this.el.getTop(true);
8365         }else{
8366             var xy = this.xy || this.el.getXY();
8367             s.x = xy[0];
8368             s.y = xy[1];
8369         }
8370         return s;
8371     },
8372
8373     /**
8374      * Sets the current box measurements of the component's underlying element.
8375      * @param {Object} box An object in the format {x, y, width, height}
8376      * @returns {Roo.BoxComponent} this
8377      */
8378     updateBox : function(box){
8379         this.setSize(box.width, box.height);
8380         this.setPagePosition(box.x, box.y);
8381         return this;
8382     },
8383
8384     // protected
8385     getResizeEl : function(){
8386         return this.resizeEl || this.el;
8387     },
8388
8389     // protected
8390     getPositionEl : function(){
8391         return this.positionEl || this.el;
8392     },
8393
8394     /**
8395      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
8396      * This method fires the move event.
8397      * @param {Number} left The new left
8398      * @param {Number} top The new top
8399      * @returns {Roo.BoxComponent} this
8400      */
8401     setPosition : function(x, y){
8402         this.x = x;
8403         this.y = y;
8404         if(!this.boxReady){
8405             return this;
8406         }
8407         var adj = this.adjustPosition(x, y);
8408         var ax = adj.x, ay = adj.y;
8409
8410         var el = this.getPositionEl();
8411         if(ax !== undefined || ay !== undefined){
8412             if(ax !== undefined && ay !== undefined){
8413                 el.setLeftTop(ax, ay);
8414             }else if(ax !== undefined){
8415                 el.setLeft(ax);
8416             }else if(ay !== undefined){
8417                 el.setTop(ay);
8418             }
8419             this.onPosition(ax, ay);
8420             this.fireEvent('move', this, ax, ay);
8421         }
8422         return this;
8423     },
8424
8425     /**
8426      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
8427      * This method fires the move event.
8428      * @param {Number} x The new x position
8429      * @param {Number} y The new y position
8430      * @returns {Roo.BoxComponent} this
8431      */
8432     setPagePosition : function(x, y){
8433         this.pageX = x;
8434         this.pageY = y;
8435         if(!this.boxReady){
8436             return;
8437         }
8438         if(x === undefined || y === undefined){ // cannot translate undefined points
8439             return;
8440         }
8441         var p = this.el.translatePoints(x, y);
8442         this.setPosition(p.left, p.top);
8443         return this;
8444     },
8445
8446     // private
8447     onRender : function(ct, position){
8448         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8449         if(this.resizeEl){
8450             this.resizeEl = Roo.get(this.resizeEl);
8451         }
8452         if(this.positionEl){
8453             this.positionEl = Roo.get(this.positionEl);
8454         }
8455     },
8456
8457     // private
8458     afterRender : function(){
8459         Roo.BoxComponent.superclass.afterRender.call(this);
8460         this.boxReady = true;
8461         this.setSize(this.width, this.height);
8462         if(this.x || this.y){
8463             this.setPosition(this.x, this.y);
8464         }
8465         if(this.pageX || this.pageY){
8466             this.setPagePosition(this.pageX, this.pageY);
8467         }
8468     },
8469
8470     /**
8471      * Force the component's size to recalculate based on the underlying element's current height and width.
8472      * @returns {Roo.BoxComponent} this
8473      */
8474     syncSize : function(){
8475         delete this.lastSize;
8476         this.setSize(this.el.getWidth(), this.el.getHeight());
8477         return this;
8478     },
8479
8480     /**
8481      * Called after the component is resized, this method is empty by default but can be implemented by any
8482      * subclass that needs to perform custom logic after a resize occurs.
8483      * @param {Number} adjWidth The box-adjusted width that was set
8484      * @param {Number} adjHeight The box-adjusted height that was set
8485      * @param {Number} rawWidth The width that was originally specified
8486      * @param {Number} rawHeight The height that was originally specified
8487      */
8488     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8489
8490     },
8491
8492     /**
8493      * Called after the component is moved, this method is empty by default but can be implemented by any
8494      * subclass that needs to perform custom logic after a move occurs.
8495      * @param {Number} x The new x position
8496      * @param {Number} y The new y position
8497      */
8498     onPosition : function(x, y){
8499
8500     },
8501
8502     // private
8503     adjustSize : function(w, h){
8504         if(this.autoWidth){
8505             w = 'auto';
8506         }
8507         if(this.autoHeight){
8508             h = 'auto';
8509         }
8510         return {width : w, height: h};
8511     },
8512
8513     // private
8514     adjustPosition : function(x, y){
8515         return {x : x, y: y};
8516     }
8517 });/*
8518  * Based on:
8519  * Ext JS Library 1.1.1
8520  * Copyright(c) 2006-2007, Ext JS, LLC.
8521  *
8522  * Originally Released Under LGPL - original licence link has changed is not relivant.
8523  *
8524  * Fork - LGPL
8525  * <script type="text/javascript">
8526  */
8527
8528
8529 /**
8530  * @class Roo.SplitBar
8531  * @extends Roo.util.Observable
8532  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8533  * <br><br>
8534  * Usage:
8535  * <pre><code>
8536 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8537                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8538 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8539 split.minSize = 100;
8540 split.maxSize = 600;
8541 split.animate = true;
8542 split.on('moved', splitterMoved);
8543 </code></pre>
8544  * @constructor
8545  * Create a new SplitBar
8546  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
8547  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
8548  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8549  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
8550                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8551                         position of the SplitBar).
8552  */
8553 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8554     
8555     /** @private */
8556     this.el = Roo.get(dragElement, true);
8557     this.el.dom.unselectable = "on";
8558     /** @private */
8559     this.resizingEl = Roo.get(resizingElement, true);
8560
8561     /**
8562      * @private
8563      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8564      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8565      * @type Number
8566      */
8567     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8568     
8569     /**
8570      * The minimum size of the resizing element. (Defaults to 0)
8571      * @type Number
8572      */
8573     this.minSize = 0;
8574     
8575     /**
8576      * The maximum size of the resizing element. (Defaults to 2000)
8577      * @type Number
8578      */
8579     this.maxSize = 2000;
8580     
8581     /**
8582      * Whether to animate the transition to the new size
8583      * @type Boolean
8584      */
8585     this.animate = false;
8586     
8587     /**
8588      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8589      * @type Boolean
8590      */
8591     this.useShim = false;
8592     
8593     /** @private */
8594     this.shim = null;
8595     
8596     if(!existingProxy){
8597         /** @private */
8598         this.proxy = Roo.SplitBar.createProxy(this.orientation);
8599     }else{
8600         this.proxy = Roo.get(existingProxy).dom;
8601     }
8602     /** @private */
8603     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8604     
8605     /** @private */
8606     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8607     
8608     /** @private */
8609     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8610     
8611     /** @private */
8612     this.dragSpecs = {};
8613     
8614     /**
8615      * @private The adapter to use to positon and resize elements
8616      */
8617     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8618     this.adapter.init(this);
8619     
8620     if(this.orientation == Roo.SplitBar.HORIZONTAL){
8621         /** @private */
8622         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8623         this.el.addClass("x-splitbar-h");
8624     }else{
8625         /** @private */
8626         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8627         this.el.addClass("x-splitbar-v");
8628     }
8629     
8630     this.addEvents({
8631         /**
8632          * @event resize
8633          * Fires when the splitter is moved (alias for {@link #event-moved})
8634          * @param {Roo.SplitBar} this
8635          * @param {Number} newSize the new width or height
8636          */
8637         "resize" : true,
8638         /**
8639          * @event moved
8640          * Fires when the splitter is moved
8641          * @param {Roo.SplitBar} this
8642          * @param {Number} newSize the new width or height
8643          */
8644         "moved" : true,
8645         /**
8646          * @event beforeresize
8647          * Fires before the splitter is dragged
8648          * @param {Roo.SplitBar} this
8649          */
8650         "beforeresize" : true,
8651
8652         "beforeapply" : true
8653     });
8654
8655     Roo.util.Observable.call(this);
8656 };
8657
8658 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8659     onStartProxyDrag : function(x, y){
8660         this.fireEvent("beforeresize", this);
8661         if(!this.overlay){
8662             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
8663             o.unselectable();
8664             o.enableDisplayMode("block");
8665             // all splitbars share the same overlay
8666             Roo.SplitBar.prototype.overlay = o;
8667         }
8668         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8669         this.overlay.show();
8670         Roo.get(this.proxy).setDisplayed("block");
8671         var size = this.adapter.getElementSize(this);
8672         this.activeMinSize = this.getMinimumSize();;
8673         this.activeMaxSize = this.getMaximumSize();;
8674         var c1 = size - this.activeMinSize;
8675         var c2 = Math.max(this.activeMaxSize - size, 0);
8676         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8677             this.dd.resetConstraints();
8678             this.dd.setXConstraint(
8679                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
8680                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8681             );
8682             this.dd.setYConstraint(0, 0);
8683         }else{
8684             this.dd.resetConstraints();
8685             this.dd.setXConstraint(0, 0);
8686             this.dd.setYConstraint(
8687                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
8688                 this.placement == Roo.SplitBar.TOP ? c2 : c1
8689             );
8690          }
8691         this.dragSpecs.startSize = size;
8692         this.dragSpecs.startPoint = [x, y];
8693         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8694     },
8695     
8696     /** 
8697      * @private Called after the drag operation by the DDProxy
8698      */
8699     onEndProxyDrag : function(e){
8700         Roo.get(this.proxy).setDisplayed(false);
8701         var endPoint = Roo.lib.Event.getXY(e);
8702         if(this.overlay){
8703             this.overlay.hide();
8704         }
8705         var newSize;
8706         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8707             newSize = this.dragSpecs.startSize + 
8708                 (this.placement == Roo.SplitBar.LEFT ?
8709                     endPoint[0] - this.dragSpecs.startPoint[0] :
8710                     this.dragSpecs.startPoint[0] - endPoint[0]
8711                 );
8712         }else{
8713             newSize = this.dragSpecs.startSize + 
8714                 (this.placement == Roo.SplitBar.TOP ?
8715                     endPoint[1] - this.dragSpecs.startPoint[1] :
8716                     this.dragSpecs.startPoint[1] - endPoint[1]
8717                 );
8718         }
8719         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8720         if(newSize != this.dragSpecs.startSize){
8721             if(this.fireEvent('beforeapply', this, newSize) !== false){
8722                 this.adapter.setElementSize(this, newSize);
8723                 this.fireEvent("moved", this, newSize);
8724                 this.fireEvent("resize", this, newSize);
8725             }
8726         }
8727     },
8728     
8729     /**
8730      * Get the adapter this SplitBar uses
8731      * @return The adapter object
8732      */
8733     getAdapter : function(){
8734         return this.adapter;
8735     },
8736     
8737     /**
8738      * Set the adapter this SplitBar uses
8739      * @param {Object} adapter A SplitBar adapter object
8740      */
8741     setAdapter : function(adapter){
8742         this.adapter = adapter;
8743         this.adapter.init(this);
8744     },
8745     
8746     /**
8747      * Gets the minimum size for the resizing element
8748      * @return {Number} The minimum size
8749      */
8750     getMinimumSize : function(){
8751         return this.minSize;
8752     },
8753     
8754     /**
8755      * Sets the minimum size for the resizing element
8756      * @param {Number} minSize The minimum size
8757      */
8758     setMinimumSize : function(minSize){
8759         this.minSize = minSize;
8760     },
8761     
8762     /**
8763      * Gets the maximum size for the resizing element
8764      * @return {Number} The maximum size
8765      */
8766     getMaximumSize : function(){
8767         return this.maxSize;
8768     },
8769     
8770     /**
8771      * Sets the maximum size for the resizing element
8772      * @param {Number} maxSize The maximum size
8773      */
8774     setMaximumSize : function(maxSize){
8775         this.maxSize = maxSize;
8776     },
8777     
8778     /**
8779      * Sets the initialize size for the resizing element
8780      * @param {Number} size The initial size
8781      */
8782     setCurrentSize : function(size){
8783         var oldAnimate = this.animate;
8784         this.animate = false;
8785         this.adapter.setElementSize(this, size);
8786         this.animate = oldAnimate;
8787     },
8788     
8789     /**
8790      * Destroy this splitbar. 
8791      * @param {Boolean} removeEl True to remove the element
8792      */
8793     destroy : function(removeEl){
8794         if(this.shim){
8795             this.shim.remove();
8796         }
8797         this.dd.unreg();
8798         this.proxy.parentNode.removeChild(this.proxy);
8799         if(removeEl){
8800             this.el.remove();
8801         }
8802     }
8803 });
8804
8805 /**
8806  * @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.
8807  */
8808 Roo.SplitBar.createProxy = function(dir){
8809     var proxy = new Roo.Element(document.createElement("div"));
8810     proxy.unselectable();
8811     var cls = 'x-splitbar-proxy';
8812     proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8813     document.body.appendChild(proxy.dom);
8814     return proxy.dom;
8815 };
8816
8817 /** 
8818  * @class Roo.SplitBar.BasicLayoutAdapter
8819  * Default Adapter. It assumes the splitter and resizing element are not positioned
8820  * elements and only gets/sets the width of the element. Generally used for table based layouts.
8821  */
8822 Roo.SplitBar.BasicLayoutAdapter = function(){
8823 };
8824
8825 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8826     // do nothing for now
8827     init : function(s){
8828     
8829     },
8830     /**
8831      * Called before drag operations to get the current size of the resizing element. 
8832      * @param {Roo.SplitBar} s The SplitBar using this adapter
8833      */
8834      getElementSize : function(s){
8835         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8836             return s.resizingEl.getWidth();
8837         }else{
8838             return s.resizingEl.getHeight();
8839         }
8840     },
8841     
8842     /**
8843      * Called after drag operations to set the size of the resizing element.
8844      * @param {Roo.SplitBar} s The SplitBar using this adapter
8845      * @param {Number} newSize The new size to set
8846      * @param {Function} onComplete A function to be invoked when resizing is complete
8847      */
8848     setElementSize : function(s, newSize, onComplete){
8849         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8850             if(!s.animate){
8851                 s.resizingEl.setWidth(newSize);
8852                 if(onComplete){
8853                     onComplete(s, newSize);
8854                 }
8855             }else{
8856                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8857             }
8858         }else{
8859             
8860             if(!s.animate){
8861                 s.resizingEl.setHeight(newSize);
8862                 if(onComplete){
8863                     onComplete(s, newSize);
8864                 }
8865             }else{
8866                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8867             }
8868         }
8869     }
8870 };
8871
8872 /** 
8873  *@class Roo.SplitBar.AbsoluteLayoutAdapter
8874  * @extends Roo.SplitBar.BasicLayoutAdapter
8875  * Adapter that  moves the splitter element to align with the resized sizing element. 
8876  * Used with an absolute positioned SplitBar.
8877  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8878  * document.body, make sure you assign an id to the body element.
8879  */
8880 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8881     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8882     this.container = Roo.get(container);
8883 };
8884
8885 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8886     init : function(s){
8887         this.basic.init(s);
8888     },
8889     
8890     getElementSize : function(s){
8891         return this.basic.getElementSize(s);
8892     },
8893     
8894     setElementSize : function(s, newSize, onComplete){
8895         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8896     },
8897     
8898     moveSplitter : function(s){
8899         var yes = Roo.SplitBar;
8900         switch(s.placement){
8901             case yes.LEFT:
8902                 s.el.setX(s.resizingEl.getRight());
8903                 break;
8904             case yes.RIGHT:
8905                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
8906                 break;
8907             case yes.TOP:
8908                 s.el.setY(s.resizingEl.getBottom());
8909                 break;
8910             case yes.BOTTOM:
8911                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
8912                 break;
8913         }
8914     }
8915 };
8916
8917 /**
8918  * Orientation constant - Create a vertical SplitBar
8919  * @static
8920  * @type Number
8921  */
8922 Roo.SplitBar.VERTICAL = 1;
8923
8924 /**
8925  * Orientation constant - Create a horizontal SplitBar
8926  * @static
8927  * @type Number
8928  */
8929 Roo.SplitBar.HORIZONTAL = 2;
8930
8931 /**
8932  * Placement constant - The resizing element is to the left of the splitter element
8933  * @static
8934  * @type Number
8935  */
8936 Roo.SplitBar.LEFT = 1;
8937
8938 /**
8939  * Placement constant - The resizing element is to the right of the splitter element
8940  * @static
8941  * @type Number
8942  */
8943 Roo.SplitBar.RIGHT = 2;
8944
8945 /**
8946  * Placement constant - The resizing element is positioned above the splitter element
8947  * @static
8948  * @type Number
8949  */
8950 Roo.SplitBar.TOP = 3;
8951
8952 /**
8953  * Placement constant - The resizing element is positioned under splitter element
8954  * @static
8955  * @type Number
8956  */
8957 Roo.SplitBar.BOTTOM = 4;
8958 /*
8959  * Based on:
8960  * Ext JS Library 1.1.1
8961  * Copyright(c) 2006-2007, Ext JS, LLC.
8962  *
8963  * Originally Released Under LGPL - original licence link has changed is not relivant.
8964  *
8965  * Fork - LGPL
8966  * <script type="text/javascript">
8967  */
8968
8969 /**
8970  * @class Roo.View
8971  * @extends Roo.util.Observable
8972  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
8973  * This class also supports single and multi selection modes. <br>
8974  * Create a data model bound view:
8975  <pre><code>
8976  var store = new Roo.data.Store(...);
8977
8978  var view = new Roo.View({
8979     el : "my-element",
8980     template : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
8981  
8982     singleSelect: true,
8983     selectedClass: "ydataview-selected",
8984     store: store
8985  });
8986
8987  // listen for node click?
8988  view.on("click", function(vw, index, node, e){
8989  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8990  });
8991
8992  // load XML data
8993  dataModel.load("foobar.xml");
8994  </code></pre>
8995  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8996  * <br><br>
8997  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8998  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8999  * 
9000  * Note: old style constructor is still suported (container, template, config)
9001  * 
9002  * @constructor
9003  * Create a new View
9004  * @param {Object} config The config object
9005  * 
9006  */
9007 Roo.View = function(config, depreciated_tpl, depreciated_config){
9008     
9009     if (typeof(depreciated_tpl) == 'undefined') {
9010         // new way.. - universal constructor.
9011         Roo.apply(this, config);
9012         this.el  = Roo.get(this.el);
9013     } else {
9014         // old format..
9015         this.el  = Roo.get(config);
9016         this.tpl = depreciated_tpl;
9017         Roo.apply(this, depreciated_config);
9018     }
9019      
9020     
9021     if(typeof(this.tpl) == "string"){
9022         this.tpl = new Roo.Template(this.tpl);
9023     } 
9024     
9025     
9026     this.tpl.compile();
9027    
9028
9029      
9030     /** @private */
9031     this.addEvents({
9032     /**
9033      * @event beforeclick
9034      * Fires before a click is processed. Returns false to cancel the default action.
9035      * @param {Roo.View} this
9036      * @param {Number} index The index of the target node
9037      * @param {HTMLElement} node The target node
9038      * @param {Roo.EventObject} e The raw event object
9039      */
9040         "beforeclick" : true,
9041     /**
9042      * @event click
9043      * Fires when a template node is clicked.
9044      * @param {Roo.View} this
9045      * @param {Number} index The index of the target node
9046      * @param {HTMLElement} node The target node
9047      * @param {Roo.EventObject} e The raw event object
9048      */
9049         "click" : true,
9050     /**
9051      * @event dblclick
9052      * Fires when a template node is double clicked.
9053      * @param {Roo.View} this
9054      * @param {Number} index The index of the target node
9055      * @param {HTMLElement} node The target node
9056      * @param {Roo.EventObject} e The raw event object
9057      */
9058         "dblclick" : true,
9059     /**
9060      * @event contextmenu
9061      * Fires when a template node is right clicked.
9062      * @param {Roo.View} this
9063      * @param {Number} index The index of the target node
9064      * @param {HTMLElement} node The target node
9065      * @param {Roo.EventObject} e The raw event object
9066      */
9067         "contextmenu" : true,
9068     /**
9069      * @event selectionchange
9070      * Fires when the selected nodes change.
9071      * @param {Roo.View} this
9072      * @param {Array} selections Array of the selected nodes
9073      */
9074         "selectionchange" : true,
9075
9076     /**
9077      * @event beforeselect
9078      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9079      * @param {Roo.View} this
9080      * @param {HTMLElement} node The node to be selected
9081      * @param {Array} selections Array of currently selected nodes
9082      */
9083         "beforeselect" : true
9084     });
9085
9086     this.el.on({
9087         "click": this.onClick,
9088         "dblclick": this.onDblClick,
9089         "contextmenu": this.onContextMenu,
9090         scope:this
9091     });
9092
9093     this.selections = [];
9094     this.nodes = [];
9095     this.cmp = new Roo.CompositeElementLite([]);
9096     if(this.store){
9097         this.store = Roo.factory(this.store, Roo.data);
9098         this.setStore(this.store, true);
9099     }
9100     Roo.View.superclass.constructor.call(this);
9101 };
9102
9103 Roo.extend(Roo.View, Roo.util.Observable, {
9104     
9105      /**
9106      * @cfg {Roo.data.Store} Data store to load data from.
9107      */
9108     el : false,
9109     
9110     /**
9111      * @cfg {String|Roo.Element} The container element.
9112      */
9113     el : '',
9114     
9115     /**
9116      * @cfg {String|Roo.DomHelper.Template} The template used by this View 
9117      */
9118     this.tpl : false,
9119     
9120     /**
9121      * @cfg {Roo.DomHelper.Template} The css class to add to selected nodes
9122      */
9123     selectedClass : "x-view-selected",
9124      /**
9125      * @cfg {String} The empty text to show when nothing is loaded.
9126      */
9127     emptyText : "",
9128     /**
9129      * Returns the element this view is bound to.
9130      * @return {Roo.Element}
9131      */
9132     getEl : function(){
9133         return this.el;
9134     },
9135
9136     /**
9137      * Refreshes the view.
9138      */
9139     refresh : function(){
9140         var t = this.tpl;
9141         this.clearSelections();
9142         this.el.update("");
9143         var html = [];
9144         var records = this.store.getRange();
9145         if(records.length < 1){
9146             this.el.update(this.emptyText);
9147             return;
9148         }
9149         for(var i = 0, len = records.length; i < len; i++){
9150             var data = this.prepareData(records[i].data, i, records[i]);
9151             html[html.length] = t.apply(data);
9152         }
9153         this.el.update(html.join(""));
9154         this.nodes = this.el.dom.childNodes;
9155         this.updateIndexes(0);
9156     },
9157
9158     /**
9159      * Function to override to reformat the data that is sent to
9160      * the template for each node.
9161      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9162      * a JSON object for an UpdateManager bound view).
9163      */
9164     prepareData : function(data){
9165         return data;
9166     },
9167
9168     onUpdate : function(ds, record){
9169         this.clearSelections();
9170         var index = this.store.indexOf(record);
9171         var n = this.nodes[index];
9172         this.tpl.insertBefore(n, this.prepareData(record.data));
9173         n.parentNode.removeChild(n);
9174         this.updateIndexes(index, index);
9175     },
9176
9177     onAdd : function(ds, records, index){
9178         this.clearSelections();
9179         if(this.nodes.length == 0){
9180             this.refresh();
9181             return;
9182         }
9183         var n = this.nodes[index];
9184         for(var i = 0, len = records.length; i < len; i++){
9185             var d = this.prepareData(records[i].data);
9186             if(n){
9187                 this.tpl.insertBefore(n, d);
9188             }else{
9189                 this.tpl.append(this.el, d);
9190             }
9191         }
9192         this.updateIndexes(index);
9193     },
9194
9195     onRemove : function(ds, record, index){
9196         this.clearSelections();
9197         this.el.dom.removeChild(this.nodes[index]);
9198         this.updateIndexes(index);
9199     },
9200
9201     /**
9202      * Refresh an individual node.
9203      * @param {Number} index
9204      */
9205     refreshNode : function(index){
9206         this.onUpdate(this.store, this.store.getAt(index));
9207     },
9208
9209     updateIndexes : function(startIndex, endIndex){
9210         var ns = this.nodes;
9211         startIndex = startIndex || 0;
9212         endIndex = endIndex || ns.length - 1;
9213         for(var i = startIndex; i <= endIndex; i++){
9214             ns[i].nodeIndex = i;
9215         }
9216     },
9217
9218     /**
9219      * Changes the data store this view uses and refresh the view.
9220      * @param {Store} store
9221      */
9222     setStore : function(store, initial){
9223         if(!initial && this.store){
9224             this.store.un("datachanged", this.refresh);
9225             this.store.un("add", this.onAdd);
9226             this.store.un("remove", this.onRemove);
9227             this.store.un("update", this.onUpdate);
9228             this.store.un("clear", this.refresh);
9229         }
9230         if(store){
9231           
9232             store.on("datachanged", this.refresh, this);
9233             store.on("add", this.onAdd, this);
9234             store.on("remove", this.onRemove, this);
9235             store.on("update", this.onUpdate, this);
9236             store.on("clear", this.refresh, this);
9237         }
9238         
9239         if(store){
9240             this.refresh();
9241         }
9242     },
9243
9244     /**
9245      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9246      * @param {HTMLElement} node
9247      * @return {HTMLElement} The template node
9248      */
9249     findItemFromChild : function(node){
9250         var el = this.el.dom;
9251         if(!node || node.parentNode == el){
9252                     return node;
9253             }
9254             var p = node.parentNode;
9255             while(p && p != el){
9256             if(p.parentNode == el){
9257                 return p;
9258             }
9259             p = p.parentNode;
9260         }
9261             return null;
9262     },
9263
9264     /** @ignore */
9265     onClick : function(e){
9266         var item = this.findItemFromChild(e.getTarget());
9267         if(item){
9268             var index = this.indexOf(item);
9269             if(this.onItemClick(item, index, e) !== false){
9270                 this.fireEvent("click", this, index, item, e);
9271             }
9272         }else{
9273             this.clearSelections();
9274         }
9275     },
9276
9277     /** @ignore */
9278     onContextMenu : function(e){
9279         var item = this.findItemFromChild(e.getTarget());
9280         if(item){
9281             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9282         }
9283     },
9284
9285     /** @ignore */
9286     onDblClick : function(e){
9287         var item = this.findItemFromChild(e.getTarget());
9288         if(item){
9289             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9290         }
9291     },
9292
9293     onItemClick : function(item, index, e){
9294         if(this.fireEvent("beforeclick", this, index, item, e) === false){
9295             return false;
9296         }
9297         if(this.multiSelect || this.singleSelect){
9298             if(this.multiSelect && e.shiftKey && this.lastSelection){
9299                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9300             }else{
9301                 this.select(item, this.multiSelect && e.ctrlKey);
9302                 this.lastSelection = item;
9303             }
9304             e.preventDefault();
9305         }
9306         return true;
9307     },
9308
9309     /**
9310      * Get the number of selected nodes.
9311      * @return {Number}
9312      */
9313     getSelectionCount : function(){
9314         return this.selections.length;
9315     },
9316
9317     /**
9318      * Get the currently selected nodes.
9319      * @return {Array} An array of HTMLElements
9320      */
9321     getSelectedNodes : function(){
9322         return this.selections;
9323     },
9324
9325     /**
9326      * Get the indexes of the selected nodes.
9327      * @return {Array}
9328      */
9329     getSelectedIndexes : function(){
9330         var indexes = [], s = this.selections;
9331         for(var i = 0, len = s.length; i < len; i++){
9332             indexes.push(s[i].nodeIndex);
9333         }
9334         return indexes;
9335     },
9336
9337     /**
9338      * Clear all selections
9339      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9340      */
9341     clearSelections : function(suppressEvent){
9342         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9343             this.cmp.elements = this.selections;
9344             this.cmp.removeClass(this.selectedClass);
9345             this.selections = [];
9346             if(!suppressEvent){
9347                 this.fireEvent("selectionchange", this, this.selections);
9348             }
9349         }
9350     },
9351
9352     /**
9353      * Returns true if the passed node is selected
9354      * @param {HTMLElement/Number} node The node or node index
9355      * @return {Boolean}
9356      */
9357     isSelected : function(node){
9358         var s = this.selections;
9359         if(s.length < 1){
9360             return false;
9361         }
9362         node = this.getNode(node);
9363         return s.indexOf(node) !== -1;
9364     },
9365
9366     /**
9367      * Selects nodes.
9368      * @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
9369      * @param {Boolean} keepExisting (optional) true to keep existing selections
9370      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9371      */
9372     select : function(nodeInfo, keepExisting, suppressEvent){
9373         if(nodeInfo instanceof Array){
9374             if(!keepExisting){
9375                 this.clearSelections(true);
9376             }
9377             for(var i = 0, len = nodeInfo.length; i < len; i++){
9378                 this.select(nodeInfo[i], true, true);
9379             }
9380         } else{
9381             var node = this.getNode(nodeInfo);
9382             if(node && !this.isSelected(node)){
9383                 if(!keepExisting){
9384                     this.clearSelections(true);
9385                 }
9386                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9387                     Roo.fly(node).addClass(this.selectedClass);
9388                     this.selections.push(node);
9389                     if(!suppressEvent){
9390                         this.fireEvent("selectionchange", this, this.selections);
9391                     }
9392                 }
9393             }
9394         }
9395     },
9396
9397     /**
9398      * Gets a template node.
9399      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9400      * @return {HTMLElement} The node or null if it wasn't found
9401      */
9402     getNode : function(nodeInfo){
9403         if(typeof nodeInfo == "string"){
9404             return document.getElementById(nodeInfo);
9405         }else if(typeof nodeInfo == "number"){
9406             return this.nodes[nodeInfo];
9407         }
9408         return nodeInfo;
9409     },
9410
9411     /**
9412      * Gets a range template nodes.
9413      * @param {Number} startIndex
9414      * @param {Number} endIndex
9415      * @return {Array} An array of nodes
9416      */
9417     getNodes : function(start, end){
9418         var ns = this.nodes;
9419         start = start || 0;
9420         end = typeof end == "undefined" ? ns.length - 1 : end;
9421         var nodes = [];
9422         if(start <= end){
9423             for(var i = start; i <= end; i++){
9424                 nodes.push(ns[i]);
9425             }
9426         } else{
9427             for(var i = start; i >= end; i--){
9428                 nodes.push(ns[i]);
9429             }
9430         }
9431         return nodes;
9432     },
9433
9434     /**
9435      * Finds the index of the passed node
9436      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9437      * @return {Number} The index of the node or -1
9438      */
9439     indexOf : function(node){
9440         node = this.getNode(node);
9441         if(typeof node.nodeIndex == "number"){
9442             return node.nodeIndex;
9443         }
9444         var ns = this.nodes;
9445         for(var i = 0, len = ns.length; i < len; i++){
9446             if(ns[i] == node){
9447                 return i;
9448             }
9449         }
9450         return -1;
9451     }
9452 });
9453 /*
9454  * Based on:
9455  * Ext JS Library 1.1.1
9456  * Copyright(c) 2006-2007, Ext JS, LLC.
9457  *
9458  * Originally Released Under LGPL - original licence link has changed is not relivant.
9459  *
9460  * Fork - LGPL
9461  * <script type="text/javascript">
9462  */
9463
9464 /**
9465  * @class Roo.JsonView
9466  * @extends Roo.View
9467  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9468 <pre><code>
9469 var view = new Roo.JsonView({
9470     container: "my-element",
9471     template: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
9472     multiSelect: true, 
9473     jsonRoot: "data" 
9474 });
9475
9476 // listen for node click?
9477 view.on("click", function(vw, index, node, e){
9478     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9479 });
9480
9481 // direct load of JSON data
9482 view.load("foobar.php");
9483
9484 // Example from my blog list
9485 var tpl = new Roo.Template(
9486     '&lt;div class="entry"&gt;' +
9487     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
9488     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
9489     "&lt;/div&gt;&lt;hr /&gt;"
9490 );
9491
9492 var moreView = new Roo.JsonView({
9493     container :  "entry-list", 
9494     template : tpl,
9495     jsonRoot: "posts"
9496 });
9497 moreView.on("beforerender", this.sortEntries, this);
9498 moreView.load({
9499     url: "/blog/get-posts.php",
9500     params: "allposts=true",
9501     text: "Loading Blog Entries..."
9502 });
9503 </code></pre>
9504
9505 * Note: old code is supported with arguments : (container, template, config)
9506
9507
9508  * @constructor
9509  * Create a new JsonView
9510  * 
9511  * @param {Object} config The config object
9512  * 
9513  */
9514 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9515     
9516     
9517     Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9518
9519     var um = this.el.getUpdateManager();
9520     um.setRenderer(this);
9521     um.on("update", this.onLoad, this);
9522     um.on("failure", this.onLoadException, this);
9523
9524     /**
9525      * @event beforerender
9526      * Fires before rendering of the downloaded JSON data.
9527      * @param {Roo.JsonView} this
9528      * @param {Object} data The JSON data loaded
9529      */
9530     /**
9531      * @event load
9532      * Fires when data is loaded.
9533      * @param {Roo.JsonView} this
9534      * @param {Object} data The JSON data loaded
9535      * @param {Object} response The raw Connect response object
9536      */
9537     /**
9538      * @event loadexception
9539      * Fires when loading fails.
9540      * @param {Roo.JsonView} this
9541      * @param {Object} response The raw Connect response object
9542      */
9543     this.addEvents({
9544         'beforerender' : true,
9545         'load' : true,
9546         'loadexception' : true
9547     });
9548 };
9549 Roo.extend(Roo.JsonView, Roo.View, {
9550     /**
9551      * 
9552      * @cfg {String} The root property in the loaded JSON object that contains the data
9553      */
9554     jsonRoot : "",
9555
9556     /**
9557      * Refreshes the view.
9558      */
9559     refresh : function(){
9560         this.clearSelections();
9561         this.el.update("");
9562         var html = [];
9563         var o = this.jsonData;
9564         if(o && o.length > 0){
9565             for(var i = 0, len = o.length; i < len; i++){
9566                 var data = this.prepareData(o[i], i, o);
9567                 html[html.length] = this.tpl.apply(data);
9568             }
9569         }else{
9570             html.push(this.emptyText);
9571         }
9572         this.el.update(html.join(""));
9573         this.nodes = this.el.dom.childNodes;
9574         this.updateIndexes(0);
9575     },
9576
9577     /**
9578      * 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.
9579      * @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:
9580      <pre><code>
9581      view.load({
9582          url: "your-url.php",
9583          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9584          callback: yourFunction,
9585          scope: yourObject, //(optional scope)
9586          discardUrl: false,
9587          nocache: false,
9588          text: "Loading...",
9589          timeout: 30,
9590          scripts: false
9591      });
9592      </code></pre>
9593      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9594      * 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.
9595      * @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}
9596      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9597      * @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.
9598      */
9599     load : function(){
9600         var um = this.el.getUpdateManager();
9601         um.update.apply(um, arguments);
9602     },
9603
9604     render : function(el, response){
9605         this.clearSelections();
9606         this.el.update("");
9607         var o;
9608         try{
9609             o = Roo.util.JSON.decode(response.responseText);
9610             if(this.jsonRoot){
9611                 
9612                 o = /** eval:var:o */ eval("o." + this.jsonRoot);
9613             }
9614         } catch(e){
9615         }
9616         /**
9617          * The current JSON data or null
9618          */
9619         this.jsonData = o;
9620         this.beforeRender();
9621         this.refresh();
9622     },
9623
9624 /**
9625  * Get the number of records in the current JSON dataset
9626  * @return {Number}
9627  */
9628     getCount : function(){
9629         return this.jsonData ? this.jsonData.length : 0;
9630     },
9631
9632 /**
9633  * Returns the JSON object for the specified node(s)
9634  * @param {HTMLElement/Array} node The node or an array of nodes
9635  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9636  * you get the JSON object for the node
9637  */
9638     getNodeData : function(node){
9639         if(node instanceof Array){
9640             var data = [];
9641             for(var i = 0, len = node.length; i < len; i++){
9642                 data.push(this.getNodeData(node[i]));
9643             }
9644             return data;
9645         }
9646         return this.jsonData[this.indexOf(node)] || null;
9647     },
9648
9649     beforeRender : function(){
9650         this.snapshot = this.jsonData;
9651         if(this.sortInfo){
9652             this.sort.apply(this, this.sortInfo);
9653         }
9654         this.fireEvent("beforerender", this, this.jsonData);
9655     },
9656
9657     onLoad : function(el, o){
9658         this.fireEvent("load", this, this.jsonData, o);
9659     },
9660
9661     onLoadException : function(el, o){
9662         this.fireEvent("loadexception", this, o);
9663     },
9664
9665 /**
9666  * Filter the data by a specific property.
9667  * @param {String} property A property on your JSON objects
9668  * @param {String/RegExp} value Either string that the property values
9669  * should start with, or a RegExp to test against the property
9670  */
9671     filter : function(property, value){
9672         if(this.jsonData){
9673             var data = [];
9674             var ss = this.snapshot;
9675             if(typeof value == "string"){
9676                 var vlen = value.length;
9677                 if(vlen == 0){
9678                     this.clearFilter();
9679                     return;
9680                 }
9681                 value = value.toLowerCase();
9682                 for(var i = 0, len = ss.length; i < len; i++){
9683                     var o = ss[i];
9684                     if(o[property].substr(0, vlen).toLowerCase() == value){
9685                         data.push(o);
9686                     }
9687                 }
9688             } else if(value.exec){ // regex?
9689                 for(var i = 0, len = ss.length; i < len; i++){
9690                     var o = ss[i];
9691                     if(value.test(o[property])){
9692                         data.push(o);
9693                     }
9694                 }
9695             } else{
9696                 return;
9697             }
9698             this.jsonData = data;
9699             this.refresh();
9700         }
9701     },
9702
9703 /**
9704  * Filter by a function. The passed function will be called with each
9705  * object in the current dataset. If the function returns true the value is kept,
9706  * otherwise it is filtered.
9707  * @param {Function} fn
9708  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9709  */
9710     filterBy : function(fn, scope){
9711         if(this.jsonData){
9712             var data = [];
9713             var ss = this.snapshot;
9714             for(var i = 0, len = ss.length; i < len; i++){
9715                 var o = ss[i];
9716                 if(fn.call(scope || this, o)){
9717                     data.push(o);
9718                 }
9719             }
9720             this.jsonData = data;
9721             this.refresh();
9722         }
9723     },
9724
9725 /**
9726  * Clears the current filter.
9727  */
9728     clearFilter : function(){
9729         if(this.snapshot && this.jsonData != this.snapshot){
9730             this.jsonData = this.snapshot;
9731             this.refresh();
9732         }
9733     },
9734
9735
9736 /**
9737  * Sorts the data for this view and refreshes it.
9738  * @param {String} property A property on your JSON objects to sort on
9739  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9740  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9741  */
9742     sort : function(property, dir, sortType){
9743         this.sortInfo = Array.prototype.slice.call(arguments, 0);
9744         if(this.jsonData){
9745             var p = property;
9746             var dsc = dir && dir.toLowerCase() == "desc";
9747             var f = function(o1, o2){
9748                 var v1 = sortType ? sortType(o1[p]) : o1[p];
9749                 var v2 = sortType ? sortType(o2[p]) : o2[p];
9750                 ;
9751                 if(v1 < v2){
9752                     return dsc ? +1 : -1;
9753                 } else if(v1 > v2){
9754                     return dsc ? -1 : +1;
9755                 } else{
9756                     return 0;
9757                 }
9758             };
9759             this.jsonData.sort(f);
9760             this.refresh();
9761             if(this.jsonData != this.snapshot){
9762                 this.snapshot.sort(f);
9763             }
9764         }
9765     }
9766 });/*
9767  * Based on:
9768  * Ext JS Library 1.1.1
9769  * Copyright(c) 2006-2007, Ext JS, LLC.
9770  *
9771  * Originally Released Under LGPL - original licence link has changed is not relivant.
9772  *
9773  * Fork - LGPL
9774  * <script type="text/javascript">
9775  */
9776  
9777
9778 /**
9779  * @class Roo.ColorPalette
9780  * @extends Roo.Component
9781  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
9782  * Here's an example of typical usage:
9783  * <pre><code>
9784 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
9785 cp.render('my-div');
9786
9787 cp.on('select', function(palette, selColor){
9788     // do something with selColor
9789 });
9790 </code></pre>
9791  * @constructor
9792  * Create a new ColorPalette
9793  * @param {Object} config The config object
9794  */
9795 Roo.ColorPalette = function(config){
9796     Roo.ColorPalette.superclass.constructor.call(this, config);
9797     this.addEvents({
9798         /**
9799              * @event select
9800              * Fires when a color is selected
9801              * @param {ColorPalette} this
9802              * @param {String} color The 6-digit color hex code (without the # symbol)
9803              */
9804         select: true
9805     });
9806
9807     if(this.handler){
9808         this.on("select", this.handler, this.scope, true);
9809     }
9810 };
9811 Roo.extend(Roo.ColorPalette, Roo.Component, {
9812     /**
9813      * @cfg {String} itemCls
9814      * The CSS class to apply to the containing element (defaults to "x-color-palette")
9815      */
9816     itemCls : "x-color-palette",
9817     /**
9818      * @cfg {String} value
9819      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
9820      * the hex codes are case-sensitive.
9821      */
9822     value : null,
9823     clickEvent:'click',
9824     // private
9825     ctype: "Roo.ColorPalette",
9826
9827     /**
9828      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9829      */
9830     allowReselect : false,
9831
9832     /**
9833      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
9834      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
9835      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9836      * of colors with the width setting until the box is symmetrical.</p>
9837      * <p>You can override individual colors if needed:</p>
9838      * <pre><code>
9839 var cp = new Roo.ColorPalette();
9840 cp.colors[0] = "FF0000";  // change the first box to red
9841 </code></pre>
9842
9843 Or you can provide a custom array of your own for complete control:
9844 <pre><code>
9845 var cp = new Roo.ColorPalette();
9846 cp.colors = ["000000", "993300", "333300"];
9847 </code></pre>
9848      * @type Array
9849      */
9850     colors : [
9851         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9852         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9853         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9854         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9855         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9856     ],
9857
9858     // private
9859     onRender : function(container, position){
9860         var t = new Roo.MasterTemplate(
9861             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
9862         );
9863         var c = this.colors;
9864         for(var i = 0, len = c.length; i < len; i++){
9865             t.add([c[i]]);
9866         }
9867         var el = document.createElement("div");
9868         el.className = this.itemCls;
9869         t.overwrite(el);
9870         container.dom.insertBefore(el, position);
9871         this.el = Roo.get(el);
9872         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
9873         if(this.clickEvent != 'click'){
9874             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
9875         }
9876     },
9877
9878     // private
9879     afterRender : function(){
9880         Roo.ColorPalette.superclass.afterRender.call(this);
9881         if(this.value){
9882             var s = this.value;
9883             this.value = null;
9884             this.select(s);
9885         }
9886     },
9887
9888     // private
9889     handleClick : function(e, t){
9890         e.preventDefault();
9891         if(!this.disabled){
9892             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9893             this.select(c.toUpperCase());
9894         }
9895     },
9896
9897     /**
9898      * Selects the specified color in the palette (fires the select event)
9899      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
9900      */
9901     select : function(color){
9902         color = color.replace("#", "");
9903         if(color != this.value || this.allowReselect){
9904             var el = this.el;
9905             if(this.value){
9906                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
9907             }
9908             el.child("a.color-"+color).addClass("x-color-palette-sel");
9909             this.value = color;
9910             this.fireEvent("select", this, color);
9911         }
9912     }
9913 });/*
9914  * Based on:
9915  * Ext JS Library 1.1.1
9916  * Copyright(c) 2006-2007, Ext JS, LLC.
9917  *
9918  * Originally Released Under LGPL - original licence link has changed is not relivant.
9919  *
9920  * Fork - LGPL
9921  * <script type="text/javascript">
9922  */
9923  
9924 /**
9925  * @class Roo.DatePicker
9926  * @extends Roo.Component
9927  * Simple date picker class.
9928  * @constructor
9929  * Create a new DatePicker
9930  * @param {Object} config The config object
9931  */
9932 Roo.DatePicker = function(config){
9933     Roo.DatePicker.superclass.constructor.call(this, config);
9934
9935     this.value = config && config.value ?
9936                  config.value.clearTime() : new Date().clearTime();
9937
9938     this.addEvents({
9939         /**
9940              * @event select
9941              * Fires when a date is selected
9942              * @param {DatePicker} this
9943              * @param {Date} date The selected date
9944              */
9945         select: true
9946     });
9947
9948     if(this.handler){
9949         this.on("select", this.handler,  this.scope || this);
9950     }
9951     // build the disabledDatesRE
9952     if(!this.disabledDatesRE && this.disabledDates){
9953         var dd = this.disabledDates;
9954         var re = "(?:";
9955         for(var i = 0; i < dd.length; i++){
9956             re += dd[i];
9957             if(i != dd.length-1) re += "|";
9958         }
9959         this.disabledDatesRE = new RegExp(re + ")");
9960     }
9961 };
9962
9963 Roo.extend(Roo.DatePicker, Roo.Component, {
9964     /**
9965      * @cfg {String} todayText
9966      * The text to display on the button that selects the current date (defaults to "Today")
9967      */
9968     todayText : "Today",
9969     /**
9970      * @cfg {String} okText
9971      * The text to display on the ok button
9972      */
9973     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
9974     /**
9975      * @cfg {String} cancelText
9976      * The text to display on the cancel button
9977      */
9978     cancelText : "Cancel",
9979     /**
9980      * @cfg {String} todayTip
9981      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
9982      */
9983     todayTip : "{0} (Spacebar)",
9984     /**
9985      * @cfg {Date} minDate
9986      * Minimum allowable date (JavaScript date object, defaults to null)
9987      */
9988     minDate : null,
9989     /**
9990      * @cfg {Date} maxDate
9991      * Maximum allowable date (JavaScript date object, defaults to null)
9992      */
9993     maxDate : null,
9994     /**
9995      * @cfg {String} minText
9996      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
9997      */
9998     minText : "This date is before the minimum date",
9999     /**
10000      * @cfg {String} maxText
10001      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10002      */
10003     maxText : "This date is after the maximum date",
10004     /**
10005      * @cfg {String} format
10006      * The default date format string which can be overriden for localization support.  The format must be
10007      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10008      */
10009     format : "m/d/y",
10010     /**
10011      * @cfg {Array} disabledDays
10012      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10013      */
10014     disabledDays : null,
10015     /**
10016      * @cfg {String} disabledDaysText
10017      * The tooltip to display when the date falls on a disabled day (defaults to "")
10018      */
10019     disabledDaysText : "",
10020     /**
10021      * @cfg {RegExp} disabledDatesRE
10022      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10023      */
10024     disabledDatesRE : null,
10025     /**
10026      * @cfg {String} disabledDatesText
10027      * The tooltip text to display when the date falls on a disabled date (defaults to "")
10028      */
10029     disabledDatesText : "",
10030     /**
10031      * @cfg {Boolean} constrainToViewport
10032      * True to constrain the date picker to the viewport (defaults to true)
10033      */
10034     constrainToViewport : true,
10035     /**
10036      * @cfg {Array} monthNames
10037      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10038      */
10039     monthNames : Date.monthNames,
10040     /**
10041      * @cfg {Array} dayNames
10042      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10043      */
10044     dayNames : Date.dayNames,
10045     /**
10046      * @cfg {String} nextText
10047      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10048      */
10049     nextText: 'Next Month (Control+Right)',
10050     /**
10051      * @cfg {String} prevText
10052      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10053      */
10054     prevText: 'Previous Month (Control+Left)',
10055     /**
10056      * @cfg {String} monthYearText
10057      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10058      */
10059     monthYearText: 'Choose a month (Control+Up/Down to move years)',
10060     /**
10061      * @cfg {Number} startDay
10062      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10063      */
10064     startDay : 0,
10065     /**
10066      * @cfg {Bool} showClear
10067      * Show a clear button (usefull for date form elements that can be blank.)
10068      */
10069     
10070     showClear: false,
10071     
10072     /**
10073      * Sets the value of the date field
10074      * @param {Date} value The date to set
10075      */
10076     setValue : function(value){
10077         var old = this.value;
10078         this.value = value.clearTime(true);
10079         if(this.el){
10080             this.update(this.value);
10081         }
10082     },
10083
10084     /**
10085      * Gets the current selected value of the date field
10086      * @return {Date} The selected date
10087      */
10088     getValue : function(){
10089         return this.value;
10090     },
10091
10092     // private
10093     focus : function(){
10094         if(this.el){
10095             this.update(this.activeDate);
10096         }
10097     },
10098
10099     // private
10100     onRender : function(container, position){
10101         var m = [
10102              '<table cellspacing="0">',
10103                 '<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>',
10104                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10105         var dn = this.dayNames;
10106         for(var i = 0; i < 7; i++){
10107             var d = this.startDay+i;
10108             if(d > 6){
10109                 d = d-7;
10110             }
10111             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10112         }
10113         m[m.length] = "</tr></thead><tbody><tr>";
10114         for(var i = 0; i < 42; i++) {
10115             if(i % 7 == 0 && i != 0){
10116                 m[m.length] = "</tr><tr>";
10117             }
10118             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10119         }
10120         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10121             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10122
10123         var el = document.createElement("div");
10124         el.className = "x-date-picker";
10125         el.innerHTML = m.join("");
10126
10127         container.dom.insertBefore(el, position);
10128
10129         this.el = Roo.get(el);
10130         this.eventEl = Roo.get(el.firstChild);
10131
10132         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10133             handler: this.showPrevMonth,
10134             scope: this,
10135             preventDefault:true,
10136             stopDefault:true
10137         });
10138
10139         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10140             handler: this.showNextMonth,
10141             scope: this,
10142             preventDefault:true,
10143             stopDefault:true
10144         });
10145
10146         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
10147
10148         this.monthPicker = this.el.down('div.x-date-mp');
10149         this.monthPicker.enableDisplayMode('block');
10150         
10151         var kn = new Roo.KeyNav(this.eventEl, {
10152             "left" : function(e){
10153                 e.ctrlKey ?
10154                     this.showPrevMonth() :
10155                     this.update(this.activeDate.add("d", -1));
10156             },
10157
10158             "right" : function(e){
10159                 e.ctrlKey ?
10160                     this.showNextMonth() :
10161                     this.update(this.activeDate.add("d", 1));
10162             },
10163
10164             "up" : function(e){
10165                 e.ctrlKey ?
10166                     this.showNextYear() :
10167                     this.update(this.activeDate.add("d", -7));
10168             },
10169
10170             "down" : function(e){
10171                 e.ctrlKey ?
10172                     this.showPrevYear() :
10173                     this.update(this.activeDate.add("d", 7));
10174             },
10175
10176             "pageUp" : function(e){
10177                 this.showNextMonth();
10178             },
10179
10180             "pageDown" : function(e){
10181                 this.showPrevMonth();
10182             },
10183
10184             "enter" : function(e){
10185                 e.stopPropagation();
10186                 return true;
10187             },
10188
10189             scope : this
10190         });
10191
10192         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
10193
10194         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
10195
10196         this.el.unselectable();
10197         
10198         this.cells = this.el.select("table.x-date-inner tbody td");
10199         this.textNodes = this.el.query("table.x-date-inner tbody span");
10200
10201         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10202             text: "&#160;",
10203             tooltip: this.monthYearText
10204         });
10205
10206         this.mbtn.on('click', this.showMonthPicker, this);
10207         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10208
10209
10210         var today = (new Date()).dateFormat(this.format);
10211         
10212         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10213         baseTb.add({
10214             text: String.format(this.todayText, today),
10215             tooltip: String.format(this.todayTip, today),
10216             handler: this.selectToday,
10217             scope: this
10218         });
10219         
10220         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10221             
10222         //});
10223         if (this.showClear) {
10224             
10225             baseTb.add( new Roo.Toolbar.Fill());
10226             baseTb.add({
10227                 text: '&#160;',
10228                 cls: 'x-btn-icon x-btn-clear',
10229                 handler: function() {
10230                     //this.value = '';
10231                     this.fireEvent("select", this, '');
10232                 },
10233                 scope: this
10234             });
10235         }
10236         
10237         
10238         if(Roo.isIE){
10239             this.el.repaint();
10240         }
10241         this.update(this.value);
10242     },
10243
10244     createMonthPicker : function(){
10245         if(!this.monthPicker.dom.firstChild){
10246             var buf = ['<table border="0" cellspacing="0">'];
10247             for(var i = 0; i < 6; i++){
10248                 buf.push(
10249                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10250                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10251                     i == 0 ?
10252                     '<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>' :
10253                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10254                 );
10255             }
10256             buf.push(
10257                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10258                     this.okText,
10259                     '</button><button type="button" class="x-date-mp-cancel">',
10260                     this.cancelText,
10261                     '</button></td></tr>',
10262                 '</table>'
10263             );
10264             this.monthPicker.update(buf.join(''));
10265             this.monthPicker.on('click', this.onMonthClick, this);
10266             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10267
10268             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10269             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10270
10271             this.mpMonths.each(function(m, a, i){
10272                 i += 1;
10273                 if((i%2) == 0){
10274                     m.dom.xmonth = 5 + Math.round(i * .5);
10275                 }else{
10276                     m.dom.xmonth = Math.round((i-1) * .5);
10277                 }
10278             });
10279         }
10280     },
10281
10282     showMonthPicker : function(){
10283         this.createMonthPicker();
10284         var size = this.el.getSize();
10285         this.monthPicker.setSize(size);
10286         this.monthPicker.child('table').setSize(size);
10287
10288         this.mpSelMonth = (this.activeDate || this.value).getMonth();
10289         this.updateMPMonth(this.mpSelMonth);
10290         this.mpSelYear = (this.activeDate || this.value).getFullYear();
10291         this.updateMPYear(this.mpSelYear);
10292
10293         this.monthPicker.slideIn('t', {duration:.2});
10294     },
10295
10296     updateMPYear : function(y){
10297         this.mpyear = y;
10298         var ys = this.mpYears.elements;
10299         for(var i = 1; i <= 10; i++){
10300             var td = ys[i-1], y2;
10301             if((i%2) == 0){
10302                 y2 = y + Math.round(i * .5);
10303                 td.firstChild.innerHTML = y2;
10304                 td.xyear = y2;
10305             }else{
10306                 y2 = y - (5-Math.round(i * .5));
10307                 td.firstChild.innerHTML = y2;
10308                 td.xyear = y2;
10309             }
10310             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10311         }
10312     },
10313
10314     updateMPMonth : function(sm){
10315         this.mpMonths.each(function(m, a, i){
10316             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10317         });
10318     },
10319
10320     selectMPMonth: function(m){
10321         
10322     },
10323
10324     onMonthClick : function(e, t){
10325         e.stopEvent();
10326         var el = new Roo.Element(t), pn;
10327         if(el.is('button.x-date-mp-cancel')){
10328             this.hideMonthPicker();
10329         }
10330         else if(el.is('button.x-date-mp-ok')){
10331             this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10332             this.hideMonthPicker();
10333         }
10334         else if(pn = el.up('td.x-date-mp-month', 2)){
10335             this.mpMonths.removeClass('x-date-mp-sel');
10336             pn.addClass('x-date-mp-sel');
10337             this.mpSelMonth = pn.dom.xmonth;
10338         }
10339         else if(pn = el.up('td.x-date-mp-year', 2)){
10340             this.mpYears.removeClass('x-date-mp-sel');
10341             pn.addClass('x-date-mp-sel');
10342             this.mpSelYear = pn.dom.xyear;
10343         }
10344         else if(el.is('a.x-date-mp-prev')){
10345             this.updateMPYear(this.mpyear-10);
10346         }
10347         else if(el.is('a.x-date-mp-next')){
10348             this.updateMPYear(this.mpyear+10);
10349         }
10350     },
10351
10352     onMonthDblClick : function(e, t){
10353         e.stopEvent();
10354         var el = new Roo.Element(t), pn;
10355         if(pn = el.up('td.x-date-mp-month', 2)){
10356             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10357             this.hideMonthPicker();
10358         }
10359         else if(pn = el.up('td.x-date-mp-year', 2)){
10360             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10361             this.hideMonthPicker();
10362         }
10363     },
10364
10365     hideMonthPicker : function(disableAnim){
10366         if(this.monthPicker){
10367             if(disableAnim === true){
10368                 this.monthPicker.hide();
10369             }else{
10370                 this.monthPicker.slideOut('t', {duration:.2});
10371             }
10372         }
10373     },
10374
10375     // private
10376     showPrevMonth : function(e){
10377         this.update(this.activeDate.add("mo", -1));
10378     },
10379
10380     // private
10381     showNextMonth : function(e){
10382         this.update(this.activeDate.add("mo", 1));
10383     },
10384
10385     // private
10386     showPrevYear : function(){
10387         this.update(this.activeDate.add("y", -1));
10388     },
10389
10390     // private
10391     showNextYear : function(){
10392         this.update(this.activeDate.add("y", 1));
10393     },
10394
10395     // private
10396     handleMouseWheel : function(e){
10397         var delta = e.getWheelDelta();
10398         if(delta > 0){
10399             this.showPrevMonth();
10400             e.stopEvent();
10401         } else if(delta < 0){
10402             this.showNextMonth();
10403             e.stopEvent();
10404         }
10405     },
10406
10407     // private
10408     handleDateClick : function(e, t){
10409         e.stopEvent();
10410         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10411             this.setValue(new Date(t.dateValue));
10412             this.fireEvent("select", this, this.value);
10413         }
10414     },
10415
10416     // private
10417     selectToday : function(){
10418         this.setValue(new Date().clearTime());
10419         this.fireEvent("select", this, this.value);
10420     },
10421
10422     // private
10423     update : function(date){
10424         var vd = this.activeDate;
10425         this.activeDate = date;
10426         if(vd && this.el){
10427             var t = date.getTime();
10428             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10429                 this.cells.removeClass("x-date-selected");
10430                 this.cells.each(function(c){
10431                    if(c.dom.firstChild.dateValue == t){
10432                        c.addClass("x-date-selected");
10433                        setTimeout(function(){
10434                             try{c.dom.firstChild.focus();}catch(e){}
10435                        }, 50);
10436                        return false;
10437                    }
10438                 });
10439                 return;
10440             }
10441         }
10442         var days = date.getDaysInMonth();
10443         var firstOfMonth = date.getFirstDateOfMonth();
10444         var startingPos = firstOfMonth.getDay()-this.startDay;
10445
10446         if(startingPos <= this.startDay){
10447             startingPos += 7;
10448         }
10449
10450         var pm = date.add("mo", -1);
10451         var prevStart = pm.getDaysInMonth()-startingPos;
10452
10453         var cells = this.cells.elements;
10454         var textEls = this.textNodes;
10455         days += startingPos;
10456
10457         // convert everything to numbers so it's fast
10458         var day = 86400000;
10459         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10460         var today = new Date().clearTime().getTime();
10461         var sel = date.clearTime().getTime();
10462         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10463         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10464         var ddMatch = this.disabledDatesRE;
10465         var ddText = this.disabledDatesText;
10466         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10467         var ddaysText = this.disabledDaysText;
10468         var format = this.format;
10469
10470         var setCellClass = function(cal, cell){
10471             cell.title = "";
10472             var t = d.getTime();
10473             cell.firstChild.dateValue = t;
10474             if(t == today){
10475                 cell.className += " x-date-today";
10476                 cell.title = cal.todayText;
10477             }
10478             if(t == sel){
10479                 cell.className += " x-date-selected";
10480                 setTimeout(function(){
10481                     try{cell.firstChild.focus();}catch(e){}
10482                 }, 50);
10483             }
10484             // disabling
10485             if(t < min) {
10486                 cell.className = " x-date-disabled";
10487                 cell.title = cal.minText;
10488                 return;
10489             }
10490             if(t > max) {
10491                 cell.className = " x-date-disabled";
10492                 cell.title = cal.maxText;
10493                 return;
10494             }
10495             if(ddays){
10496                 if(ddays.indexOf(d.getDay()) != -1){
10497                     cell.title = ddaysText;
10498                     cell.className = " x-date-disabled";
10499                 }
10500             }
10501             if(ddMatch && format){
10502                 var fvalue = d.dateFormat(format);
10503                 if(ddMatch.test(fvalue)){
10504                     cell.title = ddText.replace("%0", fvalue);
10505                     cell.className = " x-date-disabled";
10506                 }
10507             }
10508         };
10509
10510         var i = 0;
10511         for(; i < startingPos; i++) {
10512             textEls[i].innerHTML = (++prevStart);
10513             d.setDate(d.getDate()+1);
10514             cells[i].className = "x-date-prevday";
10515             setCellClass(this, cells[i]);
10516         }
10517         for(; i < days; i++){
10518             intDay = i - startingPos + 1;
10519             textEls[i].innerHTML = (intDay);
10520             d.setDate(d.getDate()+1);
10521             cells[i].className = "x-date-active";
10522             setCellClass(this, cells[i]);
10523         }
10524         var extraDays = 0;
10525         for(; i < 42; i++) {
10526              textEls[i].innerHTML = (++extraDays);
10527              d.setDate(d.getDate()+1);
10528              cells[i].className = "x-date-nextday";
10529              setCellClass(this, cells[i]);
10530         }
10531
10532         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10533
10534         if(!this.internalRender){
10535             var main = this.el.dom.firstChild;
10536             var w = main.offsetWidth;
10537             this.el.setWidth(w + this.el.getBorderWidth("lr"));
10538             Roo.fly(main).setWidth(w);
10539             this.internalRender = true;
10540             // opera does not respect the auto grow header center column
10541             // then, after it gets a width opera refuses to recalculate
10542             // without a second pass
10543             if(Roo.isOpera && !this.secondPass){
10544                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10545                 this.secondPass = true;
10546                 this.update.defer(10, this, [date]);
10547             }
10548         }
10549     }
10550 });/*
10551  * Based on:
10552  * Ext JS Library 1.1.1
10553  * Copyright(c) 2006-2007, Ext JS, LLC.
10554  *
10555  * Originally Released Under LGPL - original licence link has changed is not relivant.
10556  *
10557  * Fork - LGPL
10558  * <script type="text/javascript">
10559  */
10560 /**
10561  * @class Roo.TabPanel
10562  * @extends Roo.util.Observable
10563  * A lightweight tab container.
10564  * <br><br>
10565  * Usage:
10566  * <pre><code>
10567 // basic tabs 1, built from existing content
10568 var tabs = new Roo.TabPanel("tabs1");
10569 tabs.addTab("script", "View Script");
10570 tabs.addTab("markup", "View Markup");
10571 tabs.activate("script");
10572
10573 // more advanced tabs, built from javascript
10574 var jtabs = new Roo.TabPanel("jtabs");
10575 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10576
10577 // set up the UpdateManager
10578 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10579 var updater = tab2.getUpdateManager();
10580 updater.setDefaultUrl("ajax1.htm");
10581 tab2.on('activate', updater.refresh, updater, true);
10582
10583 // Use setUrl for Ajax loading
10584 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10585 tab3.setUrl("ajax2.htm", null, true);
10586
10587 // Disabled tab
10588 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10589 tab4.disable();
10590
10591 jtabs.activate("jtabs-1");
10592  * </code></pre>
10593  * @constructor
10594  * Create a new TabPanel.
10595  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10596  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10597  */
10598 Roo.TabPanel = function(container, config){
10599     /**
10600     * The container element for this TabPanel.
10601     * @type Roo.Element
10602     */
10603     this.el = Roo.get(container, true);
10604     if(config){
10605         if(typeof config == "boolean"){
10606             this.tabPosition = config ? "bottom" : "top";
10607         }else{
10608             Roo.apply(this, config);
10609         }
10610     }
10611     if(this.tabPosition == "bottom"){
10612         this.bodyEl = Roo.get(this.createBody(this.el.dom));
10613         this.el.addClass("x-tabs-bottom");
10614     }
10615     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10616     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10617     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10618     if(Roo.isIE){
10619         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10620     }
10621     if(this.tabPosition != "bottom"){
10622     /** The body element that contains {@link Roo.TabPanelItem} bodies.
10623      * @type Roo.Element
10624      */
10625       this.bodyEl = Roo.get(this.createBody(this.el.dom));
10626       this.el.addClass("x-tabs-top");
10627     }
10628     this.items = [];
10629
10630     this.bodyEl.setStyle("position", "relative");
10631
10632     this.active = null;
10633     this.activateDelegate = this.activate.createDelegate(this);
10634
10635     this.addEvents({
10636         /**
10637          * @event tabchange
10638          * Fires when the active tab changes
10639          * @param {Roo.TabPanel} this
10640          * @param {Roo.TabPanelItem} activePanel The new active tab
10641          */
10642         "tabchange": true,
10643         /**
10644          * @event beforetabchange
10645          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10646          * @param {Roo.TabPanel} this
10647          * @param {Object} e Set cancel to true on this object to cancel the tab change
10648          * @param {Roo.TabPanelItem} tab The tab being changed to
10649          */
10650         "beforetabchange" : true
10651     });
10652
10653     Roo.EventManager.onWindowResize(this.onResize, this);
10654     this.cpad = this.el.getPadding("lr");
10655     this.hiddenCount = 0;
10656
10657     Roo.TabPanel.superclass.constructor.call(this);
10658 };
10659
10660 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10661         /*
10662          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10663          */
10664     tabPosition : "top",
10665         /*
10666          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10667          */
10668     currentTabWidth : 0,
10669         /*
10670          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10671          */
10672     minTabWidth : 40,
10673         /*
10674          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10675          */
10676     maxTabWidth : 250,
10677         /*
10678          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10679          */
10680     preferredTabWidth : 175,
10681         /*
10682          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10683          */
10684     resizeTabs : false,
10685         /*
10686          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10687          */
10688     monitorResize : true,
10689
10690     /**
10691      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10692      * @param {String} id The id of the div to use <b>or create</b>
10693      * @param {String} text The text for the tab
10694      * @param {String} content (optional) Content to put in the TabPanelItem body
10695      * @param {Boolean} closable (optional) True to create a close icon on the tab
10696      * @return {Roo.TabPanelItem} The created TabPanelItem
10697      */
10698     addTab : function(id, text, content, closable){
10699         var item = new Roo.TabPanelItem(this, id, text, closable);
10700         this.addTabItem(item);
10701         if(content){
10702             item.setContent(content);
10703         }
10704         return item;
10705     },
10706
10707     /**
10708      * Returns the {@link Roo.TabPanelItem} with the specified id/index
10709      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10710      * @return {Roo.TabPanelItem}
10711      */
10712     getTab : function(id){
10713         return this.items[id];
10714     },
10715
10716     /**
10717      * Hides the {@link Roo.TabPanelItem} with the specified id/index
10718      * @param {String/Number} id The id or index of the TabPanelItem to hide.
10719      */
10720     hideTab : function(id){
10721         var t = this.items[id];
10722         if(!t.isHidden()){
10723            t.setHidden(true);
10724            this.hiddenCount++;
10725            this.autoSizeTabs();
10726         }
10727     },
10728
10729     /**
10730      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10731      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10732      */
10733     unhideTab : function(id){
10734         var t = this.items[id];
10735         if(t.isHidden()){
10736            t.setHidden(false);
10737            this.hiddenCount--;
10738            this.autoSizeTabs();
10739         }
10740     },
10741
10742     /**
10743      * Adds an existing {@link Roo.TabPanelItem}.
10744      * @param {Roo.TabPanelItem} item The TabPanelItem to add
10745      */
10746     addTabItem : function(item){
10747         this.items[item.id] = item;
10748         this.items.push(item);
10749         if(this.resizeTabs){
10750            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10751            this.autoSizeTabs();
10752         }else{
10753             item.autoSize();
10754         }
10755     },
10756
10757     /**
10758      * Removes a {@link Roo.TabPanelItem}.
10759      * @param {String/Number} id The id or index of the TabPanelItem to remove.
10760      */
10761     removeTab : function(id){
10762         var items = this.items;
10763         var tab = items[id];
10764         if(!tab) return;
10765         var index = items.indexOf(tab);
10766         if(this.active == tab && items.length > 1){
10767             var newTab = this.getNextAvailable(index);
10768             if(newTab)newTab.activate();
10769         }
10770         this.stripEl.dom.removeChild(tab.pnode.dom);
10771         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10772             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10773         }
10774         items.splice(index, 1);
10775         delete this.items[tab.id];
10776         tab.fireEvent("close", tab);
10777         tab.purgeListeners();
10778         this.autoSizeTabs();
10779     },
10780
10781     getNextAvailable : function(start){
10782         var items = this.items;
10783         var index = start;
10784         // look for a next tab that will slide over to
10785         // replace the one being removed
10786         while(index < items.length){
10787             var item = items[++index];
10788             if(item && !item.isHidden()){
10789                 return item;
10790             }
10791         }
10792         // if one isn't found select the previous tab (on the left)
10793         index = start;
10794         while(index >= 0){
10795             var item = items[--index];
10796             if(item && !item.isHidden()){
10797                 return item;
10798             }
10799         }
10800         return null;
10801     },
10802
10803     /**
10804      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10805      * @param {String/Number} id The id or index of the TabPanelItem to disable.
10806      */
10807     disableTab : function(id){
10808         var tab = this.items[id];
10809         if(tab && this.active != tab){
10810             tab.disable();
10811         }
10812     },
10813
10814     /**
10815      * Enables a {@link Roo.TabPanelItem} that is disabled.
10816      * @param {String/Number} id The id or index of the TabPanelItem to enable.
10817      */
10818     enableTab : function(id){
10819         var tab = this.items[id];
10820         tab.enable();
10821     },
10822
10823     /**
10824      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10825      * @param {String/Number} id The id or index of the TabPanelItem to activate.
10826      * @return {Roo.TabPanelItem} The TabPanelItem.
10827      */
10828     activate : function(id){
10829         var tab = this.items[id];
10830         if(!tab){
10831             return null;
10832         }
10833         if(tab == this.active || tab.disabled){
10834             return tab;
10835         }
10836         var e = {};
10837         this.fireEvent("beforetabchange", this, e, tab);
10838         if(e.cancel !== true && !tab.disabled){
10839             if(this.active){
10840                 this.active.hide();
10841             }
10842             this.active = this.items[id];
10843             this.active.show();
10844             this.fireEvent("tabchange", this, this.active);
10845         }
10846         return tab;
10847     },
10848
10849     /**
10850      * Gets the active {@link Roo.TabPanelItem}.
10851      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10852      */
10853     getActiveTab : function(){
10854         return this.active;
10855     },
10856
10857     /**
10858      * Updates the tab body element to fit the height of the container element
10859      * for overflow scrolling
10860      * @param {Number} targetHeight (optional) Override the starting height from the elements height
10861      */
10862     syncHeight : function(targetHeight){
10863         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10864         var bm = this.bodyEl.getMargins();
10865         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10866         this.bodyEl.setHeight(newHeight);
10867         return newHeight;
10868     },
10869
10870     onResize : function(){
10871         if(this.monitorResize){
10872             this.autoSizeTabs();
10873         }
10874     },
10875
10876     /**
10877      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10878      */
10879     beginUpdate : function(){
10880         this.updating = true;
10881     },
10882
10883     /**
10884      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10885      */
10886     endUpdate : function(){
10887         this.updating = false;
10888         this.autoSizeTabs();
10889     },
10890
10891     /**
10892      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
10893      */
10894     autoSizeTabs : function(){
10895         var count = this.items.length;
10896         var vcount = count - this.hiddenCount;
10897         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
10898         var w = Math.max(this.el.getWidth() - this.cpad, 10);
10899         var availWidth = Math.floor(w / vcount);
10900         var b = this.stripBody;
10901         if(b.getWidth() > w){
10902             var tabs = this.items;
10903             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
10904             if(availWidth < this.minTabWidth){
10905                 /*if(!this.sleft){    // incomplete scrolling code
10906                     this.createScrollButtons();
10907                 }
10908                 this.showScroll();
10909                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
10910             }
10911         }else{
10912             if(this.currentTabWidth < this.preferredTabWidth){
10913                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
10914             }
10915         }
10916     },
10917
10918     /**
10919      * Returns the number of tabs in this TabPanel.
10920      * @return {Number}
10921      */
10922      getCount : function(){
10923          return this.items.length;
10924      },
10925
10926     /**
10927      * Resizes all the tabs to the passed width
10928      * @param {Number} The new width
10929      */
10930     setTabWidth : function(width){
10931         this.currentTabWidth = width;
10932         for(var i = 0, len = this.items.length; i < len; i++) {
10933                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
10934         }
10935     },
10936
10937     /**
10938      * Destroys this TabPanel
10939      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
10940      */
10941     destroy : function(removeEl){
10942         Roo.EventManager.removeResizeListener(this.onResize, this);
10943         for(var i = 0, len = this.items.length; i < len; i++){
10944             this.items[i].purgeListeners();
10945         }
10946         if(removeEl === true){
10947             this.el.update("");
10948             this.el.remove();
10949         }
10950     }
10951 });
10952
10953 /**
10954  * @class Roo.TabPanelItem
10955  * @extends Roo.util.Observable
10956  * Represents an individual item (tab plus body) in a TabPanel.
10957  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
10958  * @param {String} id The id of this TabPanelItem
10959  * @param {String} text The text for the tab of this TabPanelItem
10960  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
10961  */
10962 Roo.TabPanelItem = function(tabPanel, id, text, closable){
10963     /**
10964      * The {@link Roo.TabPanel} this TabPanelItem belongs to
10965      * @type Roo.TabPanel
10966      */
10967     this.tabPanel = tabPanel;
10968     /**
10969      * The id for this TabPanelItem
10970      * @type String
10971      */
10972     this.id = id;
10973     /** @private */
10974     this.disabled = false;
10975     /** @private */
10976     this.text = text;
10977     /** @private */
10978     this.loaded = false;
10979     this.closable = closable;
10980
10981     /**
10982      * The body element for this TabPanelItem.
10983      * @type Roo.Element
10984      */
10985     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
10986     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
10987     this.bodyEl.setStyle("display", "block");
10988     this.bodyEl.setStyle("zoom", "1");
10989     this.hideAction();
10990
10991     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
10992     /** @private */
10993     this.el = Roo.get(els.el, true);
10994     this.inner = Roo.get(els.inner, true);
10995     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
10996     this.pnode = Roo.get(els.el.parentNode, true);
10997     this.el.on("mousedown", this.onTabMouseDown, this);
10998     this.el.on("click", this.onTabClick, this);
10999     /** @private */
11000     if(closable){
11001         var c = Roo.get(els.close, true);
11002         c.dom.title = this.closeText;
11003         c.addClassOnOver("close-over");
11004         c.on("click", this.closeClick, this);
11005      }
11006
11007     this.addEvents({
11008          /**
11009          * @event activate
11010          * Fires when this tab becomes the active tab.
11011          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11012          * @param {Roo.TabPanelItem} this
11013          */
11014         "activate": true,
11015         /**
11016          * @event beforeclose
11017          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11018          * @param {Roo.TabPanelItem} this
11019          * @param {Object} e Set cancel to true on this object to cancel the close.
11020          */
11021         "beforeclose": true,
11022         /**
11023          * @event close
11024          * Fires when this tab is closed.
11025          * @param {Roo.TabPanelItem} this
11026          */
11027          "close": true,
11028         /**
11029          * @event deactivate
11030          * Fires when this tab is no longer the active tab.
11031          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11032          * @param {Roo.TabPanelItem} this
11033          */
11034          "deactivate" : true
11035     });
11036     this.hidden = false;
11037
11038     Roo.TabPanelItem.superclass.constructor.call(this);
11039 };
11040
11041 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11042     purgeListeners : function(){
11043        Roo.util.Observable.prototype.purgeListeners.call(this);
11044        this.el.removeAllListeners();
11045     },
11046     /**
11047      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11048      */
11049     show : function(){
11050         this.pnode.addClass("on");
11051         this.showAction();
11052         if(Roo.isOpera){
11053             this.tabPanel.stripWrap.repaint();
11054         }
11055         this.fireEvent("activate", this.tabPanel, this);
11056     },
11057
11058     /**
11059      * Returns true if this tab is the active tab.
11060      * @return {Boolean}
11061      */
11062     isActive : function(){
11063         return this.tabPanel.getActiveTab() == this;
11064     },
11065
11066     /**
11067      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11068      */
11069     hide : function(){
11070         this.pnode.removeClass("on");
11071         this.hideAction();
11072         this.fireEvent("deactivate", this.tabPanel, this);
11073     },
11074
11075     hideAction : function(){
11076         this.bodyEl.hide();
11077         this.bodyEl.setStyle("position", "absolute");
11078         this.bodyEl.setLeft("-20000px");
11079         this.bodyEl.setTop("-20000px");
11080     },
11081
11082     showAction : function(){
11083         this.bodyEl.setStyle("position", "relative");
11084         this.bodyEl.setTop("");
11085         this.bodyEl.setLeft("");
11086         this.bodyEl.show();
11087     },
11088
11089     /**
11090      * Set the tooltip for the tab.
11091      * @param {String} tooltip The tab's tooltip
11092      */
11093     setTooltip : function(text){
11094         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11095             this.textEl.dom.qtip = text;
11096             this.textEl.dom.removeAttribute('title');
11097         }else{
11098             this.textEl.dom.title = text;
11099         }
11100     },
11101
11102     onTabClick : function(e){
11103         e.preventDefault();
11104         this.tabPanel.activate(this.id);
11105     },
11106
11107     onTabMouseDown : function(e){
11108         e.preventDefault();
11109         this.tabPanel.activate(this.id);
11110     },
11111
11112     getWidth : function(){
11113         return this.inner.getWidth();
11114     },
11115
11116     setWidth : function(width){
11117         var iwidth = width - this.pnode.getPadding("lr");
11118         this.inner.setWidth(iwidth);
11119         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11120         this.pnode.setWidth(width);
11121     },
11122
11123     /**
11124      * Show or hide the tab
11125      * @param {Boolean} hidden True to hide or false to show.
11126      */
11127     setHidden : function(hidden){
11128         this.hidden = hidden;
11129         this.pnode.setStyle("display", hidden ? "none" : "");
11130     },
11131
11132     /**
11133      * Returns true if this tab is "hidden"
11134      * @return {Boolean}
11135      */
11136     isHidden : function(){
11137         return this.hidden;
11138     },
11139
11140     /**
11141      * Returns the text for this tab
11142      * @return {String}
11143      */
11144     getText : function(){
11145         return this.text;
11146     },
11147
11148     autoSize : function(){
11149         //this.el.beginMeasure();
11150         this.textEl.setWidth(1);
11151         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11152         //this.el.endMeasure();
11153     },
11154
11155     /**
11156      * Sets the text for the tab (Note: this also sets the tooltip text)
11157      * @param {String} text The tab's text and tooltip
11158      */
11159     setText : function(text){
11160         this.text = text;
11161         this.textEl.update(text);
11162         this.setTooltip(text);
11163         if(!this.tabPanel.resizeTabs){
11164             this.autoSize();
11165         }
11166     },
11167     /**
11168      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11169      */
11170     activate : function(){
11171         this.tabPanel.activate(this.id);
11172     },
11173
11174     /**
11175      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11176      */
11177     disable : function(){
11178         if(this.tabPanel.active != this){
11179             this.disabled = true;
11180             this.pnode.addClass("disabled");
11181         }
11182     },
11183
11184     /**
11185      * Enables this TabPanelItem if it was previously disabled.
11186      */
11187     enable : function(){
11188         this.disabled = false;
11189         this.pnode.removeClass("disabled");
11190     },
11191
11192     /**
11193      * Sets the content for this TabPanelItem.
11194      * @param {String} content The content
11195      * @param {Boolean} loadScripts true to look for and load scripts
11196      */
11197     setContent : function(content, loadScripts){
11198         this.bodyEl.update(content, loadScripts);
11199     },
11200
11201     /**
11202      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11203      * @return {Roo.UpdateManager} The UpdateManager
11204      */
11205     getUpdateManager : function(){
11206         return this.bodyEl.getUpdateManager();
11207     },
11208
11209     /**
11210      * Set a URL to be used to load the content for this TabPanelItem.
11211      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11212      * @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)
11213      * @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)
11214      * @return {Roo.UpdateManager} The UpdateManager
11215      */
11216     setUrl : function(url, params, loadOnce){
11217         if(this.refreshDelegate){
11218             this.un('activate', this.refreshDelegate);
11219         }
11220         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11221         this.on("activate", this.refreshDelegate);
11222         return this.bodyEl.getUpdateManager();
11223     },
11224
11225     /** @private */
11226     _handleRefresh : function(url, params, loadOnce){
11227         if(!loadOnce || !this.loaded){
11228             var updater = this.bodyEl.getUpdateManager();
11229             updater.update(url, params, this._setLoaded.createDelegate(this));
11230         }
11231     },
11232
11233     /**
11234      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
11235      *   Will fail silently if the setUrl method has not been called.
11236      *   This does not activate the panel, just updates its content.
11237      */
11238     refresh : function(){
11239         if(this.refreshDelegate){
11240            this.loaded = false;
11241            this.refreshDelegate();
11242         }
11243     },
11244
11245     /** @private */
11246     _setLoaded : function(){
11247         this.loaded = true;
11248     },
11249
11250     /** @private */
11251     closeClick : function(e){
11252         var o = {};
11253         e.stopEvent();
11254         this.fireEvent("beforeclose", this, o);
11255         if(o.cancel !== true){
11256             this.tabPanel.removeTab(this.id);
11257         }
11258     },
11259     /**
11260      * The text displayed in the tooltip for the close icon.
11261      * @type String
11262      */
11263     closeText : "Close this tab"
11264 });
11265
11266 /** @private */
11267 Roo.TabPanel.prototype.createStrip = function(container){
11268     var strip = document.createElement("div");
11269     strip.className = "x-tabs-wrap";
11270     container.appendChild(strip);
11271     return strip;
11272 };
11273 /** @private */
11274 Roo.TabPanel.prototype.createStripList = function(strip){
11275     // div wrapper for retard IE
11276     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>';
11277     return strip.firstChild.firstChild.firstChild.firstChild;
11278 };
11279 /** @private */
11280 Roo.TabPanel.prototype.createBody = function(container){
11281     var body = document.createElement("div");
11282     Roo.id(body, "tab-body");
11283     Roo.fly(body).addClass("x-tabs-body");
11284     container.appendChild(body);
11285     return body;
11286 };
11287 /** @private */
11288 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11289     var body = Roo.getDom(id);
11290     if(!body){
11291         body = document.createElement("div");
11292         body.id = id;
11293     }
11294     Roo.fly(body).addClass("x-tabs-item-body");
11295     bodyEl.insertBefore(body, bodyEl.firstChild);
11296     return body;
11297 };
11298 /** @private */
11299 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11300     var td = document.createElement("td");
11301     stripEl.appendChild(td);
11302     if(closable){
11303         td.className = "x-tabs-closable";
11304         if(!this.closeTpl){
11305             this.closeTpl = new Roo.Template(
11306                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11307                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11308                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
11309             );
11310         }
11311         var el = this.closeTpl.overwrite(td, {"text": text});
11312         var close = el.getElementsByTagName("div")[0];
11313         var inner = el.getElementsByTagName("em")[0];
11314         return {"el": el, "close": close, "inner": inner};
11315     } else {
11316         if(!this.tabTpl){
11317             this.tabTpl = new Roo.Template(
11318                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11319                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11320             );
11321         }
11322         var el = this.tabTpl.overwrite(td, {"text": text});
11323         var inner = el.getElementsByTagName("em")[0];
11324         return {"el": el, "inner": inner};
11325     }
11326 };/*
11327  * Based on:
11328  * Ext JS Library 1.1.1
11329  * Copyright(c) 2006-2007, Ext JS, LLC.
11330  *
11331  * Originally Released Under LGPL - original licence link has changed is not relivant.
11332  *
11333  * Fork - LGPL
11334  * <script type="text/javascript">
11335  */
11336
11337 /**
11338  * @class Roo.Button
11339  * @extends Roo.util.Observable
11340  * Simple Button class
11341  * @cfg {String} text The button text
11342  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11343  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11344  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11345  * @cfg {Object} scope The scope of the handler
11346  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11347  * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11348  * @cfg {Boolean} hidden True to start hidden (defaults to false)
11349  * @cfg {Boolean} disabled True to start disabled (defaults to false)
11350  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11351  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11352    applies if enableToggle = true)
11353  * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11354  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11355   an {@link Roo.util.ClickRepeater} config object (defaults to false).
11356  * @constructor
11357  * Create a new button
11358  * @param {Object} config The config object
11359  */
11360 Roo.Button = function(renderTo, config)
11361 {
11362     if (!config) {
11363         config = renderTo;
11364         renderTo = config.renderTo || false;
11365     }
11366     
11367     Roo.apply(this, config);
11368     this.addEvents({
11369         /**
11370              * @event click
11371              * Fires when this button is clicked
11372              * @param {Button} this
11373              * @param {EventObject} e The click event
11374              */
11375             "click" : true,
11376         /**
11377              * @event toggle
11378              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11379              * @param {Button} this
11380              * @param {Boolean} pressed
11381              */
11382             "toggle" : true,
11383         /**
11384              * @event mouseover
11385              * Fires when the mouse hovers over the button
11386              * @param {Button} this
11387              * @param {Event} e The event object
11388              */
11389         'mouseover' : true,
11390         /**
11391              * @event mouseout
11392              * Fires when the mouse exits the button
11393              * @param {Button} this
11394              * @param {Event} e The event object
11395              */
11396         'mouseout': true,
11397          /**
11398              * @event render
11399              * Fires when the button is rendered
11400              * @param {Button} this
11401              */
11402         'render': true
11403     });
11404     if(this.menu){
11405         this.menu = Roo.menu.MenuMgr.get(this.menu);
11406     }
11407     if(renderTo){
11408         this.render(renderTo);
11409     }
11410     
11411     Roo.util.Observable.call(this);
11412 };
11413
11414 Roo.extend(Roo.Button, Roo.util.Observable, {
11415     /**
11416      * 
11417      */
11418     
11419     /**
11420      * Read-only. True if this button is hidden
11421      * @type Boolean
11422      */
11423     hidden : false,
11424     /**
11425      * Read-only. True if this button is disabled
11426      * @type Boolean
11427      */
11428     disabled : false,
11429     /**
11430      * Read-only. True if this button is pressed (only if enableToggle = true)
11431      * @type Boolean
11432      */
11433     pressed : false,
11434
11435     /**
11436      * @cfg {Number} tabIndex 
11437      * The DOM tabIndex for this button (defaults to undefined)
11438      */
11439     tabIndex : undefined,
11440
11441     /**
11442      * @cfg {Boolean} enableToggle
11443      * True to enable pressed/not pressed toggling (defaults to false)
11444      */
11445     enableToggle: false,
11446     /**
11447      * @cfg {Mixed} menu
11448      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11449      */
11450     menu : undefined,
11451     /**
11452      * @cfg {String} menuAlign
11453      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11454      */
11455     menuAlign : "tl-bl?",
11456
11457     /**
11458      * @cfg {String} iconCls
11459      * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11460      */
11461     iconCls : undefined,
11462     /**
11463      * @cfg {String} type
11464      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
11465      */
11466     type : 'button',
11467
11468     // private
11469     menuClassTarget: 'tr',
11470
11471     /**
11472      * @cfg {String} clickEvent
11473      * The type of event to map to the button's event handler (defaults to 'click')
11474      */
11475     clickEvent : 'click',
11476
11477     /**
11478      * @cfg {Boolean} handleMouseEvents
11479      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11480      */
11481     handleMouseEvents : true,
11482
11483     /**
11484      * @cfg {String} tooltipType
11485      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11486      */
11487     tooltipType : 'qtip',
11488
11489     /**
11490      * @cfg {String} cls
11491      * A CSS class to apply to the button's main element.
11492      */
11493     
11494     /**
11495      * @cfg {Roo.Template} template (Optional)
11496      * An {@link Roo.Template} with which to create the Button's main element. This Template must
11497      * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11498      * require code modifications if required elements (e.g. a button) aren't present.
11499      */
11500
11501     // private
11502     render : function(renderTo){
11503         var btn;
11504         if(this.hideParent){
11505             this.parentEl = Roo.get(renderTo);
11506         }
11507         if(!this.dhconfig){
11508             if(!this.template){
11509                 if(!Roo.Button.buttonTemplate){
11510                     // hideous table template
11511                     Roo.Button.buttonTemplate = new Roo.Template(
11512                         '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11513                         '<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>',
11514                         "</tr></tbody></table>");
11515                 }
11516                 this.template = Roo.Button.buttonTemplate;
11517             }
11518             btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
11519             var btnEl = btn.child("button:first");
11520             btnEl.on('focus', this.onFocus, this);
11521             btnEl.on('blur', this.onBlur, this);
11522             if(this.cls){
11523                 btn.addClass(this.cls);
11524             }
11525             if(this.icon){
11526                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11527             }
11528             if(this.iconCls){
11529                 btnEl.addClass(this.iconCls);
11530                 if(!this.cls){
11531                     btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11532                 }
11533             }
11534             if(this.tabIndex !== undefined){
11535                 btnEl.dom.tabIndex = this.tabIndex;
11536             }
11537             if(this.tooltip){
11538                 if(typeof this.tooltip == 'object'){
11539                     Roo.QuickTips.tips(Roo.apply({
11540                           target: btnEl.id
11541                     }, this.tooltip));
11542                 } else {
11543                     btnEl.dom[this.tooltipType] = this.tooltip;
11544                 }
11545             }
11546         }else{
11547             btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11548         }
11549         this.el = btn;
11550         if(this.id){
11551             this.el.dom.id = this.el.id = this.id;
11552         }
11553         if(this.menu){
11554             this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11555             this.menu.on("show", this.onMenuShow, this);
11556             this.menu.on("hide", this.onMenuHide, this);
11557         }
11558         btn.addClass("x-btn");
11559         if(Roo.isIE && !Roo.isIE7){
11560             this.autoWidth.defer(1, this);
11561         }else{
11562             this.autoWidth();
11563         }
11564         if(this.handleMouseEvents){
11565             btn.on("mouseover", this.onMouseOver, this);
11566             btn.on("mouseout", this.onMouseOut, this);
11567             btn.on("mousedown", this.onMouseDown, this);
11568         }
11569         btn.on(this.clickEvent, this.onClick, this);
11570         //btn.on("mouseup", this.onMouseUp, this);
11571         if(this.hidden){
11572             this.hide();
11573         }
11574         if(this.disabled){
11575             this.disable();
11576         }
11577         Roo.ButtonToggleMgr.register(this);
11578         if(this.pressed){
11579             this.el.addClass("x-btn-pressed");
11580         }
11581         if(this.repeat){
11582             var repeater = new Roo.util.ClickRepeater(btn,
11583                 typeof this.repeat == "object" ? this.repeat : {}
11584             );
11585             repeater.on("click", this.onClick,  this);
11586         }
11587         this.fireEvent('render', this);
11588         
11589     },
11590     /**
11591      * Returns the button's underlying element
11592      * @return {Roo.Element} The element
11593      */
11594     getEl : function(){
11595         return this.el;  
11596     },
11597     
11598     /**
11599      * Destroys this Button and removes any listeners.
11600      */
11601     destroy : function(){
11602         Roo.ButtonToggleMgr.unregister(this);
11603         this.el.removeAllListeners();
11604         this.purgeListeners();
11605         this.el.remove();
11606     },
11607
11608     // private
11609     autoWidth : function(){
11610         if(this.el){
11611             this.el.setWidth("auto");
11612             if(Roo.isIE7 && Roo.isStrict){
11613                 var ib = this.el.child('button');
11614                 if(ib && ib.getWidth() > 20){
11615                     ib.clip();
11616                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11617                 }
11618             }
11619             if(this.minWidth){
11620                 if(this.hidden){
11621                     this.el.beginMeasure();
11622                 }
11623                 if(this.el.getWidth() < this.minWidth){
11624                     this.el.setWidth(this.minWidth);
11625                 }
11626                 if(this.hidden){
11627                     this.el.endMeasure();
11628                 }
11629             }
11630         }
11631     },
11632
11633     /**
11634      * Assigns this button's click handler
11635      * @param {Function} handler The function to call when the button is clicked
11636      * @param {Object} scope (optional) Scope for the function passed in
11637      */
11638     setHandler : function(handler, scope){
11639         this.handler = handler;
11640         this.scope = scope;  
11641     },
11642     
11643     /**
11644      * Sets this button's text
11645      * @param {String} text The button text
11646      */
11647     setText : function(text){
11648         this.text = text;
11649         if(this.el){
11650             this.el.child("td.x-btn-center button.x-btn-text").update(text);
11651         }
11652         this.autoWidth();
11653     },
11654     
11655     /**
11656      * Gets the text for this button
11657      * @return {String} The button text
11658      */
11659     getText : function(){
11660         return this.text;  
11661     },
11662     
11663     /**
11664      * Show this button
11665      */
11666     show: function(){
11667         this.hidden = false;
11668         if(this.el){
11669             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11670         }
11671     },
11672     
11673     /**
11674      * Hide this button
11675      */
11676     hide: function(){
11677         this.hidden = true;
11678         if(this.el){
11679             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11680         }
11681     },
11682     
11683     /**
11684      * Convenience function for boolean show/hide
11685      * @param {Boolean} visible True to show, false to hide
11686      */
11687     setVisible: function(visible){
11688         if(visible) {
11689             this.show();
11690         }else{
11691             this.hide();
11692         }
11693     },
11694     
11695     /**
11696      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11697      * @param {Boolean} state (optional) Force a particular state
11698      */
11699     toggle : function(state){
11700         state = state === undefined ? !this.pressed : state;
11701         if(state != this.pressed){
11702             if(state){
11703                 this.el.addClass("x-btn-pressed");
11704                 this.pressed = true;
11705                 this.fireEvent("toggle", this, true);
11706             }else{
11707                 this.el.removeClass("x-btn-pressed");
11708                 this.pressed = false;
11709                 this.fireEvent("toggle", this, false);
11710             }
11711             if(this.toggleHandler){
11712                 this.toggleHandler.call(this.scope || this, this, state);
11713             }
11714         }
11715     },
11716     
11717     /**
11718      * Focus the button
11719      */
11720     focus : function(){
11721         this.el.child('button:first').focus();
11722     },
11723     
11724     /**
11725      * Disable this button
11726      */
11727     disable : function(){
11728         if(this.el){
11729             this.el.addClass("x-btn-disabled");
11730         }
11731         this.disabled = true;
11732     },
11733     
11734     /**
11735      * Enable this button
11736      */
11737     enable : function(){
11738         if(this.el){
11739             this.el.removeClass("x-btn-disabled");
11740         }
11741         this.disabled = false;
11742     },
11743
11744     /**
11745      * Convenience function for boolean enable/disable
11746      * @param {Boolean} enabled True to enable, false to disable
11747      */
11748     setDisabled : function(v){
11749         this[v !== true ? "enable" : "disable"]();
11750     },
11751
11752     // private
11753     onClick : function(e){
11754         if(e){
11755             e.preventDefault();
11756         }
11757         if(e.button != 0){
11758             return;
11759         }
11760         if(!this.disabled){
11761             if(this.enableToggle){
11762                 this.toggle();
11763             }
11764             if(this.menu && !this.menu.isVisible()){
11765                 this.menu.show(this.el, this.menuAlign);
11766             }
11767             this.fireEvent("click", this, e);
11768             if(this.handler){
11769                 this.el.removeClass("x-btn-over");
11770                 this.handler.call(this.scope || this, this, e);
11771             }
11772         }
11773     },
11774     // private
11775     onMouseOver : function(e){
11776         if(!this.disabled){
11777             this.el.addClass("x-btn-over");
11778             this.fireEvent('mouseover', this, e);
11779         }
11780     },
11781     // private
11782     onMouseOut : function(e){
11783         if(!e.within(this.el,  true)){
11784             this.el.removeClass("x-btn-over");
11785             this.fireEvent('mouseout', this, e);
11786         }
11787     },
11788     // private
11789     onFocus : function(e){
11790         if(!this.disabled){
11791             this.el.addClass("x-btn-focus");
11792         }
11793     },
11794     // private
11795     onBlur : function(e){
11796         this.el.removeClass("x-btn-focus");
11797     },
11798     // private
11799     onMouseDown : function(e){
11800         if(!this.disabled && e.button == 0){
11801             this.el.addClass("x-btn-click");
11802             Roo.get(document).on('mouseup', this.onMouseUp, this);
11803         }
11804     },
11805     // private
11806     onMouseUp : function(e){
11807         if(e.button == 0){
11808             this.el.removeClass("x-btn-click");
11809             Roo.get(document).un('mouseup', this.onMouseUp, this);
11810         }
11811     },
11812     // private
11813     onMenuShow : function(e){
11814         this.el.addClass("x-btn-menu-active");
11815     },
11816     // private
11817     onMenuHide : function(e){
11818         this.el.removeClass("x-btn-menu-active");
11819     }   
11820 });
11821
11822 // Private utility class used by Button
11823 Roo.ButtonToggleMgr = function(){
11824    var groups = {};
11825    
11826    function toggleGroup(btn, state){
11827        if(state){
11828            var g = groups[btn.toggleGroup];
11829            for(var i = 0, l = g.length; i < l; i++){
11830                if(g[i] != btn){
11831                    g[i].toggle(false);
11832                }
11833            }
11834        }
11835    }
11836    
11837    return {
11838        register : function(btn){
11839            if(!btn.toggleGroup){
11840                return;
11841            }
11842            var g = groups[btn.toggleGroup];
11843            if(!g){
11844                g = groups[btn.toggleGroup] = [];
11845            }
11846            g.push(btn);
11847            btn.on("toggle", toggleGroup);
11848        },
11849        
11850        unregister : function(btn){
11851            if(!btn.toggleGroup){
11852                return;
11853            }
11854            var g = groups[btn.toggleGroup];
11855            if(g){
11856                g.remove(btn);
11857                btn.un("toggle", toggleGroup);
11858            }
11859        }
11860    };
11861 }();/*
11862  * Based on:
11863  * Ext JS Library 1.1.1
11864  * Copyright(c) 2006-2007, Ext JS, LLC.
11865  *
11866  * Originally Released Under LGPL - original licence link has changed is not relivant.
11867  *
11868  * Fork - LGPL
11869  * <script type="text/javascript">
11870  */
11871  
11872 /**
11873  * @class Roo.SplitButton
11874  * @extends Roo.Button
11875  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11876  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
11877  * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11878  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11879  * @cfg {String} arrowTooltip The title attribute of the arrow
11880  * @constructor
11881  * Create a new menu button
11882  * @param {String/HTMLElement/Element} renderTo The element to append the button to
11883  * @param {Object} config The config object
11884  */
11885 Roo.SplitButton = function(renderTo, config){
11886     Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
11887     /**
11888      * @event arrowclick
11889      * Fires when this button's arrow is clicked
11890      * @param {SplitButton} this
11891      * @param {EventObject} e The click event
11892      */
11893     this.addEvents({"arrowclick":true});
11894 };
11895
11896 Roo.extend(Roo.SplitButton, Roo.Button, {
11897     render : function(renderTo){
11898         // this is one sweet looking template!
11899         var tpl = new Roo.Template(
11900             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
11901             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
11902             '<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>',
11903             "</tbody></table></td><td>",
11904             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
11905             '<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>',
11906             "</tbody></table></td></tr></table>"
11907         );
11908         var btn = tpl.append(renderTo, [this.text, this.type], true);
11909         var btnEl = btn.child("button");
11910         if(this.cls){
11911             btn.addClass(this.cls);
11912         }
11913         if(this.icon){
11914             btnEl.setStyle('background-image', 'url(' +this.icon +')');
11915         }
11916         if(this.iconCls){
11917             btnEl.addClass(this.iconCls);
11918             if(!this.cls){
11919                 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11920             }
11921         }
11922         this.el = btn;
11923         if(this.handleMouseEvents){
11924             btn.on("mouseover", this.onMouseOver, this);
11925             btn.on("mouseout", this.onMouseOut, this);
11926             btn.on("mousedown", this.onMouseDown, this);
11927             btn.on("mouseup", this.onMouseUp, this);
11928         }
11929         btn.on(this.clickEvent, this.onClick, this);
11930         if(this.tooltip){
11931             if(typeof this.tooltip == 'object'){
11932                 Roo.QuickTips.tips(Roo.apply({
11933                       target: btnEl.id
11934                 }, this.tooltip));
11935             } else {
11936                 btnEl.dom[this.tooltipType] = this.tooltip;
11937             }
11938         }
11939         if(this.arrowTooltip){
11940             btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
11941         }
11942         if(this.hidden){
11943             this.hide();
11944         }
11945         if(this.disabled){
11946             this.disable();
11947         }
11948         if(this.pressed){
11949             this.el.addClass("x-btn-pressed");
11950         }
11951         if(Roo.isIE && !Roo.isIE7){
11952             this.autoWidth.defer(1, this);
11953         }else{
11954             this.autoWidth();
11955         }
11956         if(this.menu){
11957             this.menu.on("show", this.onMenuShow, this);
11958             this.menu.on("hide", this.onMenuHide, this);
11959         }
11960         this.fireEvent('render', this);
11961     },
11962
11963     // private
11964     autoWidth : function(){
11965         if(this.el){
11966             var tbl = this.el.child("table:first");
11967             var tbl2 = this.el.child("table:last");
11968             this.el.setWidth("auto");
11969             tbl.setWidth("auto");
11970             if(Roo.isIE7 && Roo.isStrict){
11971                 var ib = this.el.child('button:first');
11972                 if(ib && ib.getWidth() > 20){
11973                     ib.clip();
11974                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11975                 }
11976             }
11977             if(this.minWidth){
11978                 if(this.hidden){
11979                     this.el.beginMeasure();
11980                 }
11981                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
11982                     tbl.setWidth(this.minWidth-tbl2.getWidth());
11983                 }
11984                 if(this.hidden){
11985                     this.el.endMeasure();
11986                 }
11987             }
11988             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
11989         } 
11990     },
11991     /**
11992      * Sets this button's click handler
11993      * @param {Function} handler The function to call when the button is clicked
11994      * @param {Object} scope (optional) Scope for the function passed above
11995      */
11996     setHandler : function(handler, scope){
11997         this.handler = handler;
11998         this.scope = scope;  
11999     },
12000     
12001     /**
12002      * Sets this button's arrow click handler
12003      * @param {Function} handler The function to call when the arrow is clicked
12004      * @param {Object} scope (optional) Scope for the function passed above
12005      */
12006     setArrowHandler : function(handler, scope){
12007         this.arrowHandler = handler;
12008         this.scope = scope;  
12009     },
12010     
12011     /**
12012      * Focus the button
12013      */
12014     focus : function(){
12015         if(this.el){
12016             this.el.child("button:first").focus();
12017         }
12018     },
12019
12020     // private
12021     onClick : function(e){
12022         e.preventDefault();
12023         if(!this.disabled){
12024             if(e.getTarget(".x-btn-menu-arrow-wrap")){
12025                 if(this.menu && !this.menu.isVisible()){
12026                     this.menu.show(this.el, this.menuAlign);
12027                 }
12028                 this.fireEvent("arrowclick", this, e);
12029                 if(this.arrowHandler){
12030                     this.arrowHandler.call(this.scope || this, this, e);
12031                 }
12032             }else{
12033                 this.fireEvent("click", this, e);
12034                 if(this.handler){
12035                     this.handler.call(this.scope || this, this, e);
12036                 }
12037             }
12038         }
12039     },
12040     // private
12041     onMouseDown : function(e){
12042         if(!this.disabled){
12043             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12044         }
12045     },
12046     // private
12047     onMouseUp : function(e){
12048         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12049     }   
12050 });
12051
12052
12053 // backwards compat
12054 Roo.MenuButton = Roo.SplitButton;/*
12055  * Based on:
12056  * Ext JS Library 1.1.1
12057  * Copyright(c) 2006-2007, Ext JS, LLC.
12058  *
12059  * Originally Released Under LGPL - original licence link has changed is not relivant.
12060  *
12061  * Fork - LGPL
12062  * <script type="text/javascript">
12063  */
12064
12065 /**
12066  * @class Roo.Toolbar
12067  * Basic Toolbar class.
12068  * @constructor
12069  * Creates a new Toolbar
12070  * @param {Object} config The config object
12071  */ 
12072 Roo.Toolbar = function(container, buttons, config)
12073 {
12074     /// old consturctor format still supported..
12075     if(container instanceof Array){ // omit the container for later rendering
12076         buttons = container;
12077         config = buttons;
12078         container = null;
12079     }
12080     if (typeof(container) == 'object' && container.xtype) {
12081         config = container;
12082         container = config.container;
12083         buttons = config.buttons; // not really - use items!!
12084     }
12085     var xitems = [];
12086     if (config && config.items) {
12087         xitems = config.items;
12088         delete config.items;
12089     }
12090     Roo.apply(this, config);
12091     this.buttons = buttons;
12092     
12093     if(container){
12094         this.render(container);
12095     }
12096     Roo.each(xitems, function(b) {
12097         this.add(b);
12098     }, this);
12099     
12100 };
12101
12102 Roo.Toolbar.prototype = {
12103     /**
12104      * @cfg {Roo.data.Store} items
12105      * array of button configs or elements to add
12106      */
12107     
12108     /**
12109      * @cfg {String/HTMLElement/Element} container
12110      * The id or element that will contain the toolbar
12111      */
12112     // private
12113     render : function(ct){
12114         this.el = Roo.get(ct);
12115         if(this.cls){
12116             this.el.addClass(this.cls);
12117         }
12118         // using a table allows for vertical alignment
12119         // 100% width is needed by Safari...
12120         this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12121         this.tr = this.el.child("tr", true);
12122         var autoId = 0;
12123         this.items = new Roo.util.MixedCollection(false, function(o){
12124             return o.id || ("item" + (++autoId));
12125         });
12126         if(this.buttons){
12127             this.add.apply(this, this.buttons);
12128             delete this.buttons;
12129         }
12130     },
12131
12132     /**
12133      * Adds element(s) to the toolbar -- this function takes a variable number of 
12134      * arguments of mixed type and adds them to the toolbar.
12135      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12136      * <ul>
12137      * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12138      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12139      * <li>Field: Any form field (equivalent to {@link #addField})</li>
12140      * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12141      * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12142      * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12143      * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12144      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12145      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12146      * </ul>
12147      * @param {Mixed} arg2
12148      * @param {Mixed} etc.
12149      */
12150     add : function(){
12151         var a = arguments, l = a.length;
12152         for(var i = 0; i < l; i++){
12153             this._add(a[i]);
12154         }
12155     },
12156     // private..
12157     _add : function(el) {
12158         
12159         if (el.xtype) {
12160             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12161         }
12162         
12163         if (el.applyTo){ // some kind of form field
12164             return this.addField(el);
12165         } 
12166         if (el.render){ // some kind of Toolbar.Item
12167             return this.addItem(el);
12168         }
12169         if (typeof el == "string"){ // string
12170             if(el == "separator" || el == "-"){
12171                 return this.addSeparator();
12172             }
12173             if (el == " "){
12174                 return this.addSpacer();
12175             }
12176             if(el == "->"){
12177                 return this.addFill();
12178             }
12179             return this.addText(el);
12180             
12181         }
12182         if(el.tagName){ // element
12183             return this.addElement(el);
12184         }
12185         if(typeof el == "object"){ // must be button config?
12186             return this.addButton(el);
12187         }
12188         // and now what?!?!
12189         return false;
12190         
12191     },
12192     
12193     /**
12194      * Add an Xtype element
12195      * @param {Object} xtype Xtype Object
12196      * @return {Object} created Object
12197      */
12198     addxtype : function(e){
12199         return this.add(e);  
12200     },
12201     
12202     /**
12203      * Returns the Element for this toolbar.
12204      * @return {Roo.Element}
12205      */
12206     getEl : function(){
12207         return this.el;  
12208     },
12209     
12210     /**
12211      * Adds a separator
12212      * @return {Roo.Toolbar.Item} The separator item
12213      */
12214     addSeparator : function(){
12215         return this.addItem(new Roo.Toolbar.Separator());
12216     },
12217
12218     /**
12219      * Adds a spacer element
12220      * @return {Roo.Toolbar.Spacer} The spacer item
12221      */
12222     addSpacer : function(){
12223         return this.addItem(new Roo.Toolbar.Spacer());
12224     },
12225
12226     /**
12227      * Adds a fill element that forces subsequent additions to the right side of the toolbar
12228      * @return {Roo.Toolbar.Fill} The fill item
12229      */
12230     addFill : function(){
12231         return this.addItem(new Roo.Toolbar.Fill());
12232     },
12233
12234     /**
12235      * Adds any standard HTML element to the toolbar
12236      * @param {String/HTMLElement/Element} el The element or id of the element to add
12237      * @return {Roo.Toolbar.Item} The element's item
12238      */
12239     addElement : function(el){
12240         return this.addItem(new Roo.Toolbar.Item(el));
12241     },
12242     /**
12243      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12244      * @type Roo.util.MixedCollection  
12245      */
12246     items : false,
12247      
12248     /**
12249      * Adds any Toolbar.Item or subclass
12250      * @param {Roo.Toolbar.Item} item
12251      * @return {Roo.Toolbar.Item} The item
12252      */
12253     addItem : function(item){
12254         var td = this.nextBlock();
12255         item.render(td);
12256         this.items.add(item);
12257         return item;
12258     },
12259     
12260     /**
12261      * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12262      * @param {Object/Array} config A button config or array of configs
12263      * @return {Roo.Toolbar.Button/Array}
12264      */
12265     addButton : function(config){
12266         if(config instanceof Array){
12267             var buttons = [];
12268             for(var i = 0, len = config.length; i < len; i++) {
12269                 buttons.push(this.addButton(config[i]));
12270             }
12271             return buttons;
12272         }
12273         var b = config;
12274         if(!(config instanceof Roo.Toolbar.Button)){
12275             b = config.split ?
12276                 new Roo.Toolbar.SplitButton(config) :
12277                 new Roo.Toolbar.Button(config);
12278         }
12279         var td = this.nextBlock();
12280         b.render(td);
12281         this.items.add(b);
12282         return b;
12283     },
12284     
12285     /**
12286      * Adds text to the toolbar
12287      * @param {String} text The text to add
12288      * @return {Roo.Toolbar.Item} The element's item
12289      */
12290     addText : function(text){
12291         return this.addItem(new Roo.Toolbar.TextItem(text));
12292     },
12293     
12294     /**
12295      * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12296      * @param {Number} index The index where the item is to be inserted
12297      * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12298      * @return {Roo.Toolbar.Button/Item}
12299      */
12300     insertButton : function(index, item){
12301         if(item instanceof Array){
12302             var buttons = [];
12303             for(var i = 0, len = item.length; i < len; i++) {
12304                buttons.push(this.insertButton(index + i, item[i]));
12305             }
12306             return buttons;
12307         }
12308         if (!(item instanceof Roo.Toolbar.Button)){
12309            item = new Roo.Toolbar.Button(item);
12310         }
12311         var td = document.createElement("td");
12312         this.tr.insertBefore(td, this.tr.childNodes[index]);
12313         item.render(td);
12314         this.items.insert(index, item);
12315         return item;
12316     },
12317     
12318     /**
12319      * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12320      * @param {Object} config
12321      * @return {Roo.Toolbar.Item} The element's item
12322      */
12323     addDom : function(config, returnEl){
12324         var td = this.nextBlock();
12325         Roo.DomHelper.overwrite(td, config);
12326         var ti = new Roo.Toolbar.Item(td.firstChild);
12327         ti.render(td);
12328         this.items.add(ti);
12329         return ti;
12330     },
12331
12332     /**
12333      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12334      * @type Roo.util.MixedCollection  
12335      */
12336     fields : false,
12337     
12338     /**
12339      * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12340      * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12341      * @param {Roo.form.Field} field
12342      * @return {Roo.ToolbarItem}
12343      */
12344      
12345       
12346     addField : function(field) {
12347         if (!this.fields) {
12348             var autoId = 0;
12349             this.fields = new Roo.util.MixedCollection(false, function(o){
12350                 return o.id || ("item" + (++autoId));
12351             });
12352
12353         }
12354         
12355         var td = this.nextBlock();
12356         field.render(td);
12357         var ti = new Roo.Toolbar.Item(td.firstChild);
12358         ti.render(td);
12359         this.items.add(ti);
12360         this.fields.add(field);
12361         return ti;
12362     },
12363     /**
12364      * Hide the toolbar
12365      * @method hide
12366      */
12367      
12368       
12369     hide : function()
12370     {
12371         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12372         this.el.child('div').hide();
12373     },
12374     /**
12375      * Show the toolbar
12376      * @method show
12377      */
12378     show : function()
12379     {
12380         this.el.child('div').show();
12381     },
12382       
12383     // private
12384     nextBlock : function(){
12385         var td = document.createElement("td");
12386         this.tr.appendChild(td);
12387         return td;
12388     },
12389
12390     // private
12391     destroy : function(){
12392         if(this.items){ // rendered?
12393             Roo.destroy.apply(Roo, this.items.items);
12394         }
12395         if(this.fields){ // rendered?
12396             Roo.destroy.apply(Roo, this.fields.items);
12397         }
12398         Roo.Element.uncache(this.el, this.tr);
12399     }
12400 };
12401
12402 /**
12403  * @class Roo.Toolbar.Item
12404  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12405  * @constructor
12406  * Creates a new Item
12407  * @param {HTMLElement} el 
12408  */
12409 Roo.Toolbar.Item = function(el){
12410     this.el = Roo.getDom(el);
12411     this.id = Roo.id(this.el);
12412     this.hidden = false;
12413 };
12414
12415 Roo.Toolbar.Item.prototype = {
12416     
12417     /**
12418      * Get this item's HTML Element
12419      * @return {HTMLElement}
12420      */
12421     getEl : function(){
12422        return this.el;  
12423     },
12424
12425     // private
12426     render : function(td){
12427         this.td = td;
12428         td.appendChild(this.el);
12429     },
12430     
12431     /**
12432      * Removes and destroys this item.
12433      */
12434     destroy : function(){
12435         this.td.parentNode.removeChild(this.td);
12436     },
12437     
12438     /**
12439      * Shows this item.
12440      */
12441     show: function(){
12442         this.hidden = false;
12443         this.td.style.display = "";
12444     },
12445     
12446     /**
12447      * Hides this item.
12448      */
12449     hide: function(){
12450         this.hidden = true;
12451         this.td.style.display = "none";
12452     },
12453     
12454     /**
12455      * Convenience function for boolean show/hide.
12456      * @param {Boolean} visible true to show/false to hide
12457      */
12458     setVisible: function(visible){
12459         if(visible) {
12460             this.show();
12461         }else{
12462             this.hide();
12463         }
12464     },
12465     
12466     /**
12467      * Try to focus this item.
12468      */
12469     focus : function(){
12470         Roo.fly(this.el).focus();
12471     },
12472     
12473     /**
12474      * Disables this item.
12475      */
12476     disable : function(){
12477         Roo.fly(this.td).addClass("x-item-disabled");
12478         this.disabled = true;
12479         this.el.disabled = true;
12480     },
12481     
12482     /**
12483      * Enables this item.
12484      */
12485     enable : function(){
12486         Roo.fly(this.td).removeClass("x-item-disabled");
12487         this.disabled = false;
12488         this.el.disabled = false;
12489     }
12490 };
12491
12492
12493 /**
12494  * @class Roo.Toolbar.Separator
12495  * @extends Roo.Toolbar.Item
12496  * A simple toolbar separator class
12497  * @constructor
12498  * Creates a new Separator
12499  */
12500 Roo.Toolbar.Separator = function(){
12501     var s = document.createElement("span");
12502     s.className = "ytb-sep";
12503     Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12504 };
12505 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12506     enable:Roo.emptyFn,
12507     disable:Roo.emptyFn,
12508     focus:Roo.emptyFn
12509 });
12510
12511 /**
12512  * @class Roo.Toolbar.Spacer
12513  * @extends Roo.Toolbar.Item
12514  * A simple element that adds extra horizontal space to a toolbar.
12515  * @constructor
12516  * Creates a new Spacer
12517  */
12518 Roo.Toolbar.Spacer = function(){
12519     var s = document.createElement("div");
12520     s.className = "ytb-spacer";
12521     Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12522 };
12523 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12524     enable:Roo.emptyFn,
12525     disable:Roo.emptyFn,
12526     focus:Roo.emptyFn
12527 });
12528
12529 /**
12530  * @class Roo.Toolbar.Fill
12531  * @extends Roo.Toolbar.Spacer
12532  * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12533  * @constructor
12534  * Creates a new Spacer
12535  */
12536 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12537     // private
12538     render : function(td){
12539         td.style.width = '100%';
12540         Roo.Toolbar.Fill.superclass.render.call(this, td);
12541     }
12542 });
12543
12544 /**
12545  * @class Roo.Toolbar.TextItem
12546  * @extends Roo.Toolbar.Item
12547  * A simple class that renders text directly into a toolbar.
12548  * @constructor
12549  * Creates a new TextItem
12550  * @param {String} text
12551  */
12552 Roo.Toolbar.TextItem = function(text){
12553     if (typeof(text) == 'object') {
12554         text = text.text;
12555     }
12556     var s = document.createElement("span");
12557     s.className = "ytb-text";
12558     s.innerHTML = text;
12559     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12560 };
12561 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12562     enable:Roo.emptyFn,
12563     disable:Roo.emptyFn,
12564     focus:Roo.emptyFn
12565 });
12566
12567 /**
12568  * @class Roo.Toolbar.Button
12569  * @extends Roo.Button
12570  * A button that renders into a toolbar.
12571  * @constructor
12572  * Creates a new Button
12573  * @param {Object} config A standard {@link Roo.Button} config object
12574  */
12575 Roo.Toolbar.Button = function(config){
12576     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12577 };
12578 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12579     render : function(td){
12580         this.td = td;
12581         Roo.Toolbar.Button.superclass.render.call(this, td);
12582     },
12583     
12584     /**
12585      * Removes and destroys this button
12586      */
12587     destroy : function(){
12588         Roo.Toolbar.Button.superclass.destroy.call(this);
12589         this.td.parentNode.removeChild(this.td);
12590     },
12591     
12592     /**
12593      * Shows this button
12594      */
12595     show: function(){
12596         this.hidden = false;
12597         this.td.style.display = "";
12598     },
12599     
12600     /**
12601      * Hides this button
12602      */
12603     hide: function(){
12604         this.hidden = true;
12605         this.td.style.display = "none";
12606     },
12607
12608     /**
12609      * Disables this item
12610      */
12611     disable : function(){
12612         Roo.fly(this.td).addClass("x-item-disabled");
12613         this.disabled = true;
12614     },
12615
12616     /**
12617      * Enables this item
12618      */
12619     enable : function(){
12620         Roo.fly(this.td).removeClass("x-item-disabled");
12621         this.disabled = false;
12622     }
12623 });
12624 // backwards compat
12625 Roo.ToolbarButton = Roo.Toolbar.Button;
12626
12627 /**
12628  * @class Roo.Toolbar.SplitButton
12629  * @extends Roo.SplitButton
12630  * A menu button that renders into a toolbar.
12631  * @constructor
12632  * Creates a new SplitButton
12633  * @param {Object} config A standard {@link Roo.SplitButton} config object
12634  */
12635 Roo.Toolbar.SplitButton = function(config){
12636     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12637 };
12638 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12639     render : function(td){
12640         this.td = td;
12641         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12642     },
12643     
12644     /**
12645      * Removes and destroys this button
12646      */
12647     destroy : function(){
12648         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12649         this.td.parentNode.removeChild(this.td);
12650     },
12651     
12652     /**
12653      * Shows this button
12654      */
12655     show: function(){
12656         this.hidden = false;
12657         this.td.style.display = "";
12658     },
12659     
12660     /**
12661      * Hides this button
12662      */
12663     hide: function(){
12664         this.hidden = true;
12665         this.td.style.display = "none";
12666     }
12667 });
12668
12669 // backwards compat
12670 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;