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     if (config.listeners || config.events) { 
76         Roo.BasicLayoutRegion.superclass.constructor.call(this,  { 
77             listeners : config.listeners || {}, 
78             events : config.events || {} 
79         });    
80     }
81 };
82
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
84
85     /**
86      * The id of the element associated with this object.  This is what we
87      * refer to as the "linked element" because the size and position of
88      * this element is used to determine when the drag and drop objects have
89      * interacted.
90      * @property id
91      * @type String
92      */
93     id: null,
94
95     /**
96      * Configuration attributes passed into the constructor
97      * @property config
98      * @type object
99      */
100     config: null,
101
102     /**
103      * The id of the element that will be dragged.  By default this is same
104      * as the linked element , but could be changed to another element. Ex:
105      * Roo.dd.DDProxy
106      * @property dragElId
107      * @type String
108      * @private
109      */
110     dragElId: null,
111
112     /**
113      * the id of the element that initiates the drag operation.  By default
114      * this is the linked element, but could be changed to be a child of this
115      * element.  This lets us do things like only starting the drag when the
116      * header element within the linked html element is clicked.
117      * @property handleElId
118      * @type String
119      * @private
120      */
121     handleElId: null,
122
123     /**
124      * An associative array of HTML tags that will be ignored if clicked.
125      * @property invalidHandleTypes
126      * @type {string: string}
127      */
128     invalidHandleTypes: null,
129
130     /**
131      * An associative array of ids for elements that will be ignored if clicked
132      * @property invalidHandleIds
133      * @type {string: string}
134      */
135     invalidHandleIds: null,
136
137     /**
138      * An indexted array of css class names for elements that will be ignored
139      * if clicked.
140      * @property invalidHandleClasses
141      * @type string[]
142      */
143     invalidHandleClasses: null,
144
145     /**
146      * The linked element's absolute X position at the time the drag was
147      * started
148      * @property startPageX
149      * @type int
150      * @private
151      */
152     startPageX: 0,
153
154     /**
155      * The linked element's absolute X position at the time the drag was
156      * started
157      * @property startPageY
158      * @type int
159      * @private
160      */
161     startPageY: 0,
162
163     /**
164      * The group defines a logical collection of DragDrop objects that are
165      * related.  Instances only get events when interacting with other
166      * DragDrop object in the same group.  This lets us define multiple
167      * groups using a single DragDrop subclass if we want.
168      * @property groups
169      * @type {string: string}
170      */
171     groups: null,
172
173     /**
174      * Individual drag/drop instances can be locked.  This will prevent
175      * onmousedown start drag.
176      * @property locked
177      * @type boolean
178      * @private
179      */
180     locked: false,
181
182     /**
183      * Lock this instance
184      * @method lock
185      */
186     lock: function() { this.locked = true; },
187
188     /**
189      * Unlock this instace
190      * @method unlock
191      */
192     unlock: function() { this.locked = false; },
193
194     /**
195      * By default, all insances can be a drop target.  This can be disabled by
196      * setting isTarget to false.
197      * @method isTarget
198      * @type boolean
199      */
200     isTarget: true,
201
202     /**
203      * The padding configured for this drag and drop object for calculating
204      * the drop zone intersection with this object.
205      * @method padding
206      * @type int[]
207      */
208     padding: null,
209
210     /**
211      * Cached reference to the linked element
212      * @property _domRef
213      * @private
214      */
215     _domRef: null,
216
217     /**
218      * Internal typeof flag
219      * @property __ygDragDrop
220      * @private
221      */
222     __ygDragDrop: true,
223
224     /**
225      * Set to true when horizontal contraints are applied
226      * @property constrainX
227      * @type boolean
228      * @private
229      */
230     constrainX: false,
231
232     /**
233      * Set to true when vertical contraints are applied
234      * @property constrainY
235      * @type boolean
236      * @private
237      */
238     constrainY: false,
239
240     /**
241      * The left constraint
242      * @property minX
243      * @type int
244      * @private
245      */
246     minX: 0,
247
248     /**
249      * The right constraint
250      * @property maxX
251      * @type int
252      * @private
253      */
254     maxX: 0,
255
256     /**
257      * The up constraint
258      * @property minY
259      * @type int
260      * @type int
261      * @private
262      */
263     minY: 0,
264
265     /**
266      * The down constraint
267      * @property maxY
268      * @type int
269      * @private
270      */
271     maxY: 0,
272
273     /**
274      * Maintain offsets when we resetconstraints.  Set to true when you want
275      * the position of the element relative to its parent to stay the same
276      * when the page changes
277      *
278      * @property maintainOffset
279      * @type boolean
280      */
281     maintainOffset: false,
282
283     /**
284      * Array of pixel locations the element will snap to if we specified a
285      * horizontal graduation/interval.  This array is generated automatically
286      * when you define a tick interval.
287      * @property xTicks
288      * @type int[]
289      */
290     xTicks: null,
291
292     /**
293      * Array of pixel locations the element will snap to if we specified a
294      * vertical graduation/interval.  This array is generated automatically
295      * when you define a tick interval.
296      * @property yTicks
297      * @type int[]
298      */
299     yTicks: null,
300
301     /**
302      * By default the drag and drop instance will only respond to the primary
303      * button click (left button for a right-handed mouse).  Set to true to
304      * allow drag and drop to start with any mouse click that is propogated
305      * by the browser
306      * @property primaryButtonOnly
307      * @type boolean
308      */
309     primaryButtonOnly: true,
310
311     /**
312      * The availabe property is false until the linked dom element is accessible.
313      * @property available
314      * @type boolean
315      */
316     available: false,
317
318     /**
319      * By default, drags can only be initiated if the mousedown occurs in the
320      * region the linked element is.  This is done in part to work around a
321      * bug in some browsers that mis-report the mousedown if the previous
322      * mouseup happened outside of the window.  This property is set to true
323      * if outer handles are defined.
324      *
325      * @property hasOuterHandles
326      * @type boolean
327      * @default false
328      */
329     hasOuterHandles: false,
330
331     /**
332      * Code that executes immediately before the startDrag event
333      * @method b4StartDrag
334      * @private
335      */
336     b4StartDrag: function(x, y) { },
337
338     /**
339      * Abstract method called after a drag/drop object is clicked
340      * and the drag or mousedown time thresholds have beeen met.
341      * @method startDrag
342      * @param {int} X click location
343      * @param {int} Y click location
344      */
345     startDrag: function(x, y) { /* override this */ },
346
347     /**
348      * Code that executes immediately before the onDrag event
349      * @method b4Drag
350      * @private
351      */
352     b4Drag: function(e) { },
353
354     /**
355      * Abstract method called during the onMouseMove event while dragging an
356      * object.
357      * @method onDrag
358      * @param {Event} e the mousemove event
359      */
360     onDrag: function(e) { /* override this */ },
361
362     /**
363      * Abstract method called when this element fist begins hovering over
364      * another DragDrop obj
365      * @method onDragEnter
366      * @param {Event} e the mousemove event
367      * @param {String|DragDrop[]} id In POINT mode, the element
368      * id this is hovering over.  In INTERSECT mode, an array of one or more
369      * dragdrop items being hovered over.
370      */
371     onDragEnter: function(e, id) { /* override this */ },
372
373     /**
374      * Code that executes immediately before the onDragOver event
375      * @method b4DragOver
376      * @private
377      */
378     b4DragOver: function(e) { },
379
380     /**
381      * Abstract method called when this element is hovering over another
382      * DragDrop obj
383      * @method onDragOver
384      * @param {Event} e the mousemove event
385      * @param {String|DragDrop[]} id In POINT mode, the element
386      * id this is hovering over.  In INTERSECT mode, an array of dd items
387      * being hovered over.
388      */
389     onDragOver: function(e, id) { /* override this */ },
390
391     /**
392      * Code that executes immediately before the onDragOut event
393      * @method b4DragOut
394      * @private
395      */
396     b4DragOut: function(e) { },
397
398     /**
399      * Abstract method called when we are no longer hovering over an element
400      * @method onDragOut
401      * @param {Event} e the mousemove event
402      * @param {String|DragDrop[]} id In POINT mode, the element
403      * id this was hovering over.  In INTERSECT mode, an array of dd items
404      * that the mouse is no longer over.
405      */
406     onDragOut: function(e, id) { /* override this */ },
407
408     /**
409      * Code that executes immediately before the onDragDrop event
410      * @method b4DragDrop
411      * @private
412      */
413     b4DragDrop: function(e) { },
414
415     /**
416      * Abstract method called when this item is dropped on another DragDrop
417      * obj
418      * @method onDragDrop
419      * @param {Event} e the mouseup event
420      * @param {String|DragDrop[]} id In POINT mode, the element
421      * id this was dropped on.  In INTERSECT mode, an array of dd items this
422      * was dropped on.
423      */
424     onDragDrop: function(e, id) { /* override this */ },
425
426     /**
427      * Abstract method called when this item is dropped on an area with no
428      * drop target
429      * @method onInvalidDrop
430      * @param {Event} e the mouseup event
431      */
432     onInvalidDrop: function(e) { /* override this */ },
433
434     /**
435      * Code that executes immediately before the endDrag event
436      * @method b4EndDrag
437      * @private
438      */
439     b4EndDrag: function(e) { },
440
441     /**
442      * Fired when we are done dragging the object
443      * @method endDrag
444      * @param {Event} e the mouseup event
445      */
446     endDrag: function(e) { /* override this */ },
447
448     /**
449      * Code executed immediately before the onMouseDown event
450      * @method b4MouseDown
451      * @param {Event} e the mousedown event
452      * @private
453      */
454     b4MouseDown: function(e) {  },
455
456     /**
457      * Event handler that fires when a drag/drop obj gets a mousedown
458      * @method onMouseDown
459      * @param {Event} e the mousedown event
460      */
461     onMouseDown: function(e) { /* override this */ },
462
463     /**
464      * Event handler that fires when a drag/drop obj gets a mouseup
465      * @method onMouseUp
466      * @param {Event} e the mouseup event
467      */
468     onMouseUp: function(e) { /* override this */ },
469
470     /**
471      * Override the onAvailable method to do what is needed after the initial
472      * position was determined.
473      * @method onAvailable
474      */
475     onAvailable: function () {
476     },
477
478     /*
479      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
480      * @type Object
481      */
482     defaultPadding : {left:0, right:0, top:0, bottom:0},
483
484     /*
485      * Initializes the drag drop object's constraints to restrict movement to a certain element.
486  *
487  * Usage:
488  <pre><code>
489  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490                 { dragElId: "existingProxyDiv" });
491  dd.startDrag = function(){
492      this.constrainTo("parent-id");
493  };
494  </code></pre>
495  * Or you can initalize it using the {@link Roo.Element} object:
496  <pre><code>
497  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498      startDrag : function(){
499          this.constrainTo("parent-id");
500      }
501  });
502  </code></pre>
503      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506      * an object containing the sides to pad. For example: {right:10, bottom:10}
507      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
508      */
509     constrainTo : function(constrainTo, pad, inContent){
510         if(typeof pad == "number"){
511             pad = {left: pad, right:pad, top:pad, bottom:pad};
512         }
513         pad = pad || this.defaultPadding;
514         var b = Roo.get(this.getEl()).getBox();
515         var ce = Roo.get(constrainTo);
516         var s = ce.getScroll();
517         var c, cd = ce.dom;
518         if(cd == document.body){
519             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
520         }else{
521             xy = ce.getXY();
522             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
523         }
524
525
526         var topSpace = b.y - c.y;
527         var leftSpace = b.x - c.x;
528
529         this.resetConstraints();
530         this.setXConstraint(leftSpace - (pad.left||0), // left
531                 c.width - leftSpace - b.width - (pad.right||0) //right
532         );
533         this.setYConstraint(topSpace - (pad.top||0), //top
534                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
535         );
536     },
537
538     /**
539      * Returns a reference to the linked element
540      * @method getEl
541      * @return {HTMLElement} the html element
542      */
543     getEl: function() {
544         if (!this._domRef) {
545             this._domRef = Roo.getDom(this.id);
546         }
547
548         return this._domRef;
549     },
550
551     /**
552      * Returns a reference to the actual element to drag.  By default this is
553      * the same as the html element, but it can be assigned to another
554      * element. An example of this can be found in Roo.dd.DDProxy
555      * @method getDragEl
556      * @return {HTMLElement} the html element
557      */
558     getDragEl: function() {
559         return Roo.getDom(this.dragElId);
560     },
561
562     /**
563      * Sets up the DragDrop object.  Must be called in the constructor of any
564      * Roo.dd.DragDrop subclass
565      * @method init
566      * @param id the id of the linked element
567      * @param {String} sGroup the group of related items
568      * @param {object} config configuration attributes
569      */
570     init: function(id, sGroup, config) {
571         this.initTarget(id, sGroup, config);
572         Event.on(this.id, "mousedown", this.handleMouseDown, this);
573         // Event.on(this.id, "selectstart", Event.preventDefault);
574     },
575
576     /**
577      * Initializes Targeting functionality only... the object does not
578      * get a mousedown handler.
579      * @method initTarget
580      * @param id the id of the linked element
581      * @param {String} sGroup the group of related items
582      * @param {object} config configuration attributes
583      */
584     initTarget: function(id, sGroup, config) {
585
586         // configuration attributes
587         this.config = config || {};
588
589         // create a local reference to the drag and drop manager
590         this.DDM = Roo.dd.DDM;
591         // initialize the groups array
592         this.groups = {};
593
594         // assume that we have an element reference instead of an id if the
595         // parameter is not a string
596         if (typeof id !== "string") {
597             id = Roo.id(id);
598         }
599
600         // set the id
601         this.id = id;
602
603         // add to an interaction group
604         this.addToGroup((sGroup) ? sGroup : "default");
605
606         // We don't want to register this as the handle with the manager
607         // so we just set the id rather than calling the setter.
608         this.handleElId = id;
609
610         // the linked element is the element that gets dragged by default
611         this.setDragElId(id);
612
613         // by default, clicked anchors will not start drag operations.
614         this.invalidHandleTypes = { A: "A" };
615         this.invalidHandleIds = {};
616         this.invalidHandleClasses = [];
617
618         this.applyConfig();
619
620         this.handleOnAvailable();
621     },
622
623     /**
624      * Applies the configuration parameters that were passed into the constructor.
625      * This is supposed to happen at each level through the inheritance chain.  So
626      * a DDProxy implentation will execute apply config on DDProxy, DD, and
627      * DragDrop in order to get all of the parameters that are available in
628      * each object.
629      * @method applyConfig
630      */
631     applyConfig: function() {
632
633         // configurable properties:
634         //    padding, isTarget, maintainOffset, primaryButtonOnly
635         this.padding           = this.config.padding || [0, 0, 0, 0];
636         this.isTarget          = (this.config.isTarget !== false);
637         this.maintainOffset    = (this.config.maintainOffset);
638         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
639
640     },
641
642     /**
643      * Executed when the linked element is available
644      * @method handleOnAvailable
645      * @private
646      */
647     handleOnAvailable: function() {
648         this.available = true;
649         this.resetConstraints();
650         this.onAvailable();
651     },
652
653      /**
654      * Configures the padding for the target zone in px.  Effectively expands
655      * (or reduces) the virtual object size for targeting calculations.
656      * Supports css-style shorthand; if only one parameter is passed, all sides
657      * will have that padding, and if only two are passed, the top and bottom
658      * will have the first param, the left and right the second.
659      * @method setPadding
660      * @param {int} iTop    Top pad
661      * @param {int} iRight  Right pad
662      * @param {int} iBot    Bot pad
663      * @param {int} iLeft   Left pad
664      */
665     setPadding: function(iTop, iRight, iBot, iLeft) {
666         // this.padding = [iLeft, iRight, iTop, iBot];
667         if (!iRight && 0 !== iRight) {
668             this.padding = [iTop, iTop, iTop, iTop];
669         } else if (!iBot && 0 !== iBot) {
670             this.padding = [iTop, iRight, iTop, iRight];
671         } else {
672             this.padding = [iTop, iRight, iBot, iLeft];
673         }
674     },
675
676     /**
677      * Stores the initial placement of the linked element.
678      * @method setInitialPosition
679      * @param {int} diffX   the X offset, default 0
680      * @param {int} diffY   the Y offset, default 0
681      */
682     setInitPosition: function(diffX, diffY) {
683         var el = this.getEl();
684
685         if (!this.DDM.verifyEl(el)) {
686             return;
687         }
688
689         var dx = diffX || 0;
690         var dy = diffY || 0;
691
692         var p = Dom.getXY( el );
693
694         this.initPageX = p[0] - dx;
695         this.initPageY = p[1] - dy;
696
697         this.lastPageX = p[0];
698         this.lastPageY = p[1];
699
700
701         this.setStartPosition(p);
702     },
703
704     /**
705      * Sets the start position of the element.  This is set when the obj
706      * is initialized, the reset when a drag is started.
707      * @method setStartPosition
708      * @param pos current position (from previous lookup)
709      * @private
710      */
711     setStartPosition: function(pos) {
712         var p = pos || Dom.getXY( this.getEl() );
713         this.deltaSetXY = null;
714
715         this.startPageX = p[0];
716         this.startPageY = p[1];
717     },
718
719     /**
720      * Add this instance to a group of related drag/drop objects.  All
721      * instances belong to at least one group, and can belong to as many
722      * groups as needed.
723      * @method addToGroup
724      * @param sGroup {string} the name of the group
725      */
726     addToGroup: function(sGroup) {
727         this.groups[sGroup] = true;
728         this.DDM.regDragDrop(this, sGroup);
729     },
730
731     /**
732      * Remove's this instance from the supplied interaction group
733      * @method removeFromGroup
734      * @param {string}  sGroup  The group to drop
735      */
736     removeFromGroup: function(sGroup) {
737         if (this.groups[sGroup]) {
738             delete this.groups[sGroup];
739         }
740
741         this.DDM.removeDDFromGroup(this, sGroup);
742     },
743
744     /**
745      * Allows you to specify that an element other than the linked element
746      * will be moved with the cursor during a drag
747      * @method setDragElId
748      * @param id {string} the id of the element that will be used to initiate the drag
749      */
750     setDragElId: function(id) {
751         this.dragElId = id;
752     },
753
754     /**
755      * Allows you to specify a child of the linked element that should be
756      * used to initiate the drag operation.  An example of this would be if
757      * you have a content div with text and links.  Clicking anywhere in the
758      * content area would normally start the drag operation.  Use this method
759      * to specify that an element inside of the content div is the element
760      * that starts the drag operation.
761      * @method setHandleElId
762      * @param id {string} the id of the element that will be used to
763      * initiate the drag.
764      */
765     setHandleElId: function(id) {
766         if (typeof id !== "string") {
767             id = Roo.id(id);
768         }
769         this.handleElId = id;
770         this.DDM.regHandle(this.id, id);
771     },
772
773     /**
774      * Allows you to set an element outside of the linked element as a drag
775      * handle
776      * @method setOuterHandleElId
777      * @param id the id of the element that will be used to initiate the drag
778      */
779     setOuterHandleElId: function(id) {
780         if (typeof id !== "string") {
781             id = Roo.id(id);
782         }
783         Event.on(id, "mousedown",
784                 this.handleMouseDown, this);
785         this.setHandleElId(id);
786
787         this.hasOuterHandles = true;
788     },
789
790     /**
791      * Remove all drag and drop hooks for this element
792      * @method unreg
793      */
794     unreg: function() {
795         Event.un(this.id, "mousedown",
796                 this.handleMouseDown);
797         this._domRef = null;
798         this.DDM._remove(this);
799     },
800
801     destroy : function(){
802         this.unreg();
803     },
804
805     /**
806      * Returns true if this instance is locked, or the drag drop mgr is locked
807      * (meaning that all drag/drop is disabled on the page.)
808      * @method isLocked
809      * @return {boolean} true if this obj or all drag/drop is locked, else
810      * false
811      */
812     isLocked: function() {
813         return (this.DDM.isLocked() || this.locked);
814     },
815
816     /**
817      * Fired when this object is clicked
818      * @method handleMouseDown
819      * @param {Event} e
820      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
821      * @private
822      */
823     handleMouseDown: function(e, oDD){
824         if (this.primaryButtonOnly && e.button != 0) {
825             return;
826         }
827
828         if (this.isLocked()) {
829             return;
830         }
831
832         this.DDM.refreshCache(this.groups);
833
834         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
836         } else {
837             if (this.clickValidator(e)) {
838
839                 // set the initial element position
840                 this.setStartPosition();
841
842
843                 this.b4MouseDown(e);
844                 this.onMouseDown(e);
845
846                 this.DDM.handleMouseDown(e, this);
847
848                 this.DDM.stopEvent(e);
849             } else {
850
851
852             }
853         }
854     },
855
856     clickValidator: function(e) {
857         var target = e.getTarget();
858         return ( this.isValidHandleChild(target) &&
859                     (this.id == this.handleElId ||
860                         this.DDM.handleWasClicked(target, this.id)) );
861     },
862
863     /**
864      * Allows you to specify a tag name that should not start a drag operation
865      * when clicked.  This is designed to facilitate embedding links within a
866      * drag handle that do something other than start the drag.
867      * @method addInvalidHandleType
868      * @param {string} tagName the type of element to exclude
869      */
870     addInvalidHandleType: function(tagName) {
871         var type = tagName.toUpperCase();
872         this.invalidHandleTypes[type] = type;
873     },
874
875     /**
876      * Lets you to specify an element id for a child of a drag handle
877      * that should not initiate a drag
878      * @method addInvalidHandleId
879      * @param {string} id the element id of the element you wish to ignore
880      */
881     addInvalidHandleId: function(id) {
882         if (typeof id !== "string") {
883             id = Roo.id(id);
884         }
885         this.invalidHandleIds[id] = id;
886     },
887
888     /**
889      * Lets you specify a css class of elements that will not initiate a drag
890      * @method addInvalidHandleClass
891      * @param {string} cssClass the class of the elements you wish to ignore
892      */
893     addInvalidHandleClass: function(cssClass) {
894         this.invalidHandleClasses.push(cssClass);
895     },
896
897     /**
898      * Unsets an excluded tag name set by addInvalidHandleType
899      * @method removeInvalidHandleType
900      * @param {string} tagName the type of element to unexclude
901      */
902     removeInvalidHandleType: function(tagName) {
903         var type = tagName.toUpperCase();
904         // this.invalidHandleTypes[type] = null;
905         delete this.invalidHandleTypes[type];
906     },
907
908     /**
909      * Unsets an invalid handle id
910      * @method removeInvalidHandleId
911      * @param {string} id the id of the element to re-enable
912      */
913     removeInvalidHandleId: function(id) {
914         if (typeof id !== "string") {
915             id = Roo.id(id);
916         }
917         delete this.invalidHandleIds[id];
918     },
919
920     /**
921      * Unsets an invalid css class
922      * @method removeInvalidHandleClass
923      * @param {string} cssClass the class of the element(s) you wish to
924      * re-enable
925      */
926     removeInvalidHandleClass: function(cssClass) {
927         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928             if (this.invalidHandleClasses[i] == cssClass) {
929                 delete this.invalidHandleClasses[i];
930             }
931         }
932     },
933
934     /**
935      * Checks the tag exclusion list to see if this click should be ignored
936      * @method isValidHandleChild
937      * @param {HTMLElement} node the HTMLElement to evaluate
938      * @return {boolean} true if this is a valid tag type, false if not
939      */
940     isValidHandleChild: function(node) {
941
942         var valid = true;
943         // var n = (node.nodeName == "#text") ? node.parentNode : node;
944         var nodeName;
945         try {
946             nodeName = node.nodeName.toUpperCase();
947         } catch(e) {
948             nodeName = node.nodeName;
949         }
950         valid = valid && !this.invalidHandleTypes[nodeName];
951         valid = valid && !this.invalidHandleIds[node.id];
952
953         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
955         }
956
957
958         return valid;
959
960     },
961
962     /**
963      * Create the array of horizontal tick marks if an interval was specified
964      * in setXConstraint().
965      * @method setXTicks
966      * @private
967      */
968     setXTicks: function(iStartX, iTickSize) {
969         this.xTicks = [];
970         this.xTickSize = iTickSize;
971
972         var tickMap = {};
973
974         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
975             if (!tickMap[i]) {
976                 this.xTicks[this.xTicks.length] = i;
977                 tickMap[i] = true;
978             }
979         }
980
981         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
982             if (!tickMap[i]) {
983                 this.xTicks[this.xTicks.length] = i;
984                 tickMap[i] = true;
985             }
986         }
987
988         this.xTicks.sort(this.DDM.numericSort) ;
989     },
990
991     /**
992      * Create the array of vertical tick marks if an interval was specified in
993      * setYConstraint().
994      * @method setYTicks
995      * @private
996      */
997     setYTicks: function(iStartY, iTickSize) {
998         this.yTicks = [];
999         this.yTickSize = iTickSize;
1000
1001         var tickMap = {};
1002
1003         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1004             if (!tickMap[i]) {
1005                 this.yTicks[this.yTicks.length] = i;
1006                 tickMap[i] = true;
1007             }
1008         }
1009
1010         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1011             if (!tickMap[i]) {
1012                 this.yTicks[this.yTicks.length] = i;
1013                 tickMap[i] = true;
1014             }
1015         }
1016
1017         this.yTicks.sort(this.DDM.numericSort) ;
1018     },
1019
1020     /**
1021      * By default, the element can be dragged any place on the screen.  Use
1022      * this method to limit the horizontal travel of the element.  Pass in
1023      * 0,0 for the parameters if you want to lock the drag to the y axis.
1024      * @method setXConstraint
1025      * @param {int} iLeft the number of pixels the element can move to the left
1026      * @param {int} iRight the number of pixels the element can move to the
1027      * right
1028      * @param {int} iTickSize optional parameter for specifying that the
1029      * element
1030      * should move iTickSize pixels at a time.
1031      */
1032     setXConstraint: function(iLeft, iRight, iTickSize) {
1033         this.leftConstraint = iLeft;
1034         this.rightConstraint = iRight;
1035
1036         this.minX = this.initPageX - iLeft;
1037         this.maxX = this.initPageX + iRight;
1038         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1039
1040         this.constrainX = true;
1041     },
1042
1043     /**
1044      * Clears any constraints applied to this instance.  Also clears ticks
1045      * since they can't exist independent of a constraint at this time.
1046      * @method clearConstraints
1047      */
1048     clearConstraints: function() {
1049         this.constrainX = false;
1050         this.constrainY = false;
1051         this.clearTicks();
1052     },
1053
1054     /**
1055      * Clears any tick interval defined for this instance
1056      * @method clearTicks
1057      */
1058     clearTicks: function() {
1059         this.xTicks = null;
1060         this.yTicks = null;
1061         this.xTickSize = 0;
1062         this.yTickSize = 0;
1063     },
1064
1065     /**
1066      * By default, the element can be dragged any place on the screen.  Set
1067      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1068      * parameters if you want to lock the drag to the x axis.
1069      * @method setYConstraint
1070      * @param {int} iUp the number of pixels the element can move up
1071      * @param {int} iDown the number of pixels the element can move down
1072      * @param {int} iTickSize optional parameter for specifying that the
1073      * element should move iTickSize pixels at a time.
1074      */
1075     setYConstraint: function(iUp, iDown, iTickSize) {
1076         this.topConstraint = iUp;
1077         this.bottomConstraint = iDown;
1078
1079         this.minY = this.initPageY - iUp;
1080         this.maxY = this.initPageY + iDown;
1081         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1082
1083         this.constrainY = true;
1084
1085     },
1086
1087     /**
1088      * resetConstraints must be called if you manually reposition a dd element.
1089      * @method resetConstraints
1090      * @param {boolean} maintainOffset
1091      */
1092     resetConstraints: function() {
1093
1094
1095         // Maintain offsets if necessary
1096         if (this.initPageX || this.initPageX === 0) {
1097             // figure out how much this thing has moved
1098             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1100
1101             this.setInitPosition(dx, dy);
1102
1103         // This is the first time we have detected the element's position
1104         } else {
1105             this.setInitPosition();
1106         }
1107
1108         if (this.constrainX) {
1109             this.setXConstraint( this.leftConstraint,
1110                                  this.rightConstraint,
1111                                  this.xTickSize        );
1112         }
1113
1114         if (this.constrainY) {
1115             this.setYConstraint( this.topConstraint,
1116                                  this.bottomConstraint,
1117                                  this.yTickSize         );
1118         }
1119     },
1120
1121     /**
1122      * Normally the drag element is moved pixel by pixel, but we can specify
1123      * that it move a number of pixels at a time.  This method resolves the
1124      * location when we have it set up like this.
1125      * @method getTick
1126      * @param {int} val where we want to place the object
1127      * @param {int[]} tickArray sorted array of valid points
1128      * @return {int} the closest tick
1129      * @private
1130      */
1131     getTick: function(val, tickArray) {
1132
1133         if (!tickArray) {
1134             // If tick interval is not defined, it is effectively 1 pixel,
1135             // so we return the value passed to us.
1136             return val;
1137         } else if (tickArray[0] >= val) {
1138             // The value is lower than the first tick, so we return the first
1139             // tick.
1140             return tickArray[0];
1141         } else {
1142             for (var i=0, len=tickArray.length; i<len; ++i) {
1143                 var next = i + 1;
1144                 if (tickArray[next] && tickArray[next] >= val) {
1145                     var diff1 = val - tickArray[i];
1146                     var diff2 = tickArray[next] - val;
1147                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1148                 }
1149             }
1150
1151             // The value is larger than the last tick, so we return the last
1152             // tick.
1153             return tickArray[tickArray.length - 1];
1154         }
1155     },
1156
1157     /**
1158      * toString method
1159      * @method toString
1160      * @return {string} string representation of the dd obj
1161      */
1162     toString: function() {
1163         return ("DragDrop " + this.id);
1164     }
1165
1166 };
1167
1168 })();
1169 /*
1170  * Based on:
1171  * Ext JS Library 1.1.1
1172  * Copyright(c) 2006-2007, Ext JS, LLC.
1173  *
1174  * Originally Released Under LGPL - original licence link has changed is not relivant.
1175  *
1176  * Fork - LGPL
1177  * <script type="text/javascript">
1178  */
1179
1180
1181 /**
1182  * The drag and drop utility provides a framework for building drag and drop
1183  * applications.  In addition to enabling drag and drop for specific elements,
1184  * the drag and drop elements are tracked by the manager class, and the
1185  * interactions between the various elements are tracked during the drag and
1186  * the implementing code is notified about these important moments.
1187  */
1188
1189 // Only load the library once.  Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1192
1193 /**
1194  * @class Roo.dd.DragDropMgr
1195  * DragDropMgr is a singleton that tracks the element interaction for
1196  * all DragDrop items in the window.  Generally, you will not call
1197  * this class directly, but it does have helper methods that could
1198  * be useful in your DragDrop implementations.
1199  * @singleton
1200  */
1201 Roo.dd.DragDropMgr = function() {
1202
1203     var Event = Roo.EventManager;
1204
1205     return {
1206
1207         /**
1208          * Two dimensional Array of registered DragDrop objects.  The first
1209          * dimension is the DragDrop item group, the second the DragDrop
1210          * object.
1211          * @property ids
1212          * @type {string: string}
1213          * @private
1214          * @static
1215          */
1216         ids: {},
1217
1218         /**
1219          * Array of element ids defined as drag handles.  Used to determine
1220          * if the element that generated the mousedown event is actually the
1221          * handle and not the html element itself.
1222          * @property handleIds
1223          * @type {string: string}
1224          * @private
1225          * @static
1226          */
1227         handleIds: {},
1228
1229         /**
1230          * the DragDrop object that is currently being dragged
1231          * @property dragCurrent
1232          * @type DragDrop
1233          * @private
1234          * @static
1235          **/
1236         dragCurrent: null,
1237
1238         /**
1239          * the DragDrop object(s) that are being hovered over
1240          * @property dragOvers
1241          * @type Array
1242          * @private
1243          * @static
1244          */
1245         dragOvers: {},
1246
1247         /**
1248          * the X distance between the cursor and the object being dragged
1249          * @property deltaX
1250          * @type int
1251          * @private
1252          * @static
1253          */
1254         deltaX: 0,
1255
1256         /**
1257          * the Y distance between the cursor and the object being dragged
1258          * @property deltaY
1259          * @type int
1260          * @private
1261          * @static
1262          */
1263         deltaY: 0,
1264
1265         /**
1266          * Flag to determine if we should prevent the default behavior of the
1267          * events we define. By default this is true, but this can be set to
1268          * false if you need the default behavior (not recommended)
1269          * @property preventDefault
1270          * @type boolean
1271          * @static
1272          */
1273         preventDefault: true,
1274
1275         /**
1276          * Flag to determine if we should stop the propagation of the events
1277          * we generate. This is true by default but you may want to set it to
1278          * false if the html element contains other features that require the
1279          * mouse click.
1280          * @property stopPropagation
1281          * @type boolean
1282          * @static
1283          */
1284         stopPropagation: true,
1285
1286         /**
1287          * Internal flag that is set to true when drag and drop has been
1288          * intialized
1289          * @property initialized
1290          * @private
1291          * @static
1292          */
1293         initalized: false,
1294
1295         /**
1296          * All drag and drop can be disabled.
1297          * @property locked
1298          * @private
1299          * @static
1300          */
1301         locked: false,
1302
1303         /**
1304          * Called the first time an element is registered.
1305          * @method init
1306          * @private
1307          * @static
1308          */
1309         init: function() {
1310             this.initialized = true;
1311         },
1312
1313         /**
1314          * In point mode, drag and drop interaction is defined by the
1315          * location of the cursor during the drag/drop
1316          * @property POINT
1317          * @type int
1318          * @static
1319          */
1320         POINT: 0,
1321
1322         /**
1323          * In intersect mode, drag and drop interactio nis defined by the
1324          * overlap of two or more drag and drop objects.
1325          * @property INTERSECT
1326          * @type int
1327          * @static
1328          */
1329         INTERSECT: 1,
1330
1331         /**
1332          * The current drag and drop mode.  Default: POINT
1333          * @property mode
1334          * @type int
1335          * @static
1336          */
1337         mode: 0,
1338
1339         /**
1340          * Runs method on all drag and drop objects
1341          * @method _execOnAll
1342          * @private
1343          * @static
1344          */
1345         _execOnAll: function(sMethod, args) {
1346             for (var i in this.ids) {
1347                 for (var j in this.ids[i]) {
1348                     var oDD = this.ids[i][j];
1349                     if (! this.isTypeOfDD(oDD)) {
1350                         continue;
1351                     }
1352                     oDD[sMethod].apply(oDD, args);
1353                 }
1354             }
1355         },
1356
1357         /**
1358          * Drag and drop initialization.  Sets up the global event handlers
1359          * @method _onLoad
1360          * @private
1361          * @static
1362          */
1363         _onLoad: function() {
1364
1365             this.init();
1366
1367
1368             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1369             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370             Event.on(window,   "unload",    this._onUnload, this, true);
1371             Event.on(window,   "resize",    this._onResize, this, true);
1372             // Event.on(window,   "mouseout",    this._test);
1373
1374         },
1375
1376         /**
1377          * Reset constraints on all drag and drop objs
1378          * @method _onResize
1379          * @private
1380          * @static
1381          */
1382         _onResize: function(e) {
1383             this._execOnAll("resetConstraints", []);
1384         },
1385
1386         /**
1387          * Lock all drag and drop functionality
1388          * @method lock
1389          * @static
1390          */
1391         lock: function() { this.locked = true; },
1392
1393         /**
1394          * Unlock all drag and drop functionality
1395          * @method unlock
1396          * @static
1397          */
1398         unlock: function() { this.locked = false; },
1399
1400         /**
1401          * Is drag and drop locked?
1402          * @method isLocked
1403          * @return {boolean} True if drag and drop is locked, false otherwise.
1404          * @static
1405          */
1406         isLocked: function() { return this.locked; },
1407
1408         /**
1409          * Location cache that is set for all drag drop objects when a drag is
1410          * initiated, cleared when the drag is finished.
1411          * @property locationCache
1412          * @private
1413          * @static
1414          */
1415         locationCache: {},
1416
1417         /**
1418          * Set useCache to false if you want to force object the lookup of each
1419          * drag and drop linked element constantly during a drag.
1420          * @property useCache
1421          * @type boolean
1422          * @static
1423          */
1424         useCache: true,
1425
1426         /**
1427          * The number of pixels that the mouse needs to move after the
1428          * mousedown before the drag is initiated.  Default=3;
1429          * @property clickPixelThresh
1430          * @type int
1431          * @static
1432          */
1433         clickPixelThresh: 3,
1434
1435         /**
1436          * The number of milliseconds after the mousedown event to initiate the
1437          * drag if we don't get a mouseup event. Default=1000
1438          * @property clickTimeThresh
1439          * @type int
1440          * @static
1441          */
1442         clickTimeThresh: 350,
1443
1444         /**
1445          * Flag that indicates that either the drag pixel threshold or the
1446          * mousdown time threshold has been met
1447          * @property dragThreshMet
1448          * @type boolean
1449          * @private
1450          * @static
1451          */
1452         dragThreshMet: false,
1453
1454         /**
1455          * Timeout used for the click time threshold
1456          * @property clickTimeout
1457          * @type Object
1458          * @private
1459          * @static
1460          */
1461         clickTimeout: null,
1462
1463         /**
1464          * The X position of the mousedown event stored for later use when a
1465          * drag threshold is met.
1466          * @property startX
1467          * @type int
1468          * @private
1469          * @static
1470          */
1471         startX: 0,
1472
1473         /**
1474          * The Y position of the mousedown event stored for later use when a
1475          * drag threshold is met.
1476          * @property startY
1477          * @type int
1478          * @private
1479          * @static
1480          */
1481         startY: 0,
1482
1483         /**
1484          * Each DragDrop instance must be registered with the DragDropMgr.
1485          * This is executed in DragDrop.init()
1486          * @method regDragDrop
1487          * @param {DragDrop} oDD the DragDrop object to register
1488          * @param {String} sGroup the name of the group this element belongs to
1489          * @static
1490          */
1491         regDragDrop: function(oDD, sGroup) {
1492             if (!this.initialized) { this.init(); }
1493
1494             if (!this.ids[sGroup]) {
1495                 this.ids[sGroup] = {};
1496             }
1497             this.ids[sGroup][oDD.id] = oDD;
1498         },
1499
1500         /**
1501          * Removes the supplied dd instance from the supplied group. Executed
1502          * by DragDrop.removeFromGroup, so don't call this function directly.
1503          * @method removeDDFromGroup
1504          * @private
1505          * @static
1506          */
1507         removeDDFromGroup: function(oDD, sGroup) {
1508             if (!this.ids[sGroup]) {
1509                 this.ids[sGroup] = {};
1510             }
1511
1512             var obj = this.ids[sGroup];
1513             if (obj && obj[oDD.id]) {
1514                 delete obj[oDD.id];
1515             }
1516         },
1517
1518         /**
1519          * Unregisters a drag and drop item.  This is executed in
1520          * DragDrop.unreg, use that method instead of calling this directly.
1521          * @method _remove
1522          * @private
1523          * @static
1524          */
1525         _remove: function(oDD) {
1526             for (var g in oDD.groups) {
1527                 if (g && this.ids[g][oDD.id]) {
1528                     delete this.ids[g][oDD.id];
1529                 }
1530             }
1531             delete this.handleIds[oDD.id];
1532         },
1533
1534         /**
1535          * Each DragDrop handle element must be registered.  This is done
1536          * automatically when executing DragDrop.setHandleElId()
1537          * @method regHandle
1538          * @param {String} sDDId the DragDrop id this element is a handle for
1539          * @param {String} sHandleId the id of the element that is the drag
1540          * handle
1541          * @static
1542          */
1543         regHandle: function(sDDId, sHandleId) {
1544             if (!this.handleIds[sDDId]) {
1545                 this.handleIds[sDDId] = {};
1546             }
1547             this.handleIds[sDDId][sHandleId] = sHandleId;
1548         },
1549
1550         /**
1551          * Utility function to determine if a given element has been
1552          * registered as a drag drop item.
1553          * @method isDragDrop
1554          * @param {String} id the element id to check
1555          * @return {boolean} true if this element is a DragDrop item,
1556          * false otherwise
1557          * @static
1558          */
1559         isDragDrop: function(id) {
1560             return ( this.getDDById(id) ) ? true : false;
1561         },
1562
1563         /**
1564          * Returns the drag and drop instances that are in all groups the
1565          * passed in instance belongs to.
1566          * @method getRelated
1567          * @param {DragDrop} p_oDD the obj to get related data for
1568          * @param {boolean} bTargetsOnly if true, only return targetable objs
1569          * @return {DragDrop[]} the related instances
1570          * @static
1571          */
1572         getRelated: function(p_oDD, bTargetsOnly) {
1573             var oDDs = [];
1574             for (var i in p_oDD.groups) {
1575                 for (j in this.ids[i]) {
1576                     var dd = this.ids[i][j];
1577                     if (! this.isTypeOfDD(dd)) {
1578                         continue;
1579                     }
1580                     if (!bTargetsOnly || dd.isTarget) {
1581                         oDDs[oDDs.length] = dd;
1582                     }
1583                 }
1584             }
1585
1586             return oDDs;
1587         },
1588
1589         /**
1590          * Returns true if the specified dd target is a legal target for
1591          * the specifice drag obj
1592          * @method isLegalTarget
1593          * @param {DragDrop} the drag obj
1594          * @param {DragDrop} the target
1595          * @return {boolean} true if the target is a legal target for the
1596          * dd obj
1597          * @static
1598          */
1599         isLegalTarget: function (oDD, oTargetDD) {
1600             var targets = this.getRelated(oDD, true);
1601             for (var i=0, len=targets.length;i<len;++i) {
1602                 if (targets[i].id == oTargetDD.id) {
1603                     return true;
1604                 }
1605             }
1606
1607             return false;
1608         },
1609
1610         /**
1611          * My goal is to be able to transparently determine if an object is
1612          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1613          * returns "object", oDD.constructor.toString() always returns
1614          * "DragDrop" and not the name of the subclass.  So for now it just
1615          * evaluates a well-known variable in DragDrop.
1616          * @method isTypeOfDD
1617          * @param {Object} the object to evaluate
1618          * @return {boolean} true if typeof oDD = DragDrop
1619          * @static
1620          */
1621         isTypeOfDD: function (oDD) {
1622             return (oDD && oDD.__ygDragDrop);
1623         },
1624
1625         /**
1626          * Utility function to determine if a given element has been
1627          * registered as a drag drop handle for the given Drag Drop object.
1628          * @method isHandle
1629          * @param {String} id the element id to check
1630          * @return {boolean} true if this element is a DragDrop handle, false
1631          * otherwise
1632          * @static
1633          */
1634         isHandle: function(sDDId, sHandleId) {
1635             return ( this.handleIds[sDDId] &&
1636                             this.handleIds[sDDId][sHandleId] );
1637         },
1638
1639         /**
1640          * Returns the DragDrop instance for a given id
1641          * @method getDDById
1642          * @param {String} id the id of the DragDrop object
1643          * @return {DragDrop} the drag drop object, null if it is not found
1644          * @static
1645          */
1646         getDDById: function(id) {
1647             for (var i in this.ids) {
1648                 if (this.ids[i][id]) {
1649                     return this.ids[i][id];
1650                 }
1651             }
1652             return null;
1653         },
1654
1655         /**
1656          * Fired after a registered DragDrop object gets the mousedown event.
1657          * Sets up the events required to track the object being dragged
1658          * @method handleMouseDown
1659          * @param {Event} e the event
1660          * @param oDD the DragDrop object being dragged
1661          * @private
1662          * @static
1663          */
1664         handleMouseDown: function(e, oDD) {
1665             if(Roo.QuickTips){
1666                 Roo.QuickTips.disable();
1667             }
1668             this.currentTarget = e.getTarget();
1669
1670             this.dragCurrent = oDD;
1671
1672             var el = oDD.getEl();
1673
1674             // track start position
1675             this.startX = e.getPageX();
1676             this.startY = e.getPageY();
1677
1678             this.deltaX = this.startX - el.offsetLeft;
1679             this.deltaY = this.startY - el.offsetTop;
1680
1681             this.dragThreshMet = false;
1682
1683             this.clickTimeout = setTimeout(
1684                     function() {
1685                         var DDM = Roo.dd.DDM;
1686                         DDM.startDrag(DDM.startX, DDM.startY);
1687                     },
1688                     this.clickTimeThresh );
1689         },
1690
1691         /**
1692          * Fired when either the drag pixel threshol or the mousedown hold
1693          * time threshold has been met.
1694          * @method startDrag
1695          * @param x {int} the X position of the original mousedown
1696          * @param y {int} the Y position of the original mousedown
1697          * @static
1698          */
1699         startDrag: function(x, y) {
1700             clearTimeout(this.clickTimeout);
1701             if (this.dragCurrent) {
1702                 this.dragCurrent.b4StartDrag(x, y);
1703                 this.dragCurrent.startDrag(x, y);
1704             }
1705             this.dragThreshMet = true;
1706         },
1707
1708         /**
1709          * Internal function to handle the mouseup event.  Will be invoked
1710          * from the context of the document.
1711          * @method handleMouseUp
1712          * @param {Event} e the event
1713          * @private
1714          * @static
1715          */
1716         handleMouseUp: function(e) {
1717
1718             if(Roo.QuickTips){
1719                 Roo.QuickTips.enable();
1720             }
1721             if (! this.dragCurrent) {
1722                 return;
1723             }
1724
1725             clearTimeout(this.clickTimeout);
1726
1727             if (this.dragThreshMet) {
1728                 this.fireEvents(e, true);
1729             } else {
1730             }
1731
1732             this.stopDrag(e);
1733
1734             this.stopEvent(e);
1735         },
1736
1737         /**
1738          * Utility to stop event propagation and event default, if these
1739          * features are turned on.
1740          * @method stopEvent
1741          * @param {Event} e the event as returned by this.getEvent()
1742          * @static
1743          */
1744         stopEvent: function(e){
1745             if(this.stopPropagation) {
1746                 e.stopPropagation();
1747             }
1748
1749             if (this.preventDefault) {
1750                 e.preventDefault();
1751             }
1752         },
1753
1754         /**
1755          * Internal function to clean up event handlers after the drag
1756          * operation is complete
1757          * @method stopDrag
1758          * @param {Event} e the event
1759          * @private
1760          * @static
1761          */
1762         stopDrag: function(e) {
1763             // Fire the drag end event for the item that was dragged
1764             if (this.dragCurrent) {
1765                 if (this.dragThreshMet) {
1766                     this.dragCurrent.b4EndDrag(e);
1767                     this.dragCurrent.endDrag(e);
1768                 }
1769
1770                 this.dragCurrent.onMouseUp(e);
1771             }
1772
1773             this.dragCurrent = null;
1774             this.dragOvers = {};
1775         },
1776
1777         /**
1778          * Internal function to handle the mousemove event.  Will be invoked
1779          * from the context of the html element.
1780          *
1781          * @TODO figure out what we can do about mouse events lost when the
1782          * user drags objects beyond the window boundary.  Currently we can
1783          * detect this in internet explorer by verifying that the mouse is
1784          * down during the mousemove event.  Firefox doesn't give us the
1785          * button state on the mousemove event.
1786          * @method handleMouseMove
1787          * @param {Event} e the event
1788          * @private
1789          * @static
1790          */
1791         handleMouseMove: function(e) {
1792             if (! this.dragCurrent) {
1793                 return true;
1794             }
1795
1796             // var button = e.which || e.button;
1797
1798             // check for IE mouseup outside of page boundary
1799             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1800                 this.stopEvent(e);
1801                 return this.handleMouseUp(e);
1802             }
1803
1804             if (!this.dragThreshMet) {
1805                 var diffX = Math.abs(this.startX - e.getPageX());
1806                 var diffY = Math.abs(this.startY - e.getPageY());
1807                 if (diffX > this.clickPixelThresh ||
1808                             diffY > this.clickPixelThresh) {
1809                     this.startDrag(this.startX, this.startY);
1810                 }
1811             }
1812
1813             if (this.dragThreshMet) {
1814                 this.dragCurrent.b4Drag(e);
1815                 this.dragCurrent.onDrag(e);
1816                 if(!this.dragCurrent.moveOnly){
1817                     this.fireEvents(e, false);
1818                 }
1819             }
1820
1821             this.stopEvent(e);
1822
1823             return true;
1824         },
1825
1826         /**
1827          * Iterates over all of the DragDrop elements to find ones we are
1828          * hovering over or dropping on
1829          * @method fireEvents
1830          * @param {Event} e the event
1831          * @param {boolean} isDrop is this a drop op or a mouseover op?
1832          * @private
1833          * @static
1834          */
1835         fireEvents: function(e, isDrop) {
1836             var dc = this.dragCurrent;
1837
1838             // If the user did the mouse up outside of the window, we could
1839             // get here even though we have ended the drag.
1840             if (!dc || dc.isLocked()) {
1841                 return;
1842             }
1843
1844             var pt = e.getPoint();
1845
1846             // cache the previous dragOver array
1847             var oldOvers = [];
1848
1849             var outEvts   = [];
1850             var overEvts  = [];
1851             var dropEvts  = [];
1852             var enterEvts = [];
1853
1854             // Check to see if the object(s) we were hovering over is no longer
1855             // being hovered over so we can fire the onDragOut event
1856             for (var i in this.dragOvers) {
1857
1858                 var ddo = this.dragOvers[i];
1859
1860                 if (! this.isTypeOfDD(ddo)) {
1861                     continue;
1862                 }
1863
1864                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865                     outEvts.push( ddo );
1866                 }
1867
1868                 oldOvers[i] = true;
1869                 delete this.dragOvers[i];
1870             }
1871
1872             for (var sGroup in dc.groups) {
1873
1874                 if ("string" != typeof sGroup) {
1875                     continue;
1876                 }
1877
1878                 for (i in this.ids[sGroup]) {
1879                     var oDD = this.ids[sGroup][i];
1880                     if (! this.isTypeOfDD(oDD)) {
1881                         continue;
1882                     }
1883
1884                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885                         if (this.isOverTarget(pt, oDD, this.mode)) {
1886                             // look for drop interactions
1887                             if (isDrop) {
1888                                 dropEvts.push( oDD );
1889                             // look for drag enter and drag over interactions
1890                             } else {
1891
1892                                 // initial drag over: dragEnter fires
1893                                 if (!oldOvers[oDD.id]) {
1894                                     enterEvts.push( oDD );
1895                                 // subsequent drag overs: dragOver fires
1896                                 } else {
1897                                     overEvts.push( oDD );
1898                                 }
1899
1900                                 this.dragOvers[oDD.id] = oDD;
1901                             }
1902                         }
1903                     }
1904                 }
1905             }
1906
1907             if (this.mode) {
1908                 if (outEvts.length) {
1909                     dc.b4DragOut(e, outEvts);
1910                     dc.onDragOut(e, outEvts);
1911                 }
1912
1913                 if (enterEvts.length) {
1914                     dc.onDragEnter(e, enterEvts);
1915                 }
1916
1917                 if (overEvts.length) {
1918                     dc.b4DragOver(e, overEvts);
1919                     dc.onDragOver(e, overEvts);
1920                 }
1921
1922                 if (dropEvts.length) {
1923                     dc.b4DragDrop(e, dropEvts);
1924                     dc.onDragDrop(e, dropEvts);
1925                 }
1926
1927             } else {
1928                 // fire dragout events
1929                 var len = 0;
1930                 for (i=0, len=outEvts.length; i<len; ++i) {
1931                     dc.b4DragOut(e, outEvts[i].id);
1932                     dc.onDragOut(e, outEvts[i].id);
1933                 }
1934
1935                 // fire enter events
1936                 for (i=0,len=enterEvts.length; i<len; ++i) {
1937                     // dc.b4DragEnter(e, oDD.id);
1938                     dc.onDragEnter(e, enterEvts[i].id);
1939                 }
1940
1941                 // fire over events
1942                 for (i=0,len=overEvts.length; i<len; ++i) {
1943                     dc.b4DragOver(e, overEvts[i].id);
1944                     dc.onDragOver(e, overEvts[i].id);
1945                 }
1946
1947                 // fire drop events
1948                 for (i=0, len=dropEvts.length; i<len; ++i) {
1949                     dc.b4DragDrop(e, dropEvts[i].id);
1950                     dc.onDragDrop(e, dropEvts[i].id);
1951                 }
1952
1953             }
1954
1955             // notify about a drop that did not find a target
1956             if (isDrop && !dropEvts.length) {
1957                 dc.onInvalidDrop(e);
1958             }
1959
1960         },
1961
1962         /**
1963          * Helper function for getting the best match from the list of drag
1964          * and drop objects returned by the drag and drop events when we are
1965          * in INTERSECT mode.  It returns either the first object that the
1966          * cursor is over, or the object that has the greatest overlap with
1967          * the dragged element.
1968          * @method getBestMatch
1969          * @param  {DragDrop[]} dds The array of drag and drop objects
1970          * targeted
1971          * @return {DragDrop}       The best single match
1972          * @static
1973          */
1974         getBestMatch: function(dds) {
1975             var winner = null;
1976             // Return null if the input is not what we expect
1977             //if (!dds || !dds.length || dds.length == 0) {
1978                // winner = null;
1979             // If there is only one item, it wins
1980             //} else if (dds.length == 1) {
1981
1982             var len = dds.length;
1983
1984             if (len == 1) {
1985                 winner = dds[0];
1986             } else {
1987                 // Loop through the targeted items
1988                 for (var i=0; i<len; ++i) {
1989                     var dd = dds[i];
1990                     // If the cursor is over the object, it wins.  If the
1991                     // cursor is over multiple matches, the first one we come
1992                     // to wins.
1993                     if (dd.cursorIsOver) {
1994                         winner = dd;
1995                         break;
1996                     // Otherwise the object with the most overlap wins
1997                     } else {
1998                         if (!winner ||
1999                             winner.overlap.getArea() < dd.overlap.getArea()) {
2000                             winner = dd;
2001                         }
2002                     }
2003                 }
2004             }
2005
2006             return winner;
2007         },
2008
2009         /**
2010          * Refreshes the cache of the top-left and bottom-right points of the
2011          * drag and drop objects in the specified group(s).  This is in the
2012          * format that is stored in the drag and drop instance, so typical
2013          * usage is:
2014          * <code>
2015          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2016          * </code>
2017          * Alternatively:
2018          * <code>
2019          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2020          * </code>
2021          * @TODO this really should be an indexed array.  Alternatively this
2022          * method could accept both.
2023          * @method refreshCache
2024          * @param {Object} groups an associative array of groups to refresh
2025          * @static
2026          */
2027         refreshCache: function(groups) {
2028             for (var sGroup in groups) {
2029                 if ("string" != typeof sGroup) {
2030                     continue;
2031                 }
2032                 for (var i in this.ids[sGroup]) {
2033                     var oDD = this.ids[sGroup][i];
2034
2035                     if (this.isTypeOfDD(oDD)) {
2036                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037                         var loc = this.getLocation(oDD);
2038                         if (loc) {
2039                             this.locationCache[oDD.id] = loc;
2040                         } else {
2041                             delete this.locationCache[oDD.id];
2042                             // this will unregister the drag and drop object if
2043                             // the element is not in a usable state
2044                             // oDD.unreg();
2045                         }
2046                     }
2047                 }
2048             }
2049         },
2050
2051         /**
2052          * This checks to make sure an element exists and is in the DOM.  The
2053          * main purpose is to handle cases where innerHTML is used to remove
2054          * drag and drop objects from the DOM.  IE provides an 'unspecified
2055          * error' when trying to access the offsetParent of such an element
2056          * @method verifyEl
2057          * @param {HTMLElement} el the element to check
2058          * @return {boolean} true if the element looks usable
2059          * @static
2060          */
2061         verifyEl: function(el) {
2062             if (el) {
2063                 var parent;
2064                 if(Roo.isIE){
2065                     try{
2066                         parent = el.offsetParent;
2067                     }catch(e){}
2068                 }else{
2069                     parent = el.offsetParent;
2070                 }
2071                 if (parent) {
2072                     return true;
2073                 }
2074             }
2075
2076             return false;
2077         },
2078
2079         /**
2080          * Returns a Region object containing the drag and drop element's position
2081          * and size, including the padding configured for it
2082          * @method getLocation
2083          * @param {DragDrop} oDD the drag and drop object to get the
2084          *                       location for
2085          * @return {Roo.lib.Region} a Region object representing the total area
2086          *                             the element occupies, including any padding
2087          *                             the instance is configured for.
2088          * @static
2089          */
2090         getLocation: function(oDD) {
2091             if (! this.isTypeOfDD(oDD)) {
2092                 return null;
2093             }
2094
2095             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2096
2097             try {
2098                 pos= Roo.lib.Dom.getXY(el);
2099             } catch (e) { }
2100
2101             if (!pos) {
2102                 return null;
2103             }
2104
2105             x1 = pos[0];
2106             x2 = x1 + el.offsetWidth;
2107             y1 = pos[1];
2108             y2 = y1 + el.offsetHeight;
2109
2110             t = y1 - oDD.padding[0];
2111             r = x2 + oDD.padding[1];
2112             b = y2 + oDD.padding[2];
2113             l = x1 - oDD.padding[3];
2114
2115             return new Roo.lib.Region( t, r, b, l );
2116         },
2117
2118         /**
2119          * Checks the cursor location to see if it over the target
2120          * @method isOverTarget
2121          * @param {Roo.lib.Point} pt The point to evaluate
2122          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123          * @return {boolean} true if the mouse is over the target
2124          * @private
2125          * @static
2126          */
2127         isOverTarget: function(pt, oTarget, intersect) {
2128             // use cache if available
2129             var loc = this.locationCache[oTarget.id];
2130             if (!loc || !this.useCache) {
2131                 loc = this.getLocation(oTarget);
2132                 this.locationCache[oTarget.id] = loc;
2133
2134             }
2135
2136             if (!loc) {
2137                 return false;
2138             }
2139
2140             oTarget.cursorIsOver = loc.contains( pt );
2141
2142             // DragDrop is using this as a sanity check for the initial mousedown
2143             // in this case we are done.  In POINT mode, if the drag obj has no
2144             // contraints, we are also done. Otherwise we need to evaluate the
2145             // location of the target as related to the actual location of the
2146             // dragged element.
2147             var dc = this.dragCurrent;
2148             if (!dc || !dc.getTargetCoord ||
2149                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2150                 return oTarget.cursorIsOver;
2151             }
2152
2153             oTarget.overlap = null;
2154
2155             // Get the current location of the drag element, this is the
2156             // location of the mouse event less the delta that represents
2157             // where the original mousedown happened on the element.  We
2158             // need to consider constraints and ticks as well.
2159             var pos = dc.getTargetCoord(pt.x, pt.y);
2160
2161             var el = dc.getDragEl();
2162             var curRegion = new Roo.lib.Region( pos.y,
2163                                                    pos.x + el.offsetWidth,
2164                                                    pos.y + el.offsetHeight,
2165                                                    pos.x );
2166
2167             var overlap = curRegion.intersect(loc);
2168
2169             if (overlap) {
2170                 oTarget.overlap = overlap;
2171                 return (intersect) ? true : oTarget.cursorIsOver;
2172             } else {
2173                 return false;
2174             }
2175         },
2176
2177         /**
2178          * unload event handler
2179          * @method _onUnload
2180          * @private
2181          * @static
2182          */
2183         _onUnload: function(e, me) {
2184             Roo.dd.DragDropMgr.unregAll();
2185         },
2186
2187         /**
2188          * Cleans up the drag and drop events and objects.
2189          * @method unregAll
2190          * @private
2191          * @static
2192          */
2193         unregAll: function() {
2194
2195             if (this.dragCurrent) {
2196                 this.stopDrag();
2197                 this.dragCurrent = null;
2198             }
2199
2200             this._execOnAll("unreg", []);
2201
2202             for (i in this.elementCache) {
2203                 delete this.elementCache[i];
2204             }
2205
2206             this.elementCache = {};
2207             this.ids = {};
2208         },
2209
2210         /**
2211          * A cache of DOM elements
2212          * @property elementCache
2213          * @private
2214          * @static
2215          */
2216         elementCache: {},
2217
2218         /**
2219          * Get the wrapper for the DOM element specified
2220          * @method getElWrapper
2221          * @param {String} id the id of the element to get
2222          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2223          * @private
2224          * @deprecated This wrapper isn't that useful
2225          * @static
2226          */
2227         getElWrapper: function(id) {
2228             var oWrapper = this.elementCache[id];
2229             if (!oWrapper || !oWrapper.el) {
2230                 oWrapper = this.elementCache[id] =
2231                     new this.ElementWrapper(Roo.getDom(id));
2232             }
2233             return oWrapper;
2234         },
2235
2236         /**
2237          * Returns the actual DOM element
2238          * @method getElement
2239          * @param {String} id the id of the elment to get
2240          * @return {Object} The element
2241          * @deprecated use Roo.getDom instead
2242          * @static
2243          */
2244         getElement: function(id) {
2245             return Roo.getDom(id);
2246         },
2247
2248         /**
2249          * Returns the style property for the DOM element (i.e.,
2250          * document.getElById(id).style)
2251          * @method getCss
2252          * @param {String} id the id of the elment to get
2253          * @return {Object} The style property of the element
2254          * @deprecated use Roo.getDom instead
2255          * @static
2256          */
2257         getCss: function(id) {
2258             var el = Roo.getDom(id);
2259             return (el) ? el.style : null;
2260         },
2261
2262         /**
2263          * Inner class for cached elements
2264          * @class DragDropMgr.ElementWrapper
2265          * @for DragDropMgr
2266          * @private
2267          * @deprecated
2268          */
2269         ElementWrapper: function(el) {
2270                 /**
2271                  * The element
2272                  * @property el
2273                  */
2274                 this.el = el || null;
2275                 /**
2276                  * The element id
2277                  * @property id
2278                  */
2279                 this.id = this.el && el.id;
2280                 /**
2281                  * A reference to the style property
2282                  * @property css
2283                  */
2284                 this.css = this.el && el.style;
2285             },
2286
2287         /**
2288          * Returns the X position of an html element
2289          * @method getPosX
2290          * @param el the element for which to get the position
2291          * @return {int} the X coordinate
2292          * @for DragDropMgr
2293          * @deprecated use Roo.lib.Dom.getX instead
2294          * @static
2295          */
2296         getPosX: function(el) {
2297             return Roo.lib.Dom.getX(el);
2298         },
2299
2300         /**
2301          * Returns the Y position of an html element
2302          * @method getPosY
2303          * @param el the element for which to get the position
2304          * @return {int} the Y coordinate
2305          * @deprecated use Roo.lib.Dom.getY instead
2306          * @static
2307          */
2308         getPosY: function(el) {
2309             return Roo.lib.Dom.getY(el);
2310         },
2311
2312         /**
2313          * Swap two nodes.  In IE, we use the native method, for others we
2314          * emulate the IE behavior
2315          * @method swapNode
2316          * @param n1 the first node to swap
2317          * @param n2 the other node to swap
2318          * @static
2319          */
2320         swapNode: function(n1, n2) {
2321             if (n1.swapNode) {
2322                 n1.swapNode(n2);
2323             } else {
2324                 var p = n2.parentNode;
2325                 var s = n2.nextSibling;
2326
2327                 if (s == n1) {
2328                     p.insertBefore(n1, n2);
2329                 } else if (n2 == n1.nextSibling) {
2330                     p.insertBefore(n2, n1);
2331                 } else {
2332                     n1.parentNode.replaceChild(n2, n1);
2333                     p.insertBefore(n1, s);
2334                 }
2335             }
2336         },
2337
2338         /**
2339          * Returns the current scroll position
2340          * @method getScroll
2341          * @private
2342          * @static
2343          */
2344         getScroll: function () {
2345             var t, l, dde=document.documentElement, db=document.body;
2346             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2347                 t = dde.scrollTop;
2348                 l = dde.scrollLeft;
2349             } else if (db) {
2350                 t = db.scrollTop;
2351                 l = db.scrollLeft;
2352             } else {
2353
2354             }
2355             return { top: t, left: l };
2356         },
2357
2358         /**
2359          * Returns the specified element style property
2360          * @method getStyle
2361          * @param {HTMLElement} el          the element
2362          * @param {string}      styleProp   the style property
2363          * @return {string} The value of the style property
2364          * @deprecated use Roo.lib.Dom.getStyle
2365          * @static
2366          */
2367         getStyle: function(el, styleProp) {
2368             return Roo.fly(el).getStyle(styleProp);
2369         },
2370
2371         /**
2372          * Gets the scrollTop
2373          * @method getScrollTop
2374          * @return {int} the document's scrollTop
2375          * @static
2376          */
2377         getScrollTop: function () { return this.getScroll().top; },
2378
2379         /**
2380          * Gets the scrollLeft
2381          * @method getScrollLeft
2382          * @return {int} the document's scrollTop
2383          * @static
2384          */
2385         getScrollLeft: function () { return this.getScroll().left; },
2386
2387         /**
2388          * Sets the x/y position of an element to the location of the
2389          * target element.
2390          * @method moveToEl
2391          * @param {HTMLElement} moveEl      The element to move
2392          * @param {HTMLElement} targetEl    The position reference element
2393          * @static
2394          */
2395         moveToEl: function (moveEl, targetEl) {
2396             var aCoord = Roo.lib.Dom.getXY(targetEl);
2397             Roo.lib.Dom.setXY(moveEl, aCoord);
2398         },
2399
2400         /**
2401          * Numeric array sort function
2402          * @method numericSort
2403          * @static
2404          */
2405         numericSort: function(a, b) { return (a - b); },
2406
2407         /**
2408          * Internal counter
2409          * @property _timeoutCount
2410          * @private
2411          * @static
2412          */
2413         _timeoutCount: 0,
2414
2415         /**
2416          * Trying to make the load order less important.  Without this we get
2417          * an error if this file is loaded before the Event Utility.
2418          * @method _addListeners
2419          * @private
2420          * @static
2421          */
2422         _addListeners: function() {
2423             var DDM = Roo.dd.DDM;
2424             if ( Roo.lib.Event && document ) {
2425                 DDM._onLoad();
2426             } else {
2427                 if (DDM._timeoutCount > 2000) {
2428                 } else {
2429                     setTimeout(DDM._addListeners, 10);
2430                     if (document && document.body) {
2431                         DDM._timeoutCount += 1;
2432                     }
2433                 }
2434             }
2435         },
2436
2437         /**
2438          * Recursively searches the immediate parent and all child nodes for
2439          * the handle element in order to determine wheter or not it was
2440          * clicked.
2441          * @method handleWasClicked
2442          * @param node the html element to inspect
2443          * @static
2444          */
2445         handleWasClicked: function(node, id) {
2446             if (this.isHandle(id, node.id)) {
2447                 return true;
2448             } else {
2449                 // check to see if this is a text node child of the one we want
2450                 var p = node.parentNode;
2451
2452                 while (p) {
2453                     if (this.isHandle(id, p.id)) {
2454                         return true;
2455                     } else {
2456                         p = p.parentNode;
2457                     }
2458                 }
2459             }
2460
2461             return false;
2462         }
2463
2464     };
2465
2466 }();
2467
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2471
2472 }/*
2473  * Based on:
2474  * Ext JS Library 1.1.1
2475  * Copyright(c) 2006-2007, Ext JS, LLC.
2476  *
2477  * Originally Released Under LGPL - original licence link has changed is not relivant.
2478  *
2479  * Fork - LGPL
2480  * <script type="text/javascript">
2481  */
2482
2483 /**
2484  * @class Roo.dd.DD
2485  * A DragDrop implementation where the linked element follows the
2486  * mouse cursor during a drag.
2487  * @extends Roo.dd.DragDrop
2488  * @constructor
2489  * @param {String} id the id of the linked element
2490  * @param {String} sGroup the group of related DragDrop items
2491  * @param {object} config an object containing configurable attributes
2492  *                Valid properties for DD:
2493  *                    scroll
2494  */
2495 Roo.dd.DD = function(id, sGroup, config) {
2496     if (id) {
2497         this.init(id, sGroup, config);
2498     }
2499 };
2500
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2502
2503     /**
2504      * When set to true, the utility automatically tries to scroll the browser
2505      * window wehn a drag and drop element is dragged near the viewport boundary.
2506      * Defaults to true.
2507      * @property scroll
2508      * @type boolean
2509      */
2510     scroll: true,
2511
2512     /**
2513      * Sets the pointer offset to the distance between the linked element's top
2514      * left corner and the location the element was clicked
2515      * @method autoOffset
2516      * @param {int} iPageX the X coordinate of the click
2517      * @param {int} iPageY the Y coordinate of the click
2518      */
2519     autoOffset: function(iPageX, iPageY) {
2520         var x = iPageX - this.startPageX;
2521         var y = iPageY - this.startPageY;
2522         this.setDelta(x, y);
2523     },
2524
2525     /**
2526      * Sets the pointer offset.  You can call this directly to force the
2527      * offset to be in a particular location (e.g., pass in 0,0 to set it
2528      * to the center of the object)
2529      * @method setDelta
2530      * @param {int} iDeltaX the distance from the left
2531      * @param {int} iDeltaY the distance from the top
2532      */
2533     setDelta: function(iDeltaX, iDeltaY) {
2534         this.deltaX = iDeltaX;
2535         this.deltaY = iDeltaY;
2536     },
2537
2538     /**
2539      * Sets the drag element to the location of the mousedown or click event,
2540      * maintaining the cursor location relative to the location on the element
2541      * that was clicked.  Override this if you want to place the element in a
2542      * location other than where the cursor is.
2543      * @method setDragElPos
2544      * @param {int} iPageX the X coordinate of the mousedown or drag event
2545      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2546      */
2547     setDragElPos: function(iPageX, iPageY) {
2548         // the first time we do this, we are going to check to make sure
2549         // the element has css positioning
2550
2551         var el = this.getDragEl();
2552         this.alignElWithMouse(el, iPageX, iPageY);
2553     },
2554
2555     /**
2556      * Sets the element to the location of the mousedown or click event,
2557      * maintaining the cursor location relative to the location on the element
2558      * that was clicked.  Override this if you want to place the element in a
2559      * location other than where the cursor is.
2560      * @method alignElWithMouse
2561      * @param {HTMLElement} el the element to move
2562      * @param {int} iPageX the X coordinate of the mousedown or drag event
2563      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2564      */
2565     alignElWithMouse: function(el, iPageX, iPageY) {
2566         var oCoord = this.getTargetCoord(iPageX, iPageY);
2567         var fly = el.dom ? el : Roo.fly(el);
2568         if (!this.deltaSetXY) {
2569             var aCoord = [oCoord.x, oCoord.y];
2570             fly.setXY(aCoord);
2571             var newLeft = fly.getLeft(true);
2572             var newTop  = fly.getTop(true);
2573             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2574         } else {
2575             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2576         }
2577
2578         this.cachePosition(oCoord.x, oCoord.y);
2579         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2580         return oCoord;
2581     },
2582
2583     /**
2584      * Saves the most recent position so that we can reset the constraints and
2585      * tick marks on-demand.  We need to know this so that we can calculate the
2586      * number of pixels the element is offset from its original position.
2587      * @method cachePosition
2588      * @param iPageX the current x position (optional, this just makes it so we
2589      * don't have to look it up again)
2590      * @param iPageY the current y position (optional, this just makes it so we
2591      * don't have to look it up again)
2592      */
2593     cachePosition: function(iPageX, iPageY) {
2594         if (iPageX) {
2595             this.lastPageX = iPageX;
2596             this.lastPageY = iPageY;
2597         } else {
2598             var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599             this.lastPageX = aCoord[0];
2600             this.lastPageY = aCoord[1];
2601         }
2602     },
2603
2604     /**
2605      * Auto-scroll the window if the dragged object has been moved beyond the
2606      * visible window boundary.
2607      * @method autoScroll
2608      * @param {int} x the drag element's x position
2609      * @param {int} y the drag element's y position
2610      * @param {int} h the height of the drag element
2611      * @param {int} w the width of the drag element
2612      * @private
2613      */
2614     autoScroll: function(x, y, h, w) {
2615
2616         if (this.scroll) {
2617             // The client height
2618             var clientH = Roo.lib.Dom.getViewWidth();
2619
2620             // The client width
2621             var clientW = Roo.lib.Dom.getViewHeight();
2622
2623             // The amt scrolled down
2624             var st = this.DDM.getScrollTop();
2625
2626             // The amt scrolled right
2627             var sl = this.DDM.getScrollLeft();
2628
2629             // Location of the bottom of the element
2630             var bot = h + y;
2631
2632             // Location of the right of the element
2633             var right = w + x;
2634
2635             // The distance from the cursor to the bottom of the visible area,
2636             // adjusted so that we don't scroll if the cursor is beyond the
2637             // element drag constraints
2638             var toBot = (clientH + st - y - this.deltaY);
2639
2640             // The distance from the cursor to the right of the visible area
2641             var toRight = (clientW + sl - x - this.deltaX);
2642
2643
2644             // How close to the edge the cursor must be before we scroll
2645             // var thresh = (document.all) ? 100 : 40;
2646             var thresh = 40;
2647
2648             // How many pixels to scroll per autoscroll op.  This helps to reduce
2649             // clunky scrolling. IE is more sensitive about this ... it needs this
2650             // value to be higher.
2651             var scrAmt = (document.all) ? 80 : 30;
2652
2653             // Scroll down if we are near the bottom of the visible page and the
2654             // obj extends below the crease
2655             if ( bot > clientH && toBot < thresh ) {
2656                 window.scrollTo(sl, st + scrAmt);
2657             }
2658
2659             // Scroll up if the window is scrolled down and the top of the object
2660             // goes above the top border
2661             if ( y < st && st > 0 && y - st < thresh ) {
2662                 window.scrollTo(sl, st - scrAmt);
2663             }
2664
2665             // Scroll right if the obj is beyond the right border and the cursor is
2666             // near the border.
2667             if ( right > clientW && toRight < thresh ) {
2668                 window.scrollTo(sl + scrAmt, st);
2669             }
2670
2671             // Scroll left if the window has been scrolled to the right and the obj
2672             // extends past the left border
2673             if ( x < sl && sl > 0 && x - sl < thresh ) {
2674                 window.scrollTo(sl - scrAmt, st);
2675             }
2676         }
2677     },
2678
2679     /**
2680      * Finds the location the element should be placed if we want to move
2681      * it to where the mouse location less the click offset would place us.
2682      * @method getTargetCoord
2683      * @param {int} iPageX the X coordinate of the click
2684      * @param {int} iPageY the Y coordinate of the click
2685      * @return an object that contains the coordinates (Object.x and Object.y)
2686      * @private
2687      */
2688     getTargetCoord: function(iPageX, iPageY) {
2689
2690
2691         var x = iPageX - this.deltaX;
2692         var y = iPageY - this.deltaY;
2693
2694         if (this.constrainX) {
2695             if (x < this.minX) { x = this.minX; }
2696             if (x > this.maxX) { x = this.maxX; }
2697         }
2698
2699         if (this.constrainY) {
2700             if (y < this.minY) { y = this.minY; }
2701             if (y > this.maxY) { y = this.maxY; }
2702         }
2703
2704         x = this.getTick(x, this.xTicks);
2705         y = this.getTick(y, this.yTicks);
2706
2707
2708         return {x:x, y:y};
2709     },
2710
2711     /*
2712      * Sets up config options specific to this class. Overrides
2713      * Roo.dd.DragDrop, but all versions of this method through the
2714      * inheritance chain are called
2715      */
2716     applyConfig: function() {
2717         Roo.dd.DD.superclass.applyConfig.call(this);
2718         this.scroll = (this.config.scroll !== false);
2719     },
2720
2721     /*
2722      * Event that fires prior to the onMouseDown event.  Overrides
2723      * Roo.dd.DragDrop.
2724      */
2725     b4MouseDown: function(e) {
2726         // this.resetConstraints();
2727         this.autoOffset(e.getPageX(),
2728                             e.getPageY());
2729     },
2730
2731     /*
2732      * Event that fires prior to the onDrag event.  Overrides
2733      * Roo.dd.DragDrop.
2734      */
2735     b4Drag: function(e) {
2736         this.setDragElPos(e.getPageX(),
2737                             e.getPageY());
2738     },
2739
2740     toString: function() {
2741         return ("DD " + this.id);
2742     }
2743
2744     //////////////////////////////////////////////////////////////////////////
2745     // Debugging ygDragDrop events that can be overridden
2746     //////////////////////////////////////////////////////////////////////////
2747     /*
2748     startDrag: function(x, y) {
2749     },
2750
2751     onDrag: function(e) {
2752     },
2753
2754     onDragEnter: function(e, id) {
2755     },
2756
2757     onDragOver: function(e, id) {
2758     },
2759
2760     onDragOut: function(e, id) {
2761     },
2762
2763     onDragDrop: function(e, id) {
2764     },
2765
2766     endDrag: function(e) {
2767     }
2768
2769     */
2770
2771 });/*
2772  * Based on:
2773  * Ext JS Library 1.1.1
2774  * Copyright(c) 2006-2007, Ext JS, LLC.
2775  *
2776  * Originally Released Under LGPL - original licence link has changed is not relivant.
2777  *
2778  * Fork - LGPL
2779  * <script type="text/javascript">
2780  */
2781
2782 /**
2783  * @class Roo.dd.DDProxy
2784  * A DragDrop implementation that inserts an empty, bordered div into
2785  * the document that follows the cursor during drag operations.  At the time of
2786  * the click, the frame div is resized to the dimensions of the linked html
2787  * element, and moved to the exact location of the linked element.
2788  *
2789  * References to the "frame" element refer to the single proxy element that
2790  * was created to be dragged in place of all DDProxy elements on the
2791  * page.
2792  *
2793  * @extends Roo.dd.DD
2794  * @constructor
2795  * @param {String} id the id of the linked html element
2796  * @param {String} sGroup the group of related DragDrop objects
2797  * @param {object} config an object containing configurable attributes
2798  *                Valid properties for DDProxy in addition to those in DragDrop:
2799  *                   resizeFrame, centerFrame, dragElId
2800  */
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2802     if (id) {
2803         this.init(id, sGroup, config);
2804         this.initFrame();
2805     }
2806 };
2807
2808 /**
2809  * The default drag frame div id
2810  * @property Roo.dd.DDProxy.dragElId
2811  * @type String
2812  * @static
2813  */
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2815
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2817
2818     /**
2819      * By default we resize the drag frame to be the same size as the element
2820      * we want to drag (this is to get the frame effect).  We can turn it off
2821      * if we want a different behavior.
2822      * @property resizeFrame
2823      * @type boolean
2824      */
2825     resizeFrame: true,
2826
2827     /**
2828      * By default the frame is positioned exactly where the drag element is, so
2829      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
2830      * you do not have constraints on the obj is to have the drag frame centered
2831      * around the cursor.  Set centerFrame to true for this effect.
2832      * @property centerFrame
2833      * @type boolean
2834      */
2835     centerFrame: false,
2836
2837     /**
2838      * Creates the proxy element if it does not yet exist
2839      * @method createFrame
2840      */
2841     createFrame: function() {
2842         var self = this;
2843         var body = document.body;
2844
2845         if (!body || !body.firstChild) {
2846             setTimeout( function() { self.createFrame(); }, 50 );
2847             return;
2848         }
2849
2850         var div = this.getDragEl();
2851
2852         if (!div) {
2853             div    = document.createElement("div");
2854             div.id = this.dragElId;
2855             var s  = div.style;
2856
2857             s.position   = "absolute";
2858             s.visibility = "hidden";
2859             s.cursor     = "move";
2860             s.border     = "2px solid #aaa";
2861             s.zIndex     = 999;
2862
2863             // appendChild can blow up IE if invoked prior to the window load event
2864             // while rendering a table.  It is possible there are other scenarios
2865             // that would cause this to happen as well.
2866             body.insertBefore(div, body.firstChild);
2867         }
2868     },
2869
2870     /**
2871      * Initialization for the drag frame element.  Must be called in the
2872      * constructor of all subclasses
2873      * @method initFrame
2874      */
2875     initFrame: function() {
2876         this.createFrame();
2877     },
2878
2879     applyConfig: function() {
2880         Roo.dd.DDProxy.superclass.applyConfig.call(this);
2881
2882         this.resizeFrame = (this.config.resizeFrame !== false);
2883         this.centerFrame = (this.config.centerFrame);
2884         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2885     },
2886
2887     /**
2888      * Resizes the drag frame to the dimensions of the clicked object, positions
2889      * it over the object, and finally displays it
2890      * @method showFrame
2891      * @param {int} iPageX X click position
2892      * @param {int} iPageY Y click position
2893      * @private
2894      */
2895     showFrame: function(iPageX, iPageY) {
2896         var el = this.getEl();
2897         var dragEl = this.getDragEl();
2898         var s = dragEl.style;
2899
2900         this._resizeProxy();
2901
2902         if (this.centerFrame) {
2903             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2904                            Math.round(parseInt(s.height, 10)/2) );
2905         }
2906
2907         this.setDragElPos(iPageX, iPageY);
2908
2909         Roo.fly(dragEl).show();
2910     },
2911
2912     /**
2913      * The proxy is automatically resized to the dimensions of the linked
2914      * element when a drag is initiated, unless resizeFrame is set to false
2915      * @method _resizeProxy
2916      * @private
2917      */
2918     _resizeProxy: function() {
2919         if (this.resizeFrame) {
2920             var el = this.getEl();
2921             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2922         }
2923     },
2924
2925     // overrides Roo.dd.DragDrop
2926     b4MouseDown: function(e) {
2927         var x = e.getPageX();
2928         var y = e.getPageY();
2929         this.autoOffset(x, y);
2930         this.setDragElPos(x, y);
2931     },
2932
2933     // overrides Roo.dd.DragDrop
2934     b4StartDrag: function(x, y) {
2935         // show the drag frame
2936         this.showFrame(x, y);
2937     },
2938
2939     // overrides Roo.dd.DragDrop
2940     b4EndDrag: function(e) {
2941         Roo.fly(this.getDragEl()).hide();
2942     },
2943
2944     // overrides Roo.dd.DragDrop
2945     // By default we try to move the element to the last location of the frame.
2946     // This is so that the default behavior mirrors that of Roo.dd.DD.
2947     endDrag: function(e) {
2948
2949         var lel = this.getEl();
2950         var del = this.getDragEl();
2951
2952         // Show the drag frame briefly so we can get its position
2953         del.style.visibility = "";
2954
2955         this.beforeMove();
2956         // Hide the linked element before the move to get around a Safari
2957         // rendering bug.
2958         lel.style.visibility = "hidden";
2959         Roo.dd.DDM.moveToEl(lel, del);
2960         del.style.visibility = "hidden";
2961         lel.style.visibility = "";
2962
2963         this.afterDrag();
2964     },
2965
2966     beforeMove : function(){
2967
2968     },
2969
2970     afterDrag : function(){
2971
2972     },
2973
2974     toString: function() {
2975         return ("DDProxy " + this.id);
2976     }
2977
2978 });
2979 /*
2980  * Based on:
2981  * Ext JS Library 1.1.1
2982  * Copyright(c) 2006-2007, Ext JS, LLC.
2983  *
2984  * Originally Released Under LGPL - original licence link has changed is not relivant.
2985  *
2986  * Fork - LGPL
2987  * <script type="text/javascript">
2988  */
2989
2990  /**
2991  * @class Roo.dd.DDTarget
2992  * A DragDrop implementation that does not move, but can be a drop
2993  * target.  You would get the same result by simply omitting implementation
2994  * for the event callbacks, but this way we reduce the processing cost of the
2995  * event listener and the callbacks.
2996  * @extends Roo.dd.DragDrop
2997  * @constructor
2998  * @param {String} id the id of the element that is a drop target
2999  * @param {String} sGroup the group of related DragDrop objects
3000  * @param {object} config an object containing configurable attributes
3001  *                 Valid properties for DDTarget in addition to those in
3002  *                 DragDrop:
3003  *                    none
3004  */
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3006     if (id) {
3007         this.initTarget(id, sGroup, config);
3008     }
3009 };
3010
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013     toString: function() {
3014         return ("DDTarget " + this.id);
3015     }
3016 });
3017 /*
3018  * Based on:
3019  * Ext JS Library 1.1.1
3020  * Copyright(c) 2006-2007, Ext JS, LLC.
3021  *
3022  * Originally Released Under LGPL - original licence link has changed is not relivant.
3023  *
3024  * Fork - LGPL
3025  * <script type="text/javascript">
3026  */
3027  
3028
3029 /**
3030  * @class Roo.dd.ScrollManager
3031  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3033  * @singleton
3034  */
3035 Roo.dd.ScrollManager = function(){
3036     var ddm = Roo.dd.DragDropMgr;
3037     var els = {};
3038     var dragEl = null;
3039     var proc = {};
3040     
3041     var onStop = function(e){
3042         dragEl = null;
3043         clearProc();
3044     };
3045     
3046     var triggerRefresh = function(){
3047         if(ddm.dragCurrent){
3048              ddm.refreshCache(ddm.dragCurrent.groups);
3049         }
3050     };
3051     
3052     var doScroll = function(){
3053         if(ddm.dragCurrent){
3054             var dds = Roo.dd.ScrollManager;
3055             if(!dds.animate){
3056                 if(proc.el.scroll(proc.dir, dds.increment)){
3057                     triggerRefresh();
3058                 }
3059             }else{
3060                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3061             }
3062         }
3063     };
3064     
3065     var clearProc = function(){
3066         if(proc.id){
3067             clearInterval(proc.id);
3068         }
3069         proc.id = 0;
3070         proc.el = null;
3071         proc.dir = "";
3072     };
3073     
3074     var startProc = function(el, dir){
3075         clearProc();
3076         proc.el = el;
3077         proc.dir = dir;
3078         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3079     };
3080     
3081     var onFire = function(e, isDrop){
3082         if(isDrop || !ddm.dragCurrent){ return; }
3083         var dds = Roo.dd.ScrollManager;
3084         if(!dragEl || dragEl != ddm.dragCurrent){
3085             dragEl = ddm.dragCurrent;
3086             // refresh regions on drag start
3087             dds.refreshCache();
3088         }
3089         
3090         var xy = Roo.lib.Event.getXY(e);
3091         var pt = new Roo.lib.Point(xy[0], xy[1]);
3092         for(var id in els){
3093             var el = els[id], r = el._region;
3094             if(r && r.contains(pt) && el.isScrollable()){
3095                 if(r.bottom - pt.y <= dds.thresh){
3096                     if(proc.el != el){
3097                         startProc(el, "down");
3098                     }
3099                     return;
3100                 }else if(r.right - pt.x <= dds.thresh){
3101                     if(proc.el != el){
3102                         startProc(el, "left");
3103                     }
3104                     return;
3105                 }else if(pt.y - r.top <= dds.thresh){
3106                     if(proc.el != el){
3107                         startProc(el, "up");
3108                     }
3109                     return;
3110                 }else if(pt.x - r.left <= dds.thresh){
3111                     if(proc.el != el){
3112                         startProc(el, "right");
3113                     }
3114                     return;
3115                 }
3116             }
3117         }
3118         clearProc();
3119     };
3120     
3121     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3123     
3124     return {
3125         /**
3126          * Registers new overflow element(s) to auto scroll
3127          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3128          */
3129         register : function(el){
3130             if(el instanceof Array){
3131                 for(var i = 0, len = el.length; i < len; i++) {
3132                         this.register(el[i]);
3133                 }
3134             }else{
3135                 el = Roo.get(el);
3136                 els[el.id] = el;
3137             }
3138         },
3139         
3140         /**
3141          * Unregisters overflow element(s) so they are no longer scrolled
3142          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3143          */
3144         unregister : function(el){
3145             if(el instanceof Array){
3146                 for(var i = 0, len = el.length; i < len; i++) {
3147                         this.unregister(el[i]);
3148                 }
3149             }else{
3150                 el = Roo.get(el);
3151                 delete els[el.id];
3152             }
3153         },
3154         
3155         /**
3156          * The number of pixels from the edge of a container the pointer needs to be to 
3157          * trigger scrolling (defaults to 25)
3158          * @type Number
3159          */
3160         thresh : 25,
3161         
3162         /**
3163          * The number of pixels to scroll in each scroll increment (defaults to 50)
3164          * @type Number
3165          */
3166         increment : 100,
3167         
3168         /**
3169          * The frequency of scrolls in milliseconds (defaults to 500)
3170          * @type Number
3171          */
3172         frequency : 500,
3173         
3174         /**
3175          * True to animate the scroll (defaults to true)
3176          * @type Boolean
3177          */
3178         animate: true,
3179         
3180         /**
3181          * The animation duration in seconds - 
3182          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3183          * @type Number
3184          */
3185         animDuration: .4,
3186         
3187         /**
3188          * Manually trigger a cache refresh.
3189          */
3190         refreshCache : function(){
3191             for(var id in els){
3192                 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193                     els[id]._region = els[id].getRegion();
3194                 }
3195             }
3196         }
3197     };
3198 }();/*
3199  * Based on:
3200  * Ext JS Library 1.1.1
3201  * Copyright(c) 2006-2007, Ext JS, LLC.
3202  *
3203  * Originally Released Under LGPL - original licence link has changed is not relivant.
3204  *
3205  * Fork - LGPL
3206  * <script type="text/javascript">
3207  */
3208  
3209
3210 /**
3211  * @class Roo.dd.Registry
3212  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
3213  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3214  * @singleton
3215  */
3216 Roo.dd.Registry = function(){
3217     var elements = {}; 
3218     var handles = {}; 
3219     var autoIdSeed = 0;
3220
3221     var getId = function(el, autogen){
3222         if(typeof el == "string"){
3223             return el;
3224         }
3225         var id = el.id;
3226         if(!id && autogen !== false){
3227             id = "roodd-" + (++autoIdSeed);
3228             el.id = id;
3229         }
3230         return id;
3231     };
3232     
3233     return {
3234     /**
3235      * Register a drag drop element
3236      * @param {String|HTMLElement} element The id or DOM node to register
3237      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
3239      * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240      * populated in the data object (if applicable):
3241      * <pre>
3242 Value      Description<br />
3243 ---------  ------------------------------------------<br />
3244 handles    Array of DOM nodes that trigger dragging<br />
3245            for the element being registered<br />
3246 isHandle   True if the element passed in triggers<br />
3247            dragging itself, else false
3248 </pre>
3249      */
3250         register : function(el, data){
3251             data = data || {};
3252             if(typeof el == "string"){
3253                 el = document.getElementById(el);
3254             }
3255             data.ddel = el;
3256             elements[getId(el)] = data;
3257             if(data.isHandle !== false){
3258                 handles[data.ddel.id] = data;
3259             }
3260             if(data.handles){
3261                 var hs = data.handles;
3262                 for(var i = 0, len = hs.length; i < len; i++){
3263                         handles[getId(hs[i])] = data;
3264                 }
3265             }
3266         },
3267
3268     /**
3269      * Unregister a drag drop element
3270      * @param {String|HTMLElement}  element The id or DOM node to unregister
3271      */
3272         unregister : function(el){
3273             var id = getId(el, false);
3274             var data = elements[id];
3275             if(data){
3276                 delete elements[id];
3277                 if(data.handles){
3278                     var hs = data.handles;
3279                     for(var i = 0, len = hs.length; i < len; i++){
3280                         delete handles[getId(hs[i], false)];
3281                     }
3282                 }
3283             }
3284         },
3285
3286     /**
3287      * Returns the handle registered for a DOM Node by id
3288      * @param {String|HTMLElement} id The DOM node or id to look up
3289      * @return {Object} handle The custom handle data
3290      */
3291         getHandle : function(id){
3292             if(typeof id != "string"){ // must be element?
3293                 id = id.id;
3294             }
3295             return handles[id];
3296         },
3297
3298     /**
3299      * Returns the handle that is registered for the DOM node that is the target of the event
3300      * @param {Event} e The event
3301      * @return {Object} handle The custom handle data
3302      */
3303         getHandleFromEvent : function(e){
3304             var t = Roo.lib.Event.getTarget(e);
3305             return t ? handles[t.id] : null;
3306         },
3307
3308     /**
3309      * Returns a custom data object that is registered for a DOM node by id
3310      * @param {String|HTMLElement} id The DOM node or id to look up
3311      * @return {Object} data The custom data
3312      */
3313         getTarget : function(id){
3314             if(typeof id != "string"){ // must be element?
3315                 id = id.id;
3316             }
3317             return elements[id];
3318         },
3319
3320     /**
3321      * Returns a custom data object that is registered for the DOM node that is the target of the event
3322      * @param {Event} e The event
3323      * @return {Object} data The custom data
3324      */
3325         getTargetFromEvent : function(e){
3326             var t = Roo.lib.Event.getTarget(e);
3327             return t ? elements[t.id] || handles[t.id] : null;
3328         }
3329     };
3330 }();/*
3331  * Based on:
3332  * Ext JS Library 1.1.1
3333  * Copyright(c) 2006-2007, Ext JS, LLC.
3334  *
3335  * Originally Released Under LGPL - original licence link has changed is not relivant.
3336  *
3337  * Fork - LGPL
3338  * <script type="text/javascript">
3339  */
3340  
3341
3342 /**
3343  * @class Roo.dd.StatusProxy
3344  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
3345  * default drag proxy used by all Roo.dd components.
3346  * @constructor
3347  * @param {Object} config
3348  */
3349 Roo.dd.StatusProxy = function(config){
3350     Roo.apply(this, config);
3351     this.id = this.id || Roo.id();
3352     this.el = new Roo.Layer({
3353         dh: {
3354             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355                 {tag: "div", cls: "x-dd-drop-icon"},
3356                 {tag: "div", cls: "x-dd-drag-ghost"}
3357             ]
3358         }, 
3359         shadow: !config || config.shadow !== false
3360     });
3361     this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362     this.dropStatus = this.dropNotAllowed;
3363 };
3364
3365 Roo.dd.StatusProxy.prototype = {
3366     /**
3367      * @cfg {String} dropAllowed
3368      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3369      */
3370     dropAllowed : "x-dd-drop-ok",
3371     /**
3372      * @cfg {String} dropNotAllowed
3373      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3374      */
3375     dropNotAllowed : "x-dd-drop-nodrop",
3376
3377     /**
3378      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379      * over the current target element.
3380      * @param {String} cssClass The css class for the new drop status indicator image
3381      */
3382     setStatus : function(cssClass){
3383         cssClass = cssClass || this.dropNotAllowed;
3384         if(this.dropStatus != cssClass){
3385             this.el.replaceClass(this.dropStatus, cssClass);
3386             this.dropStatus = cssClass;
3387         }
3388     },
3389
3390     /**
3391      * Resets the status indicator to the default dropNotAllowed value
3392      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3393      */
3394     reset : function(clearGhost){
3395         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396         this.dropStatus = this.dropNotAllowed;
3397         if(clearGhost){
3398             this.ghost.update("");
3399         }
3400     },
3401
3402     /**
3403      * Updates the contents of the ghost element
3404      * @param {String} html The html that will replace the current innerHTML of the ghost element
3405      */
3406     update : function(html){
3407         if(typeof html == "string"){
3408             this.ghost.update(html);
3409         }else{
3410             this.ghost.update("");
3411             html.style.margin = "0";
3412             this.ghost.dom.appendChild(html);
3413         }
3414         // ensure float = none set?? cant remember why though.
3415         var el = this.ghost.dom.firstChild;
3416                 if(el){
3417                         Roo.fly(el).setStyle('float', 'none');
3418                 }
3419     },
3420     
3421     /**
3422      * Returns the underlying proxy {@link Roo.Layer}
3423      * @return {Roo.Layer} el
3424     */
3425     getEl : function(){
3426         return this.el;
3427     },
3428
3429     /**
3430      * Returns the ghost element
3431      * @return {Roo.Element} el
3432      */
3433     getGhost : function(){
3434         return this.ghost;
3435     },
3436
3437     /**
3438      * Hides the proxy
3439      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3440      */
3441     hide : function(clear){
3442         this.el.hide();
3443         if(clear){
3444             this.reset(true);
3445         }
3446     },
3447
3448     /**
3449      * Stops the repair animation if it's currently running
3450      */
3451     stop : function(){
3452         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3453             this.anim.stop();
3454         }
3455     },
3456
3457     /**
3458      * Displays this proxy
3459      */
3460     show : function(){
3461         this.el.show();
3462     },
3463
3464     /**
3465      * Force the Layer to sync its shadow and shim positions to the element
3466      */
3467     sync : function(){
3468         this.el.sync();
3469     },
3470
3471     /**
3472      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
3473      * invalid drop operation by the item being dragged.
3474      * @param {Array} xy The XY position of the element ([x, y])
3475      * @param {Function} callback The function to call after the repair is complete
3476      * @param {Object} scope The scope in which to execute the callback
3477      */
3478     repair : function(xy, callback, scope){
3479         this.callback = callback;
3480         this.scope = scope;
3481         if(xy && this.animRepair !== false){
3482             this.el.addClass("x-dd-drag-repair");
3483             this.el.hideUnders(true);
3484             this.anim = this.el.shift({
3485                 duration: this.repairDuration || .5,
3486                 easing: 'easeOut',
3487                 xy: xy,
3488                 stopFx: true,
3489                 callback: this.afterRepair,
3490                 scope: this
3491             });
3492         }else{
3493             this.afterRepair();
3494         }
3495     },
3496
3497     // private
3498     afterRepair : function(){
3499         this.hide(true);
3500         if(typeof this.callback == "function"){
3501             this.callback.call(this.scope || this);
3502         }
3503         this.callback = null;
3504         this.scope = null;
3505     }
3506 };/*
3507  * Based on:
3508  * Ext JS Library 1.1.1
3509  * Copyright(c) 2006-2007, Ext JS, LLC.
3510  *
3511  * Originally Released Under LGPL - original licence link has changed is not relivant.
3512  *
3513  * Fork - LGPL
3514  * <script type="text/javascript">
3515  */
3516
3517 /**
3518  * @class Roo.dd.DragSource
3519  * @extends Roo.dd.DDProxy
3520  * A simple class that provides the basic implementation needed to make any element draggable.
3521  * @constructor
3522  * @param {String/HTMLElement/Element} el The container element
3523  * @param {Object} config
3524  */
3525 Roo.dd.DragSource = function(el, config){
3526     this.el = Roo.get(el);
3527     this.dragData = {};
3528     
3529     Roo.apply(this, config);
3530     
3531     if(!this.proxy){
3532         this.proxy = new Roo.dd.StatusProxy();
3533     }
3534
3535     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3537     
3538     this.dragging = false;
3539 };
3540
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3542     /**
3543      * @cfg {String} dropAllowed
3544      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3545      */
3546     dropAllowed : "x-dd-drop-ok",
3547     /**
3548      * @cfg {String} dropNotAllowed
3549      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3550      */
3551     dropNotAllowed : "x-dd-drop-nodrop",
3552
3553     /**
3554      * Returns the data object associated with this drag source
3555      * @return {Object} data An object containing arbitrary data
3556      */
3557     getDragData : function(e){
3558         return this.dragData;
3559     },
3560
3561     // private
3562     onDragEnter : function(e, id){
3563         var target = Roo.dd.DragDropMgr.getDDById(id);
3564         this.cachedTarget = target;
3565         if(this.beforeDragEnter(target, e, id) !== false){
3566             if(target.isNotifyTarget){
3567                 var status = target.notifyEnter(this, e, this.dragData);
3568                 this.proxy.setStatus(status);
3569             }else{
3570                 this.proxy.setStatus(this.dropAllowed);
3571             }
3572             
3573             if(this.afterDragEnter){
3574                 /**
3575                  * An empty function by default, but provided so that you can perform a custom action
3576                  * when the dragged item enters the drop target by providing an implementation.
3577                  * @param {Roo.dd.DragDrop} target The drop target
3578                  * @param {Event} e The event object
3579                  * @param {String} id The id of the dragged element
3580                  * @method afterDragEnter
3581                  */
3582                 this.afterDragEnter(target, e, id);
3583             }
3584         }
3585     },
3586
3587     /**
3588      * An empty function by default, but provided so that you can perform a custom action
3589      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590      * @param {Roo.dd.DragDrop} target The drop target
3591      * @param {Event} e The event object
3592      * @param {String} id The id of the dragged element
3593      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3594      */
3595     beforeDragEnter : function(target, e, id){
3596         return true;
3597     },
3598
3599     // private
3600     alignElWithMouse: function() {
3601         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3602         this.proxy.sync();
3603     },
3604
3605     // private
3606     onDragOver : function(e, id){
3607         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608         if(this.beforeDragOver(target, e, id) !== false){
3609             if(target.isNotifyTarget){
3610                 var status = target.notifyOver(this, e, this.dragData);
3611                 this.proxy.setStatus(status);
3612             }
3613
3614             if(this.afterDragOver){
3615                 /**
3616                  * An empty function by default, but provided so that you can perform a custom action
3617                  * while the dragged item is over the drop target by providing an implementation.
3618                  * @param {Roo.dd.DragDrop} target The drop target
3619                  * @param {Event} e The event object
3620                  * @param {String} id The id of the dragged element
3621                  * @method afterDragOver
3622                  */
3623                 this.afterDragOver(target, e, id);
3624             }
3625         }
3626     },
3627
3628     /**
3629      * An empty function by default, but provided so that you can perform a custom action
3630      * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631      * @param {Roo.dd.DragDrop} target The drop target
3632      * @param {Event} e The event object
3633      * @param {String} id The id of the dragged element
3634      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3635      */
3636     beforeDragOver : function(target, e, id){
3637         return true;
3638     },
3639
3640     // private
3641     onDragOut : function(e, id){
3642         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643         if(this.beforeDragOut(target, e, id) !== false){
3644             if(target.isNotifyTarget){
3645                 target.notifyOut(this, e, this.dragData);
3646             }
3647             this.proxy.reset();
3648             if(this.afterDragOut){
3649                 /**
3650                  * An empty function by default, but provided so that you can perform a custom action
3651                  * after the dragged item is dragged out of the target without dropping.
3652                  * @param {Roo.dd.DragDrop} target The drop target
3653                  * @param {Event} e The event object
3654                  * @param {String} id The id of the dragged element
3655                  * @method afterDragOut
3656                  */
3657                 this.afterDragOut(target, e, id);
3658             }
3659         }
3660         this.cachedTarget = null;
3661     },
3662
3663     /**
3664      * An empty function by default, but provided so that you can perform a custom action before the dragged
3665      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666      * @param {Roo.dd.DragDrop} target The drop target
3667      * @param {Event} e The event object
3668      * @param {String} id The id of the dragged element
3669      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3670      */
3671     beforeDragOut : function(target, e, id){
3672         return true;
3673     },
3674     
3675     // private
3676     onDragDrop : function(e, id){
3677         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678         if(this.beforeDragDrop(target, e, id) !== false){
3679             if(target.isNotifyTarget){
3680                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681                     this.onValidDrop(target, e, id);
3682                 }else{
3683                     this.onInvalidDrop(target, e, id);
3684                 }
3685             }else{
3686                 this.onValidDrop(target, e, id);
3687             }
3688             
3689             if(this.afterDragDrop){
3690                 /**
3691                  * An empty function by default, but provided so that you can perform a custom action
3692                  * after a valid drag drop has occurred by providing an implementation.
3693                  * @param {Roo.dd.DragDrop} target The drop target
3694                  * @param {Event} e The event object
3695                  * @param {String} id The id of the dropped element
3696                  * @method afterDragDrop
3697                  */
3698                 this.afterDragDrop(target, e, id);
3699             }
3700         }
3701         delete this.cachedTarget;
3702     },
3703
3704     /**
3705      * An empty function by default, but provided so that you can perform a custom action before the dragged
3706      * item is dropped onto the target and optionally cancel the onDragDrop.
3707      * @param {Roo.dd.DragDrop} target The drop target
3708      * @param {Event} e The event object
3709      * @param {String} id The id of the dragged element
3710      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3711      */
3712     beforeDragDrop : function(target, e, id){
3713         return true;
3714     },
3715
3716     // private
3717     onValidDrop : function(target, e, id){
3718         this.hideProxy();
3719         if(this.afterValidDrop){
3720             /**
3721              * An empty function by default, but provided so that you can perform a custom action
3722              * after a valid drop has occurred by providing an implementation.
3723              * @param {Object} target The target DD 
3724              * @param {Event} e The event object
3725              * @param {String} id The id of the dropped element
3726              * @method afterInvalidDrop
3727              */
3728             this.afterValidDrop(target, e, id);
3729         }
3730     },
3731
3732     // private
3733     getRepairXY : function(e, data){
3734         return this.el.getXY();  
3735     },
3736
3737     // private
3738     onInvalidDrop : function(target, e, id){
3739         this.beforeInvalidDrop(target, e, id);
3740         if(this.cachedTarget){
3741             if(this.cachedTarget.isNotifyTarget){
3742                 this.cachedTarget.notifyOut(this, e, this.dragData);
3743             }
3744             this.cacheTarget = null;
3745         }
3746         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3747
3748         if(this.afterInvalidDrop){
3749             /**
3750              * An empty function by default, but provided so that you can perform a custom action
3751              * after an invalid drop has occurred by providing an implementation.
3752              * @param {Event} e The event object
3753              * @param {String} id The id of the dropped element
3754              * @method afterInvalidDrop
3755              */
3756             this.afterInvalidDrop(e, id);
3757         }
3758     },
3759
3760     // private
3761     afterRepair : function(){
3762         if(Roo.enableFx){
3763             this.el.highlight(this.hlColor || "c3daf9");
3764         }
3765         this.dragging = false;
3766     },
3767
3768     /**
3769      * An empty function by default, but provided so that you can perform a custom action after an invalid
3770      * drop has occurred.
3771      * @param {Roo.dd.DragDrop} target The drop target
3772      * @param {Event} e The event object
3773      * @param {String} id The id of the dragged element
3774      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3775      */
3776     beforeInvalidDrop : function(target, e, id){
3777         return true;
3778     },
3779
3780     // private
3781     handleMouseDown : function(e){
3782         if(this.dragging) {
3783             return;
3784         }
3785         var data = this.getDragData(e);
3786         if(data && this.onBeforeDrag(data, e) !== false){
3787             this.dragData = data;
3788             this.proxy.stop();
3789             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3790         } 
3791     },
3792
3793     /**
3794      * An empty function by default, but provided so that you can perform a custom action before the initial
3795      * drag event begins and optionally cancel it.
3796      * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797      * @param {Event} e The event object
3798      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3799      */
3800     onBeforeDrag : function(data, e){
3801         return true;
3802     },
3803
3804     /**
3805      * An empty function by default, but provided so that you can perform a custom action once the initial
3806      * drag event has begun.  The drag cannot be canceled from this function.
3807      * @param {Number} x The x position of the click on the dragged object
3808      * @param {Number} y The y position of the click on the dragged object
3809      */
3810     onStartDrag : Roo.emptyFn,
3811
3812     // private - YUI override
3813     startDrag : function(x, y){
3814         this.proxy.reset();
3815         this.dragging = true;
3816         this.proxy.update("");
3817         this.onInitDrag(x, y);
3818         this.proxy.show();
3819     },
3820
3821     // private
3822     onInitDrag : function(x, y){
3823         var clone = this.el.dom.cloneNode(true);
3824         clone.id = Roo.id(); // prevent duplicate ids
3825         this.proxy.update(clone);
3826         this.onStartDrag(x, y);
3827         return true;
3828     },
3829
3830     /**
3831      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3833      */
3834     getProxy : function(){
3835         return this.proxy;  
3836     },
3837
3838     /**
3839      * Hides the drag source's {@link Roo.dd.StatusProxy}
3840      */
3841     hideProxy : function(){
3842         this.proxy.hide();  
3843         this.proxy.reset(true);
3844         this.dragging = false;
3845     },
3846
3847     // private
3848     triggerCacheRefresh : function(){
3849         Roo.dd.DDM.refreshCache(this.groups);
3850     },
3851
3852     // private - override to prevent hiding
3853     b4EndDrag: function(e) {
3854     },
3855
3856     // private - override to prevent moving
3857     endDrag : function(e){
3858         this.onEndDrag(this.dragData, e);
3859     },
3860
3861     // private
3862     onEndDrag : function(data, e){
3863     },
3864     
3865     // private - pin to cursor
3866     autoOffset : function(x, y) {
3867         this.setDelta(-12, -20);
3868     }    
3869 });/*
3870  * Based on:
3871  * Ext JS Library 1.1.1
3872  * Copyright(c) 2006-2007, Ext JS, LLC.
3873  *
3874  * Originally Released Under LGPL - original licence link has changed is not relivant.
3875  *
3876  * Fork - LGPL
3877  * <script type="text/javascript">
3878  */
3879
3880
3881 /**
3882  * @class Roo.dd.DropTarget
3883  * @extends Roo.dd.DDTarget
3884  * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
3886  * @constructor
3887  * @param {String/HTMLElement/Element} el The container element
3888  * @param {Object} config
3889  */
3890 Roo.dd.DropTarget = function(el, config){
3891     this.el = Roo.get(el);
3892     
3893     Roo.apply(this, config);
3894     
3895     if(this.containerScroll){
3896         Roo.dd.ScrollManager.register(this.el);
3897     }
3898     
3899      
3900     Roo.dd.DropTarget.superclass.constructor.call(  this, 
3901         this.el.dom, 
3902         this.ddGroup || this.group,
3903         {
3904             isTarget: true,
3905             events : {
3906                  /**
3907                  * @scope Roo.dd.DropTarget
3908                  */
3909                  
3910                  /**
3911                  * @event enter
3912                  * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913                  * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914                  * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
3915                  * 
3916                  * IMPORTANT : it should set this.overClass and this.dropAllowed
3917                  * 
3918                  * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919                  * @param {Event} e The event
3920                  * @param {Object} data An object containing arbitrary data supplied by the drag source
3921                  */
3922                 "enter" : true,
3923                 
3924                  /**
3925                  * @event over
3926                  * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927                  * This method will be called on every mouse movement while the drag source is over the drop target.
3928                  * This default implementation simply returns the dropAllowed config value.
3929                  * 
3930                  * IMPORTANT : it should set this.dropAllowed
3931                  * 
3932                  * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933                  * @param {Event} e The event
3934                  * @param {Object} data An object containing arbitrary data supplied by the drag source
3935                  
3936                  */
3937                 "over" : true,
3938                 /**
3939                  * @event out
3940                  * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941                  * out of the target without dropping.  This default implementation simply removes the CSS class specified by
3942                  * overClass (if any) from the drop element.
3943                  * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944                  * @param {Event} e The event
3945                  * @param {Object} data An object containing arbitrary data supplied by the drag source
3946                  */
3947                  "out" : true,
3948                  
3949                 /**
3950                  * @event drop
3951                  * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952                  * been dropped on it.  This method has no default implementation and returns false, so you must provide an
3953                  * implementation that does something to process the drop event and returns true so that the drag source's
3954                  * repair action does not run.
3955                  * 
3956                  * IMPORTANT : it should set this.success
3957                  * 
3958                  * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959                  * @param {Event} e The event
3960                  * @param {Object} data An object containing arbitrary data supplied by the drag source
3961                 */
3962                  "drop" : true
3963             }
3964                 
3965         
3966         }
3967     );
3968
3969 };
3970
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3972     /**
3973      * @cfg {String} overClass
3974      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3975      */
3976     /**
3977      * @cfg {String} dropAllowed
3978      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3979      */
3980     dropAllowed : "x-dd-drop-ok",
3981     /**
3982      * @cfg {String} dropNotAllowed
3983      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3984      */
3985     dropNotAllowed : "x-dd-drop-nodrop",
3986     /**
3987      * @cfg {boolean} success
3988      * set this after drop listener.. 
3989      */
3990     success : false,
3991     /**
3992      * @cfg {boolean} valid
3993      * if the drop point is valid for over/enter..
3994      */
3995     valid : false,
3996     // private
3997     isTarget : true,
3998
3999     // private
4000     isNotifyTarget : true,
4001     
4002     // private
4003
4004     notifyEnter : function(dd, e, data){
4005         this.valid = true;
4006         this.fireEvent('enter', this, dd, e, data);
4007         if(this.overClass){
4008             this.el.addClass(this.overClass);
4009         }
4010         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4011     },
4012
4013     // private
4014
4015     notifyOver : function(dd, e, data){
4016         this.valid = true;
4017         this.fireEvent('over', this, dd, e, data);
4018         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4019     },
4020
4021     
4022     notifyOut : function(dd, e, data){
4023         this.fireEvent('out', this, dd, e, data);
4024         if(this.overClass){
4025             this.el.removeClass(this.overClass);
4026         }
4027     },
4028
4029     
4030     notifyDrop : function(dd, e, data){
4031         this.success = false;
4032         this.fireEvent('drop', this, dd, e, data);
4033         return this.success;
4034     }
4035 });/*
4036  * Based on:
4037  * Ext JS Library 1.1.1
4038  * Copyright(c) 2006-2007, Ext JS, LLC.
4039  *
4040  * Originally Released Under LGPL - original licence link has changed is not relivant.
4041  *
4042  * Fork - LGPL
4043  * <script type="text/javascript">
4044  */
4045
4046
4047 /**
4048  * @class Roo.dd.DragZone
4049  * @extends Roo.dd.DragSource
4050  * This class provides a container DD instance that proxies for multiple child node sources.<br />
4051  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4052  * @constructor
4053  * @param {String/HTMLElement/Element} el The container element
4054  * @param {Object} config
4055  */
4056 Roo.dd.DragZone = function(el, config){
4057     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4058     if(this.containerScroll){
4059         Roo.dd.ScrollManager.register(this.el);
4060     }
4061 };
4062
4063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4064     /**
4065      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4066      * for auto scrolling during drag operations.
4067      */
4068     /**
4069      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4070      * method after a failed drop (defaults to "c3daf9" - light blue)
4071      */
4072
4073     /**
4074      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4075      * for a valid target to drag based on the mouse down. Override this method
4076      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4077      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4078      * @param {EventObject} e The mouse down event
4079      * @return {Object} The dragData
4080      */
4081     getDragData : function(e){
4082         return Roo.dd.Registry.getHandleFromEvent(e);
4083     },
4084     
4085     /**
4086      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4087      * this.dragData.ddel
4088      * @param {Number} x The x position of the click on the dragged object
4089      * @param {Number} y The y position of the click on the dragged object
4090      * @return {Boolean} true to continue the drag, false to cancel
4091      */
4092     onInitDrag : function(x, y){
4093         this.proxy.update(this.dragData.ddel.cloneNode(true));
4094         this.onStartDrag(x, y);
4095         return true;
4096     },
4097     
4098     /**
4099      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4100      */
4101     afterRepair : function(){
4102         if(Roo.enableFx){
4103             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4104         }
4105         this.dragging = false;
4106     },
4107
4108     /**
4109      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4110      * the XY of this.dragData.ddel
4111      * @param {EventObject} e The mouse up event
4112      * @return {Array} The xy location (e.g. [100, 200])
4113      */
4114     getRepairXY : function(e){
4115         return Roo.Element.fly(this.dragData.ddel).getXY();  
4116     }
4117 });/*
4118  * Based on:
4119  * Ext JS Library 1.1.1
4120  * Copyright(c) 2006-2007, Ext JS, LLC.
4121  *
4122  * Originally Released Under LGPL - original licence link has changed is not relivant.
4123  *
4124  * Fork - LGPL
4125  * <script type="text/javascript">
4126  */
4127 /**
4128  * @class Roo.dd.DropZone
4129  * @extends Roo.dd.DropTarget
4130  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4131  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4132  * @constructor
4133  * @param {String/HTMLElement/Element} el The container element
4134  * @param {Object} config
4135  */
4136 Roo.dd.DropZone = function(el, config){
4137     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4138 };
4139
4140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4141     /**
4142      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4143      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4144      * provide your own custom lookup.
4145      * @param {Event} e The event
4146      * @return {Object} data The custom data
4147      */
4148     getTargetFromEvent : function(e){
4149         return Roo.dd.Registry.getTargetFromEvent(e);
4150     },
4151
4152     /**
4153      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4154      * that it has registered.  This method has no default implementation and should be overridden to provide
4155      * node-specific processing if necessary.
4156      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4157      * {@link #getTargetFromEvent} for this node)
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      */
4162     onNodeEnter : function(n, dd, e, data){
4163         
4164     },
4165
4166     /**
4167      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4168      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4169      * overridden to provide the proper feedback.
4170      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4171      * {@link #getTargetFromEvent} for this node)
4172      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4173      * @param {Event} e The event
4174      * @param {Object} data An object containing arbitrary data supplied by the drag source
4175      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4176      * underlying {@link Roo.dd.StatusProxy} can be updated
4177      */
4178     onNodeOver : function(n, dd, e, data){
4179         return this.dropAllowed;
4180     },
4181
4182     /**
4183      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4184      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4185      * node-specific processing if necessary.
4186      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4187      * {@link #getTargetFromEvent} for this node)
4188      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4189      * @param {Event} e The event
4190      * @param {Object} data An object containing arbitrary data supplied by the drag source
4191      */
4192     onNodeOut : function(n, dd, e, data){
4193         
4194     },
4195
4196     /**
4197      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4198      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4199      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4200      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4201      * {@link #getTargetFromEvent} for this node)
4202      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4203      * @param {Event} e The event
4204      * @param {Object} data An object containing arbitrary data supplied by the drag source
4205      * @return {Boolean} True if the drop was valid, else false
4206      */
4207     onNodeDrop : function(n, dd, e, data){
4208         return false;
4209     },
4210
4211     /**
4212      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4213      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4214      * it should be overridden to provide the proper feedback if necessary.
4215      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216      * @param {Event} e The event
4217      * @param {Object} data An object containing arbitrary data supplied by the drag source
4218      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4219      * underlying {@link Roo.dd.StatusProxy} can be updated
4220      */
4221     onContainerOver : function(dd, e, data){
4222         return this.dropNotAllowed;
4223     },
4224
4225     /**
4226      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4227      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4228      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4229      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4230      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4231      * @param {Event} e The event
4232      * @param {Object} data An object containing arbitrary data supplied by the drag source
4233      * @return {Boolean} True if the drop was valid, else false
4234      */
4235     onContainerDrop : function(dd, e, data){
4236         return false;
4237     },
4238
4239     /**
4240      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4241      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4242      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4243      * you should override this method and provide a custom implementation.
4244      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4245      * @param {Event} e The event
4246      * @param {Object} data An object containing arbitrary data supplied by the drag source
4247      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4248      * underlying {@link Roo.dd.StatusProxy} can be updated
4249      */
4250     notifyEnter : function(dd, e, data){
4251         return this.dropNotAllowed;
4252     },
4253
4254     /**
4255      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4256      * This method will be called on every mouse movement while the drag source is over the drop zone.
4257      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4258      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4259      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4260      * registered node, it will call {@link #onContainerOver}.
4261      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262      * @param {Event} e The event
4263      * @param {Object} data An object containing arbitrary data supplied by the drag source
4264      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265      * underlying {@link Roo.dd.StatusProxy} can be updated
4266      */
4267     notifyOver : function(dd, e, data){
4268         var n = this.getTargetFromEvent(e);
4269         if(!n){ // not over valid drop target
4270             if(this.lastOverNode){
4271                 this.onNodeOut(this.lastOverNode, dd, e, data);
4272                 this.lastOverNode = null;
4273             }
4274             return this.onContainerOver(dd, e, data);
4275         }
4276         if(this.lastOverNode != n){
4277             if(this.lastOverNode){
4278                 this.onNodeOut(this.lastOverNode, dd, e, data);
4279             }
4280             this.onNodeEnter(n, dd, e, data);
4281             this.lastOverNode = n;
4282         }
4283         return this.onNodeOver(n, dd, e, data);
4284     },
4285
4286     /**
4287      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4288      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4289      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4290      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4291      * @param {Event} e The event
4292      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4293      */
4294     notifyOut : function(dd, e, data){
4295         if(this.lastOverNode){
4296             this.onNodeOut(this.lastOverNode, dd, e, data);
4297             this.lastOverNode = null;
4298         }
4299     },
4300
4301     /**
4302      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4303      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4304      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4305      * otherwise it will call {@link #onContainerDrop}.
4306      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4307      * @param {Event} e The event
4308      * @param {Object} data An object containing arbitrary data supplied by the drag source
4309      * @return {Boolean} True if the drop was valid, else false
4310      */
4311     notifyDrop : function(dd, e, data){
4312         if(this.lastOverNode){
4313             this.onNodeOut(this.lastOverNode, dd, e, data);
4314             this.lastOverNode = null;
4315         }
4316         var n = this.getTargetFromEvent(e);
4317         return n ?
4318             this.onNodeDrop(n, dd, e, data) :
4319             this.onContainerDrop(dd, e, data);
4320     },
4321
4322     // private
4323     triggerCacheRefresh : function(){
4324         Roo.dd.DDM.refreshCache(this.groups);
4325     }  
4326 });/*
4327  * Based on:
4328  * Ext JS Library 1.1.1
4329  * Copyright(c) 2006-2007, Ext JS, LLC.
4330  *
4331  * Originally Released Under LGPL - original licence link has changed is not relivant.
4332  *
4333  * Fork - LGPL
4334  * <script type="text/javascript">
4335  */
4336
4337
4338 /**
4339  * @class Roo.data.SortTypes
4340  * @singleton
4341  * Defines the default sorting (casting?) comparison functions used when sorting data.
4342  */
4343 Roo.data.SortTypes = {
4344     /**
4345      * Default sort that does nothing
4346      * @param {Mixed} s The value being converted
4347      * @return {Mixed} The comparison value
4348      */
4349     none : function(s){
4350         return s;
4351     },
4352     
4353     /**
4354      * The regular expression used to strip tags
4355      * @type {RegExp}
4356      * @property
4357      */
4358     stripTagsRE : /<\/?[^>]+>/gi,
4359     
4360     /**
4361      * Strips all HTML tags to sort on text only
4362      * @param {Mixed} s The value being converted
4363      * @return {String} The comparison value
4364      */
4365     asText : function(s){
4366         return String(s).replace(this.stripTagsRE, "");
4367     },
4368     
4369     /**
4370      * Strips all HTML tags to sort on text only - Case insensitive
4371      * @param {Mixed} s The value being converted
4372      * @return {String} The comparison value
4373      */
4374     asUCText : function(s){
4375         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4376     },
4377     
4378     /**
4379      * Case insensitive string
4380      * @param {Mixed} s The value being converted
4381      * @return {String} The comparison value
4382      */
4383     asUCString : function(s) {
4384         return String(s).toUpperCase();
4385     },
4386     
4387     /**
4388      * Date sorting
4389      * @param {Mixed} s The value being converted
4390      * @return {Number} The comparison value
4391      */
4392     asDate : function(s) {
4393         if(!s){
4394             return 0;
4395         }
4396         if(s instanceof Date){
4397             return s.getTime();
4398         }
4399         return Date.parse(String(s));
4400     },
4401     
4402     /**
4403      * Float sorting
4404      * @param {Mixed} s The value being converted
4405      * @return {Float} The comparison value
4406      */
4407     asFloat : function(s) {
4408         var val = parseFloat(String(s).replace(/,/g, ""));
4409         if(isNaN(val)) val = 0;
4410         return val;
4411     },
4412     
4413     /**
4414      * Integer sorting
4415      * @param {Mixed} s The value being converted
4416      * @return {Number} The comparison value
4417      */
4418     asInt : function(s) {
4419         var val = parseInt(String(s).replace(/,/g, ""));
4420         if(isNaN(val)) val = 0;
4421         return val;
4422     }
4423 };/*
4424  * Based on:
4425  * Ext JS Library 1.1.1
4426  * Copyright(c) 2006-2007, Ext JS, LLC.
4427  *
4428  * Originally Released Under LGPL - original licence link has changed is not relivant.
4429  *
4430  * Fork - LGPL
4431  * <script type="text/javascript">
4432  */
4433
4434 /**
4435 * @class Roo.data.Record
4436  * Instances of this class encapsulate both record <em>definition</em> information, and record
4437  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4438  * to access Records cached in an {@link Roo.data.Store} object.<br>
4439  * <p>
4440  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4441  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4442  * objects.<br>
4443  * <p>
4444  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4445  * @constructor
4446  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4447  * {@link #create}. The parameters are the same.
4448  * @param {Array} data An associative Array of data values keyed by the field name.
4449  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4450  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4451  * not specified an integer id is generated.
4452  */
4453 Roo.data.Record = function(data, id){
4454     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4455     this.data = data;
4456 };
4457
4458 /**
4459  * Generate a constructor for a specific record layout.
4460  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4461  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4462  * Each field definition object may contain the following properties: <ul>
4463  * <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,
4464  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4465  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4466  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4467  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4468  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4469  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4470  * this may be omitted.</p></li>
4471  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4472  * <ul><li>auto (Default, implies no conversion)</li>
4473  * <li>string</li>
4474  * <li>int</li>
4475  * <li>float</li>
4476  * <li>boolean</li>
4477  * <li>date</li></ul></p></li>
4478  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4479  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4480  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4481  * by the Reader into an object that will be stored in the Record. It is passed the
4482  * following parameters:<ul>
4483  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4484  * </ul></p></li>
4485  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4486  * </ul>
4487  * <br>usage:<br><pre><code>
4488 var TopicRecord = Roo.data.Record.create(
4489     {name: 'title', mapping: 'topic_title'},
4490     {name: 'author', mapping: 'username'},
4491     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4492     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4493     {name: 'lastPoster', mapping: 'user2'},
4494     {name: 'excerpt', mapping: 'post_text'}
4495 );
4496
4497 var myNewRecord = new TopicRecord({
4498     title: 'Do my job please',
4499     author: 'noobie',
4500     totalPosts: 1,
4501     lastPost: new Date(),
4502     lastPoster: 'Animal',
4503     excerpt: 'No way dude!'
4504 });
4505 myStore.add(myNewRecord);
4506 </code></pre>
4507  * @method create
4508  * @static
4509  */
4510 Roo.data.Record.create = function(o){
4511     var f = function(){
4512         f.superclass.constructor.apply(this, arguments);
4513     };
4514     Roo.extend(f, Roo.data.Record);
4515     var p = f.prototype;
4516     p.fields = new Roo.util.MixedCollection(false, function(field){
4517         return field.name;
4518     });
4519     for(var i = 0, len = o.length; i < len; i++){
4520         p.fields.add(new Roo.data.Field(o[i]));
4521     }
4522     f.getField = function(name){
4523         return p.fields.get(name);  
4524     };
4525     return f;
4526 };
4527
4528 Roo.data.Record.AUTO_ID = 1000;
4529 Roo.data.Record.EDIT = 'edit';
4530 Roo.data.Record.REJECT = 'reject';
4531 Roo.data.Record.COMMIT = 'commit';
4532
4533 Roo.data.Record.prototype = {
4534     /**
4535      * Readonly flag - true if this record has been modified.
4536      * @type Boolean
4537      */
4538     dirty : false,
4539     editing : false,
4540     error: null,
4541     modified: null,
4542
4543     // private
4544     join : function(store){
4545         this.store = store;
4546     },
4547
4548     /**
4549      * Set the named field to the specified value.
4550      * @param {String} name The name of the field to set.
4551      * @param {Object} value The value to set the field to.
4552      */
4553     set : function(name, value){
4554         if(this.data[name] == value){
4555             return;
4556         }
4557         this.dirty = true;
4558         if(!this.modified){
4559             this.modified = {};
4560         }
4561         if(typeof this.modified[name] == 'undefined'){
4562             this.modified[name] = this.data[name];
4563         }
4564         this.data[name] = value;
4565         if(!this.editing){
4566             this.store.afterEdit(this);
4567         }       
4568     },
4569
4570     /**
4571      * Get the value of the named field.
4572      * @param {String} name The name of the field to get the value of.
4573      * @return {Object} The value of the field.
4574      */
4575     get : function(name){
4576         return this.data[name]; 
4577     },
4578
4579     // private
4580     beginEdit : function(){
4581         this.editing = true;
4582         this.modified = {}; 
4583     },
4584
4585     // private
4586     cancelEdit : function(){
4587         this.editing = false;
4588         delete this.modified;
4589     },
4590
4591     // private
4592     endEdit : function(){
4593         this.editing = false;
4594         if(this.dirty && this.store){
4595             this.store.afterEdit(this);
4596         }
4597     },
4598
4599     /**
4600      * Usually called by the {@link Roo.data.Store} which owns the Record.
4601      * Rejects all changes made to the Record since either creation, or the last commit operation.
4602      * Modified fields are reverted to their original values.
4603      * <p>
4604      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4605      * of reject operations.
4606      */
4607     reject : function(){
4608         var m = this.modified;
4609         for(var n in m){
4610             if(typeof m[n] != "function"){
4611                 this.data[n] = m[n];
4612             }
4613         }
4614         this.dirty = false;
4615         delete this.modified;
4616         this.editing = false;
4617         if(this.store){
4618             this.store.afterReject(this);
4619         }
4620     },
4621
4622     /**
4623      * Usually called by the {@link Roo.data.Store} which owns the Record.
4624      * Commits all changes made to the Record since either creation, or the last commit operation.
4625      * <p>
4626      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627      * of commit operations.
4628      */
4629     commit : function(){
4630         this.dirty = false;
4631         delete this.modified;
4632         this.editing = false;
4633         if(this.store){
4634             this.store.afterCommit(this);
4635         }
4636     },
4637
4638     // private
4639     hasError : function(){
4640         return this.error != null;
4641     },
4642
4643     // private
4644     clearError : function(){
4645         this.error = null;
4646     },
4647
4648     /**
4649      * Creates a copy of this record.
4650      * @param {String} id (optional) A new record id if you don't want to use this record's id
4651      * @return {Record}
4652      */
4653     copy : function(newId) {
4654         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4655     }
4656 };/*
4657  * Based on:
4658  * Ext JS Library 1.1.1
4659  * Copyright(c) 2006-2007, Ext JS, LLC.
4660  *
4661  * Originally Released Under LGPL - original licence link has changed is not relivant.
4662  *
4663  * Fork - LGPL
4664  * <script type="text/javascript">
4665  */
4666
4667
4668
4669 /**
4670  * @class Roo.data.Store
4671  * @extends Roo.util.Observable
4672  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4673  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4674  * <p>
4675  * 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
4676  * has no knowledge of the format of the data returned by the Proxy.<br>
4677  * <p>
4678  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4679  * instances from the data object. These records are cached and made available through accessor functions.
4680  * @constructor
4681  * Creates a new Store.
4682  * @param {Object} config A config object containing the objects needed for the Store to access data,
4683  * and read the data into Records.
4684  */
4685 Roo.data.Store = function(config){
4686     this.data = new Roo.util.MixedCollection(false);
4687     this.data.getKey = function(o){
4688         return o.id;
4689     };
4690     this.baseParams = {};
4691     // private
4692     this.paramNames = {
4693         "start" : "start",
4694         "limit" : "limit",
4695         "sort" : "sort",
4696         "dir" : "dir"
4697     };
4698
4699     if(config && config.data){
4700         this.inlineData = config.data;
4701         delete config.data;
4702     }
4703
4704     Roo.apply(this, config);
4705     
4706     if(this.reader){ // reader passed
4707         this.reader = Roo.factory(this.reader, Roo.data);
4708         this.reader.xmodule = this.xmodule || false;
4709         if(!this.recordType){
4710             this.recordType = this.reader.recordType;
4711         }
4712         if(this.reader.onMetaChange){
4713             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4714         }
4715     }
4716
4717     if(this.recordType){
4718         this.fields = this.recordType.prototype.fields;
4719     }
4720     this.modified = [];
4721
4722     this.addEvents({
4723         /**
4724          * @event datachanged
4725          * Fires when the data cache has changed, and a widget which is using this Store
4726          * as a Record cache should refresh its view.
4727          * @param {Store} this
4728          */
4729         datachanged : true,
4730         /**
4731          * @event metachange
4732          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4733          * @param {Store} this
4734          * @param {Object} meta The JSON metadata
4735          */
4736         metachange : true,
4737         /**
4738          * @event add
4739          * Fires when Records have been added to the Store
4740          * @param {Store} this
4741          * @param {Roo.data.Record[]} records The array of Records added
4742          * @param {Number} index The index at which the record(s) were added
4743          */
4744         add : true,
4745         /**
4746          * @event remove
4747          * Fires when a Record has been removed from the Store
4748          * @param {Store} this
4749          * @param {Roo.data.Record} record The Record that was removed
4750          * @param {Number} index The index at which the record was removed
4751          */
4752         remove : true,
4753         /**
4754          * @event update
4755          * Fires when a Record has been updated
4756          * @param {Store} this
4757          * @param {Roo.data.Record} record The Record that was updated
4758          * @param {String} operation The update operation being performed.  Value may be one of:
4759          * <pre><code>
4760  Roo.data.Record.EDIT
4761  Roo.data.Record.REJECT
4762  Roo.data.Record.COMMIT
4763          * </code></pre>
4764          */
4765         update : true,
4766         /**
4767          * @event clear
4768          * Fires when the data cache has been cleared.
4769          * @param {Store} this
4770          */
4771         clear : true,
4772         /**
4773          * @event beforeload
4774          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4775          * the load action will be canceled.
4776          * @param {Store} this
4777          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4778          */
4779         beforeload : true,
4780         /**
4781          * @event load
4782          * Fires after a new set of Records has been loaded.
4783          * @param {Store} this
4784          * @param {Roo.data.Record[]} records The Records that were loaded
4785          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4786          */
4787         load : true,
4788         /**
4789          * @event loadexception
4790          * Fires if an exception occurs in the Proxy during loading.
4791          * Called with the signature of the Proxy's "loadexception" event.
4792          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4793          * 
4794          * @param {Proxy} 
4795          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4796          * @param {Object} load options 
4797          * @param {Object} jsonData from your request (normally this contains the Exception)
4798          */
4799         loadexception : true
4800     });
4801     
4802     if(this.proxy){
4803         this.proxy = Roo.factory(this.proxy, Roo.data);
4804         this.proxy.xmodule = this.xmodule || false;
4805         this.relayEvents(this.proxy,  ["loadexception"]);
4806     }
4807     this.sortToggle = {};
4808
4809     Roo.data.Store.superclass.constructor.call(this);
4810
4811     if(this.inlineData){
4812         this.loadData(this.inlineData);
4813         delete this.inlineData;
4814     }
4815 };
4816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4817      /**
4818     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4819     * without a remote query - used by combo/forms at present.
4820     */
4821     
4822     /**
4823     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4824     */
4825     /**
4826     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4827     */
4828     /**
4829     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4830     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4831     */
4832     /**
4833     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4834     * on any HTTP request
4835     */
4836     /**
4837     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4838     */
4839     /**
4840     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4841     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4842     */
4843     remoteSort : false,
4844
4845     /**
4846     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4847      * loaded or when a record is removed. (defaults to false).
4848     */
4849     pruneModifiedRecords : false,
4850
4851     // private
4852     lastOptions : null,
4853
4854     /**
4855      * Add Records to the Store and fires the add event.
4856      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4857      */
4858     add : function(records){
4859         records = [].concat(records);
4860         for(var i = 0, len = records.length; i < len; i++){
4861             records[i].join(this);
4862         }
4863         var index = this.data.length;
4864         this.data.addAll(records);
4865         this.fireEvent("add", this, records, index);
4866     },
4867
4868     /**
4869      * Remove a Record from the Store and fires the remove event.
4870      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4871      */
4872     remove : function(record){
4873         var index = this.data.indexOf(record);
4874         this.data.removeAt(index);
4875         if(this.pruneModifiedRecords){
4876             this.modified.remove(record);
4877         }
4878         this.fireEvent("remove", this, record, index);
4879     },
4880
4881     /**
4882      * Remove all Records from the Store and fires the clear event.
4883      */
4884     removeAll : function(){
4885         this.data.clear();
4886         if(this.pruneModifiedRecords){
4887             this.modified = [];
4888         }
4889         this.fireEvent("clear", this);
4890     },
4891
4892     /**
4893      * Inserts Records to the Store at the given index and fires the add event.
4894      * @param {Number} index The start index at which to insert the passed Records.
4895      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4896      */
4897     insert : function(index, records){
4898         records = [].concat(records);
4899         for(var i = 0, len = records.length; i < len; i++){
4900             this.data.insert(index, records[i]);
4901             records[i].join(this);
4902         }
4903         this.fireEvent("add", this, records, index);
4904     },
4905
4906     /**
4907      * Get the index within the cache of the passed Record.
4908      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4909      * @return {Number} The index of the passed Record. Returns -1 if not found.
4910      */
4911     indexOf : function(record){
4912         return this.data.indexOf(record);
4913     },
4914
4915     /**
4916      * Get the index within the cache of the Record with the passed id.
4917      * @param {String} id The id of the Record to find.
4918      * @return {Number} The index of the Record. Returns -1 if not found.
4919      */
4920     indexOfId : function(id){
4921         return this.data.indexOfKey(id);
4922     },
4923
4924     /**
4925      * Get the Record with the specified id.
4926      * @param {String} id The id of the Record to find.
4927      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4928      */
4929     getById : function(id){
4930         return this.data.key(id);
4931     },
4932
4933     /**
4934      * Get the Record at the specified index.
4935      * @param {Number} index The index of the Record to find.
4936      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4937      */
4938     getAt : function(index){
4939         return this.data.itemAt(index);
4940     },
4941
4942     /**
4943      * Returns a range of Records between specified indices.
4944      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4945      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4946      * @return {Roo.data.Record[]} An array of Records
4947      */
4948     getRange : function(start, end){
4949         return this.data.getRange(start, end);
4950     },
4951
4952     // private
4953     storeOptions : function(o){
4954         o = Roo.apply({}, o);
4955         delete o.callback;
4956         delete o.scope;
4957         this.lastOptions = o;
4958     },
4959
4960     /**
4961      * Loads the Record cache from the configured Proxy using the configured Reader.
4962      * <p>
4963      * If using remote paging, then the first load call must specify the <em>start</em>
4964      * and <em>limit</em> properties in the options.params property to establish the initial
4965      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4966      * <p>
4967      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4968      * and this call will return before the new data has been loaded. Perform any post-processing
4969      * in a callback function, or in a "load" event handler.</strong>
4970      * <p>
4971      * @param {Object} options An object containing properties which control loading options:<ul>
4972      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4973      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4974      * passed the following arguments:<ul>
4975      * <li>r : Roo.data.Record[]</li>
4976      * <li>options: Options object from the load call</li>
4977      * <li>success: Boolean success indicator</li></ul></li>
4978      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4979      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4980      * </ul>
4981      */
4982     load : function(options){
4983         options = options || {};
4984         if(this.fireEvent("beforeload", this, options) !== false){
4985             this.storeOptions(options);
4986             var p = Roo.apply(options.params || {}, this.baseParams);
4987             // if meta was not loaded from remote source.. try requesting it.
4988             if (!this.reader.metaFromRemote) {
4989                 p._requestMeta = 1;
4990             }
4991             if(this.sortInfo && this.remoteSort){
4992                 var pn = this.paramNames;
4993                 p[pn["sort"]] = this.sortInfo.field;
4994                 p[pn["dir"]] = this.sortInfo.direction;
4995             }
4996             this.proxy.load(p, this.reader, this.loadRecords, this, options);
4997         }
4998     },
4999
5000     /**
5001      * Reloads the Record cache from the configured Proxy using the configured Reader and
5002      * the options from the last load operation performed.
5003      * @param {Object} options (optional) An object containing properties which may override the options
5004      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5005      * the most recently used options are reused).
5006      */
5007     reload : function(options){
5008         this.load(Roo.applyIf(options||{}, this.lastOptions));
5009     },
5010
5011     // private
5012     // Called as a callback by the Reader during a load operation.
5013     loadRecords : function(o, options, success){
5014         if(!o || success === false){
5015             if(success !== false){
5016                 this.fireEvent("load", this, [], options);
5017             }
5018             if(options.callback){
5019                 options.callback.call(options.scope || this, [], options, false);
5020             }
5021             return;
5022         }
5023         // if data returned failure - throw an exception.
5024         if (o.success === false) {
5025             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5026             return;
5027         }
5028         var r = o.records, t = o.totalRecords || r.length;
5029         if(!options || options.add !== true){
5030             if(this.pruneModifiedRecords){
5031                 this.modified = [];
5032             }
5033             for(var i = 0, len = r.length; i < len; i++){
5034                 r[i].join(this);
5035             }
5036             if(this.snapshot){
5037                 this.data = this.snapshot;
5038                 delete this.snapshot;
5039             }
5040             this.data.clear();
5041             this.data.addAll(r);
5042             this.totalLength = t;
5043             this.applySort();
5044             this.fireEvent("datachanged", this);
5045         }else{
5046             this.totalLength = Math.max(t, this.data.length+r.length);
5047             this.add(r);
5048         }
5049         this.fireEvent("load", this, r, options);
5050         if(options.callback){
5051             options.callback.call(options.scope || this, r, options, true);
5052         }
5053     },
5054
5055     /**
5056      * Loads data from a passed data block. A Reader which understands the format of the data
5057      * must have been configured in the constructor.
5058      * @param {Object} data The data block from which to read the Records.  The format of the data expected
5059      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5060      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5061      */
5062     loadData : function(o, append){
5063         var r = this.reader.readRecords(o);
5064         this.loadRecords(r, {add: append}, true);
5065     },
5066
5067     /**
5068      * Gets the number of cached records.
5069      * <p>
5070      * <em>If using paging, this may not be the total size of the dataset. If the data object
5071      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5072      * the data set size</em>
5073      */
5074     getCount : function(){
5075         return this.data.length || 0;
5076     },
5077
5078     /**
5079      * Gets the total number of records in the dataset as returned by the server.
5080      * <p>
5081      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5082      * the dataset size</em>
5083      */
5084     getTotalCount : function(){
5085         return this.totalLength || 0;
5086     },
5087
5088     /**
5089      * Returns the sort state of the Store as an object with two properties:
5090      * <pre><code>
5091  field {String} The name of the field by which the Records are sorted
5092  direction {String} The sort order, "ASC" or "DESC"
5093      * </code></pre>
5094      */
5095     getSortState : function(){
5096         return this.sortInfo;
5097     },
5098
5099     // private
5100     applySort : function(){
5101         if(this.sortInfo && !this.remoteSort){
5102             var s = this.sortInfo, f = s.field;
5103             var st = this.fields.get(f).sortType;
5104             var fn = function(r1, r2){
5105                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5106                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5107             };
5108             this.data.sort(s.direction, fn);
5109             if(this.snapshot && this.snapshot != this.data){
5110                 this.snapshot.sort(s.direction, fn);
5111             }
5112         }
5113     },
5114
5115     /**
5116      * Sets the default sort column and order to be used by the next load operation.
5117      * @param {String} fieldName The name of the field to sort by.
5118      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5119      */
5120     setDefaultSort : function(field, dir){
5121         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5122     },
5123
5124     /**
5125      * Sort the Records.
5126      * If remote sorting is used, the sort is performed on the server, and the cache is
5127      * reloaded. If local sorting is used, the cache is sorted internally.
5128      * @param {String} fieldName The name of the field to sort by.
5129      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5130      */
5131     sort : function(fieldName, dir){
5132         var f = this.fields.get(fieldName);
5133         if(!dir){
5134             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5135                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5136             }else{
5137                 dir = f.sortDir;
5138             }
5139         }
5140         this.sortToggle[f.name] = dir;
5141         this.sortInfo = {field: f.name, direction: dir};
5142         if(!this.remoteSort){
5143             this.applySort();
5144             this.fireEvent("datachanged", this);
5145         }else{
5146             this.load(this.lastOptions);
5147         }
5148     },
5149
5150     /**
5151      * Calls the specified function for each of the Records in the cache.
5152      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5153      * Returning <em>false</em> aborts and exits the iteration.
5154      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5155      */
5156     each : function(fn, scope){
5157         this.data.each(fn, scope);
5158     },
5159
5160     /**
5161      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5162      * (e.g., during paging).
5163      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5164      */
5165     getModifiedRecords : function(){
5166         return this.modified;
5167     },
5168
5169     // private
5170     createFilterFn : function(property, value, anyMatch){
5171         if(!value.exec){ // not a regex
5172             value = String(value);
5173             if(value.length == 0){
5174                 return false;
5175             }
5176             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5177         }
5178         return function(r){
5179             return value.test(r.data[property]);
5180         };
5181     },
5182
5183     /**
5184      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5185      * @param {String} property A field on your records
5186      * @param {Number} start The record index to start at (defaults to 0)
5187      * @param {Number} end The last record index to include (defaults to length - 1)
5188      * @return {Number} The sum
5189      */
5190     sum : function(property, start, end){
5191         var rs = this.data.items, v = 0;
5192         start = start || 0;
5193         end = (end || end === 0) ? end : rs.length-1;
5194
5195         for(var i = start; i <= end; i++){
5196             v += (rs[i].data[property] || 0);
5197         }
5198         return v;
5199     },
5200
5201     /**
5202      * Filter the records by a specified property.
5203      * @param {String} field A field on your records
5204      * @param {String/RegExp} value Either a string that the field
5205      * should start with or a RegExp to test against the field
5206      * @param {Boolean} anyMatch True to match any part not just the beginning
5207      */
5208     filter : function(property, value, anyMatch){
5209         var fn = this.createFilterFn(property, value, anyMatch);
5210         return fn ? this.filterBy(fn) : this.clearFilter();
5211     },
5212
5213     /**
5214      * Filter by a function. The specified function will be called with each
5215      * record in this data source. If the function returns true the record is included,
5216      * otherwise it is filtered.
5217      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5218      * @param {Object} scope (optional) The scope of the function (defaults to this)
5219      */
5220     filterBy : function(fn, scope){
5221         this.snapshot = this.snapshot || this.data;
5222         this.data = this.queryBy(fn, scope||this);
5223         this.fireEvent("datachanged", this);
5224     },
5225
5226     /**
5227      * Query the records by a specified property.
5228      * @param {String} field A field on your records
5229      * @param {String/RegExp} value Either a string that the field
5230      * should start with or a RegExp to test against the field
5231      * @param {Boolean} anyMatch True to match any part not just the beginning
5232      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5233      */
5234     query : function(property, value, anyMatch){
5235         var fn = this.createFilterFn(property, value, anyMatch);
5236         return fn ? this.queryBy(fn) : this.data.clone();
5237     },
5238
5239     /**
5240      * Query by a function. The specified function will be called with each
5241      * record in this data source. If the function returns true the record is included
5242      * in the results.
5243      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5244      * @param {Object} scope (optional) The scope of the function (defaults to this)
5245       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5246      **/
5247     queryBy : function(fn, scope){
5248         var data = this.snapshot || this.data;
5249         return data.filterBy(fn, scope||this);
5250     },
5251
5252     /**
5253      * Collects unique values for a particular dataIndex from this store.
5254      * @param {String} dataIndex The property to collect
5255      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5256      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5257      * @return {Array} An array of the unique values
5258      **/
5259     collect : function(dataIndex, allowNull, bypassFilter){
5260         var d = (bypassFilter === true && this.snapshot) ?
5261                 this.snapshot.items : this.data.items;
5262         var v, sv, r = [], l = {};
5263         for(var i = 0, len = d.length; i < len; i++){
5264             v = d[i].data[dataIndex];
5265             sv = String(v);
5266             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5267                 l[sv] = true;
5268                 r[r.length] = v;
5269             }
5270         }
5271         return r;
5272     },
5273
5274     /**
5275      * Revert to a view of the Record cache with no filtering applied.
5276      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5277      */
5278     clearFilter : function(suppressEvent){
5279         if(this.snapshot && this.snapshot != this.data){
5280             this.data = this.snapshot;
5281             delete this.snapshot;
5282             if(suppressEvent !== true){
5283                 this.fireEvent("datachanged", this);
5284             }
5285         }
5286     },
5287
5288     // private
5289     afterEdit : function(record){
5290         if(this.modified.indexOf(record) == -1){
5291             this.modified.push(record);
5292         }
5293         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5294     },
5295
5296     // private
5297     afterReject : function(record){
5298         this.modified.remove(record);
5299         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5300     },
5301
5302     // private
5303     afterCommit : function(record){
5304         this.modified.remove(record);
5305         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5306     },
5307
5308     /**
5309      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5310      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5311      */
5312     commitChanges : function(){
5313         var m = this.modified.slice(0);
5314         this.modified = [];
5315         for(var i = 0, len = m.length; i < len; i++){
5316             m[i].commit();
5317         }
5318     },
5319
5320     /**
5321      * Cancel outstanding changes on all changed records.
5322      */
5323     rejectChanges : function(){
5324         var m = this.modified.slice(0);
5325         this.modified = [];
5326         for(var i = 0, len = m.length; i < len; i++){
5327             m[i].reject();
5328         }
5329     },
5330
5331     onMetaChange : function(meta, rtype, o){
5332         this.recordType = rtype;
5333         this.fields = rtype.prototype.fields;
5334         delete this.snapshot;
5335         this.sortInfo = meta.sortInfo || this.sortInfo;
5336         this.modified = [];
5337         this.fireEvent('metachange', this, this.reader.meta);
5338     }
5339 });/*
5340  * Based on:
5341  * Ext JS Library 1.1.1
5342  * Copyright(c) 2006-2007, Ext JS, LLC.
5343  *
5344  * Originally Released Under LGPL - original licence link has changed is not relivant.
5345  *
5346  * Fork - LGPL
5347  * <script type="text/javascript">
5348  */
5349
5350 /**
5351  * @class Roo.data.SimpleStore
5352  * @extends Roo.data.Store
5353  * Small helper class to make creating Stores from Array data easier.
5354  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5355  * @cfg {Array} fields An array of field definition objects, or field name strings.
5356  * @cfg {Array} data The multi-dimensional array of data
5357  * @constructor
5358  * @param {Object} config
5359  */
5360 Roo.data.SimpleStore = function(config){
5361     Roo.data.SimpleStore.superclass.constructor.call(this, {
5362         isLocal : true,
5363         reader: new Roo.data.ArrayReader({
5364                 id: config.id
5365             },
5366             Roo.data.Record.create(config.fields)
5367         ),
5368         proxy : new Roo.data.MemoryProxy(config.data)
5369     });
5370     this.load();
5371 };
5372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5373  * Based on:
5374  * Ext JS Library 1.1.1
5375  * Copyright(c) 2006-2007, Ext JS, LLC.
5376  *
5377  * Originally Released Under LGPL - original licence link has changed is not relivant.
5378  *
5379  * Fork - LGPL
5380  * <script type="text/javascript">
5381  */
5382
5383 /**
5384 /**
5385  * @extends Roo.data.Store
5386  * @class Roo.data.JsonStore
5387  * Small helper class to make creating Stores for JSON data easier. <br/>
5388 <pre><code>
5389 var store = new Roo.data.JsonStore({
5390     url: 'get-images.php',
5391     root: 'images',
5392     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5393 });
5394 </code></pre>
5395  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5396  * JsonReader and HttpProxy (unless inline data is provided).</b>
5397  * @cfg {Array} fields An array of field definition objects, or field name strings.
5398  * @constructor
5399  * @param {Object} config
5400  */
5401 Roo.data.JsonStore = function(c){
5402     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5403         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5404         reader: new Roo.data.JsonReader(c, c.fields)
5405     }));
5406 };
5407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5408  * Based on:
5409  * Ext JS Library 1.1.1
5410  * Copyright(c) 2006-2007, Ext JS, LLC.
5411  *
5412  * Originally Released Under LGPL - original licence link has changed is not relivant.
5413  *
5414  * Fork - LGPL
5415  * <script type="text/javascript">
5416  */
5417
5418  
5419 Roo.data.Field = function(config){
5420     if(typeof config == "string"){
5421         config = {name: config};
5422     }
5423     Roo.apply(this, config);
5424     
5425     if(!this.type){
5426         this.type = "auto";
5427     }
5428     
5429     var st = Roo.data.SortTypes;
5430     // named sortTypes are supported, here we look them up
5431     if(typeof this.sortType == "string"){
5432         this.sortType = st[this.sortType];
5433     }
5434     
5435     // set default sortType for strings and dates
5436     if(!this.sortType){
5437         switch(this.type){
5438             case "string":
5439                 this.sortType = st.asUCString;
5440                 break;
5441             case "date":
5442                 this.sortType = st.asDate;
5443                 break;
5444             default:
5445                 this.sortType = st.none;
5446         }
5447     }
5448
5449     // define once
5450     var stripRe = /[\$,%]/g;
5451
5452     // prebuilt conversion function for this field, instead of
5453     // switching every time we're reading a value
5454     if(!this.convert){
5455         var cv, dateFormat = this.dateFormat;
5456         switch(this.type){
5457             case "":
5458             case "auto":
5459             case undefined:
5460                 cv = function(v){ return v; };
5461                 break;
5462             case "string":
5463                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5464                 break;
5465             case "int":
5466                 cv = function(v){
5467                     return v !== undefined && v !== null && v !== '' ?
5468                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5469                     };
5470                 break;
5471             case "float":
5472                 cv = function(v){
5473                     return v !== undefined && v !== null && v !== '' ?
5474                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5475                     };
5476                 break;
5477             case "bool":
5478             case "boolean":
5479                 cv = function(v){ return v === true || v === "true" || v == 1; };
5480                 break;
5481             case "date":
5482                 cv = function(v){
5483                     if(!v){
5484                         return '';
5485                     }
5486                     if(v instanceof Date){
5487                         return v;
5488                     }
5489                     if(dateFormat){
5490                         if(dateFormat == "timestamp"){
5491                             return new Date(v*1000);
5492                         }
5493                         return Date.parseDate(v, dateFormat);
5494                     }
5495                     var parsed = Date.parse(v);
5496                     return parsed ? new Date(parsed) : null;
5497                 };
5498              break;
5499             
5500         }
5501         this.convert = cv;
5502     }
5503 };
5504
5505 Roo.data.Field.prototype = {
5506     dateFormat: null,
5507     defaultValue: "",
5508     mapping: null,
5509     sortType : null,
5510     sortDir : "ASC"
5511 };/*
5512  * Based on:
5513  * Ext JS Library 1.1.1
5514  * Copyright(c) 2006-2007, Ext JS, LLC.
5515  *
5516  * Originally Released Under LGPL - original licence link has changed is not relivant.
5517  *
5518  * Fork - LGPL
5519  * <script type="text/javascript">
5520  */
5521  
5522 // Base class for reading structured data from a data source.  This class is intended to be
5523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5524
5525 /**
5526  * @class Roo.data.DataReader
5527  * Base class for reading structured data from a data source.  This class is intended to be
5528  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5529  */
5530
5531 Roo.data.DataReader = function(meta, recordType){
5532     
5533     this.meta = meta;
5534     
5535     this.recordType = recordType instanceof Array ? 
5536         Roo.data.Record.create(recordType) : recordType;
5537 };
5538
5539 Roo.data.DataReader.prototype = {
5540      /**
5541      * Create an empty record
5542      * @param {Object} data (optional) - overlay some values
5543      * @return {Roo.data.Record} record created.
5544      */
5545     newRow :  function(d) {
5546         var da =  {};
5547         this.recordType.prototype.fields.each(function(c) {
5548             switch( c.type) {
5549                 case 'int' : da[c.name] = 0; break;
5550                 case 'date' : da[c.name] = new Date(); break;
5551                 case 'float' : da[c.name] = 0.0; break;
5552                 case 'boolean' : da[c.name] = false; break;
5553                 default : da[c.name] = ""; break;
5554             }
5555             
5556         });
5557         return new this.recordType(Roo.apply(da, d));
5558     }
5559     
5560 };/*
5561  * Based on:
5562  * Ext JS Library 1.1.1
5563  * Copyright(c) 2006-2007, Ext JS, LLC.
5564  *
5565  * Originally Released Under LGPL - original licence link has changed is not relivant.
5566  *
5567  * Fork - LGPL
5568  * <script type="text/javascript">
5569  */
5570
5571 /**
5572  * @class Roo.data.DataProxy
5573  * @extends Roo.data.Observable
5574  * This class is an abstract base class for implementations which provide retrieval of
5575  * unformatted data objects.<br>
5576  * <p>
5577  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5578  * (of the appropriate type which knows how to parse the data object) to provide a block of
5579  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5580  * <p>
5581  * Custom implementations must implement the load method as described in
5582  * {@link Roo.data.HttpProxy#load}.
5583  */
5584 Roo.data.DataProxy = function(){
5585     this.addEvents({
5586         /**
5587          * @event beforeload
5588          * Fires before a network request is made to retrieve a data object.
5589          * @param {Object} This DataProxy object.
5590          * @param {Object} params The params parameter to the load function.
5591          */
5592         beforeload : true,
5593         /**
5594          * @event load
5595          * Fires before the load method's callback is called.
5596          * @param {Object} This DataProxy object.
5597          * @param {Object} o The data object.
5598          * @param {Object} arg The callback argument object passed to the load function.
5599          */
5600         load : true,
5601         /**
5602          * @event loadexception
5603          * Fires if an Exception occurs during data retrieval.
5604          * @param {Object} This DataProxy object.
5605          * @param {Object} o The data object.
5606          * @param {Object} arg The callback argument object passed to the load function.
5607          * @param {Object} e The Exception.
5608          */
5609         loadexception : true
5610     });
5611     Roo.data.DataProxy.superclass.constructor.call(this);
5612 };
5613
5614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5615
5616     /**
5617      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5618      */
5619 /*
5620  * Based on:
5621  * Ext JS Library 1.1.1
5622  * Copyright(c) 2006-2007, Ext JS, LLC.
5623  *
5624  * Originally Released Under LGPL - original licence link has changed is not relivant.
5625  *
5626  * Fork - LGPL
5627  * <script type="text/javascript">
5628  */
5629 /**
5630  * @class Roo.data.MemoryProxy
5631  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5632  * to the Reader when its load method is called.
5633  * @constructor
5634  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5635  */
5636 Roo.data.MemoryProxy = function(data){
5637     if (data.data) {
5638         data = data.data;
5639     }
5640     Roo.data.MemoryProxy.superclass.constructor.call(this);
5641     this.data = data;
5642 };
5643
5644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5645     /**
5646      * Load data from the requested source (in this case an in-memory
5647      * data object passed to the constructor), read the data object into
5648      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5649      * process that block using the passed callback.
5650      * @param {Object} params This parameter is not used by the MemoryProxy class.
5651      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652      * object into a block of Roo.data.Records.
5653      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5654      * The function must be passed <ul>
5655      * <li>The Record block object</li>
5656      * <li>The "arg" argument from the load function</li>
5657      * <li>A boolean success indicator</li>
5658      * </ul>
5659      * @param {Object} scope The scope in which to call the callback
5660      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5661      */
5662     load : function(params, reader, callback, scope, arg){
5663         params = params || {};
5664         var result;
5665         try {
5666             result = reader.readRecords(this.data);
5667         }catch(e){
5668             this.fireEvent("loadexception", this, arg, null, e);
5669             callback.call(scope, null, arg, false);
5670             return;
5671         }
5672         callback.call(scope, result, arg, true);
5673     },
5674     
5675     // private
5676     update : function(params, records){
5677         
5678     }
5679 });/*
5680  * Based on:
5681  * Ext JS Library 1.1.1
5682  * Copyright(c) 2006-2007, Ext JS, LLC.
5683  *
5684  * Originally Released Under LGPL - original licence link has changed is not relivant.
5685  *
5686  * Fork - LGPL
5687  * <script type="text/javascript">
5688  */
5689 /**
5690  * @class Roo.data.HttpProxy
5691  * @extends Roo.data.DataProxy
5692  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5693  * configured to reference a certain URL.<br><br>
5694  * <p>
5695  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5696  * from which the running page was served.<br><br>
5697  * <p>
5698  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5699  * <p>
5700  * Be aware that to enable the browser to parse an XML document, the server must set
5701  * the Content-Type header in the HTTP response to "text/xml".
5702  * @constructor
5703  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5704  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5705  * will be used to make the request.
5706  */
5707 Roo.data.HttpProxy = function(conn){
5708     Roo.data.HttpProxy.superclass.constructor.call(this);
5709     // is conn a conn config or a real conn?
5710     this.conn = conn;
5711     this.useAjax = !conn || !conn.events;
5712   
5713 };
5714
5715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5716     // thse are take from connection...
5717     
5718     /**
5719      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5720      */
5721     /**
5722      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5723      * extra parameters to each request made by this object. (defaults to undefined)
5724      */
5725     /**
5726      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5727      *  to each request made by this object. (defaults to undefined)
5728      */
5729     /**
5730      * @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)
5731      */
5732     /**
5733      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5734      */
5735      /**
5736      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5737      * @type Boolean
5738      */
5739   
5740
5741     /**
5742      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5743      * @type Boolean
5744      */
5745     /**
5746      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5747      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5748      * a finer-grained basis than the DataProxy events.
5749      */
5750     getConnection : function(){
5751         return this.useAjax ? Roo.Ajax : this.conn;
5752     },
5753
5754     /**
5755      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5756      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5757      * process that block using the passed callback.
5758      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5759      * for the request to the remote server.
5760      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5761      * object into a block of Roo.data.Records.
5762      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5763      * The function must be passed <ul>
5764      * <li>The Record block object</li>
5765      * <li>The "arg" argument from the load function</li>
5766      * <li>A boolean success indicator</li>
5767      * </ul>
5768      * @param {Object} scope The scope in which to call the callback
5769      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5770      */
5771     load : function(params, reader, callback, scope, arg){
5772         if(this.fireEvent("beforeload", this, params) !== false){
5773             var  o = {
5774                 params : params || {},
5775                 request: {
5776                     callback : callback,
5777                     scope : scope,
5778                     arg : arg
5779                 },
5780                 reader: reader,
5781                 callback : this.loadResponse,
5782                 scope: this
5783             };
5784             if(this.useAjax){
5785                 Roo.applyIf(o, this.conn);
5786                 if(this.activeRequest){
5787                     Roo.Ajax.abort(this.activeRequest);
5788                 }
5789                 this.activeRequest = Roo.Ajax.request(o);
5790             }else{
5791                 this.conn.request(o);
5792             }
5793         }else{
5794             callback.call(scope||this, null, arg, false);
5795         }
5796     },
5797
5798     // private
5799     loadResponse : function(o, success, response){
5800         delete this.activeRequest;
5801         if(!success){
5802             this.fireEvent("loadexception", this, o, response);
5803             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5804             return;
5805         }
5806         var result;
5807         try {
5808             result = o.reader.read(response);
5809         }catch(e){
5810             this.fireEvent("loadexception", this, o, response, e);
5811             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5812             return;
5813         }
5814         
5815         this.fireEvent("load", this, o, o.request.arg);
5816         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5817     },
5818
5819     // private
5820     update : function(dataSet){
5821
5822     },
5823
5824     // private
5825     updateResponse : function(dataSet){
5826
5827     }
5828 });/*
5829  * Based on:
5830  * Ext JS Library 1.1.1
5831  * Copyright(c) 2006-2007, Ext JS, LLC.
5832  *
5833  * Originally Released Under LGPL - original licence link has changed is not relivant.
5834  *
5835  * Fork - LGPL
5836  * <script type="text/javascript">
5837  */
5838
5839 /**
5840  * @class Roo.data.ScriptTagProxy
5841  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5842  * other than the originating domain of the running page.<br><br>
5843  * <p>
5844  * <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
5845  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5846  * <p>
5847  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5848  * source code that is used as the source inside a &lt;script> tag.<br><br>
5849  * <p>
5850  * In order for the browser to process the returned data, the server must wrap the data object
5851  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5852  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5853  * depending on whether the callback name was passed:
5854  * <p>
5855  * <pre><code>
5856 boolean scriptTag = false;
5857 String cb = request.getParameter("callback");
5858 if (cb != null) {
5859     scriptTag = true;
5860     response.setContentType("text/javascript");
5861 } else {
5862     response.setContentType("application/x-json");
5863 }
5864 Writer out = response.getWriter();
5865 if (scriptTag) {
5866     out.write(cb + "(");
5867 }
5868 out.print(dataBlock.toJsonString());
5869 if (scriptTag) {
5870     out.write(");");
5871 }
5872 </pre></code>
5873  *
5874  * @constructor
5875  * @param {Object} config A configuration object.
5876  */
5877 Roo.data.ScriptTagProxy = function(config){
5878     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5879     Roo.apply(this, config);
5880     this.head = document.getElementsByTagName("head")[0];
5881 };
5882
5883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5884
5885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5886     /**
5887      * @cfg {String} url The URL from which to request the data object.
5888      */
5889     /**
5890      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5891      */
5892     timeout : 30000,
5893     /**
5894      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5895      * the server the name of the callback function set up by the load call to process the returned data object.
5896      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5897      * javascript output which calls this named function passing the data object as its only parameter.
5898      */
5899     callbackParam : "callback",
5900     /**
5901      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5902      * name to the request.
5903      */
5904     nocache : true,
5905
5906     /**
5907      * Load data from the configured URL, read the data object into
5908      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5909      * process that block using the passed callback.
5910      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5911      * for the request to the remote server.
5912      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5913      * object into a block of Roo.data.Records.
5914      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5915      * The function must be passed <ul>
5916      * <li>The Record block object</li>
5917      * <li>The "arg" argument from the load function</li>
5918      * <li>A boolean success indicator</li>
5919      * </ul>
5920      * @param {Object} scope The scope in which to call the callback
5921      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5922      */
5923     load : function(params, reader, callback, scope, arg){
5924         if(this.fireEvent("beforeload", this, params) !== false){
5925
5926             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5927
5928             var url = this.url;
5929             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5930             if(this.nocache){
5931                 url += "&_dc=" + (new Date().getTime());
5932             }
5933             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5934             var trans = {
5935                 id : transId,
5936                 cb : "stcCallback"+transId,
5937                 scriptId : "stcScript"+transId,
5938                 params : params,
5939                 arg : arg,
5940                 url : url,
5941                 callback : callback,
5942                 scope : scope,
5943                 reader : reader
5944             };
5945             var conn = this;
5946
5947             window[trans.cb] = function(o){
5948                 conn.handleResponse(o, trans);
5949             };
5950
5951             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5952
5953             if(this.autoAbort !== false){
5954                 this.abort();
5955             }
5956
5957             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5958
5959             var script = document.createElement("script");
5960             script.setAttribute("src", url);
5961             script.setAttribute("type", "text/javascript");
5962             script.setAttribute("id", trans.scriptId);
5963             this.head.appendChild(script);
5964
5965             this.trans = trans;
5966         }else{
5967             callback.call(scope||this, null, arg, false);
5968         }
5969     },
5970
5971     // private
5972     isLoading : function(){
5973         return this.trans ? true : false;
5974     },
5975
5976     /**
5977      * Abort the current server request.
5978      */
5979     abort : function(){
5980         if(this.isLoading()){
5981             this.destroyTrans(this.trans);
5982         }
5983     },
5984
5985     // private
5986     destroyTrans : function(trans, isLoaded){
5987         this.head.removeChild(document.getElementById(trans.scriptId));
5988         clearTimeout(trans.timeoutId);
5989         if(isLoaded){
5990             window[trans.cb] = undefined;
5991             try{
5992                 delete window[trans.cb];
5993             }catch(e){}
5994         }else{
5995             // if hasn't been loaded, wait for load to remove it to prevent script error
5996             window[trans.cb] = function(){
5997                 window[trans.cb] = undefined;
5998                 try{
5999                     delete window[trans.cb];
6000                 }catch(e){}
6001             };
6002         }
6003     },
6004
6005     // private
6006     handleResponse : function(o, trans){
6007         this.trans = false;
6008         this.destroyTrans(trans, true);
6009         var result;
6010         try {
6011             result = trans.reader.readRecords(o);
6012         }catch(e){
6013             this.fireEvent("loadexception", this, o, trans.arg, e);
6014             trans.callback.call(trans.scope||window, null, trans.arg, false);
6015             return;
6016         }
6017         this.fireEvent("load", this, o, trans.arg);
6018         trans.callback.call(trans.scope||window, result, trans.arg, true);
6019     },
6020
6021     // private
6022     handleFailure : function(trans){
6023         this.trans = false;
6024         this.destroyTrans(trans, false);
6025         this.fireEvent("loadexception", this, null, trans.arg);
6026         trans.callback.call(trans.scope||window, null, trans.arg, false);
6027     }
6028 });/*
6029  * Based on:
6030  * Ext JS Library 1.1.1
6031  * Copyright(c) 2006-2007, Ext JS, LLC.
6032  *
6033  * Originally Released Under LGPL - original licence link has changed is not relivant.
6034  *
6035  * Fork - LGPL
6036  * <script type="text/javascript">
6037  */
6038
6039 /**
6040  * @class Roo.data.JsonReader
6041  * @extends Roo.data.DataReader
6042  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6043  * based on mappings in a provided Roo.data.Record constructor.
6044  * 
6045  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6046  * in the reply previously. 
6047  * 
6048  * <p>
6049  * Example code:
6050  * <pre><code>
6051 var RecordDef = Roo.data.Record.create([
6052     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6053     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6054 ]);
6055 var myReader = new Roo.data.JsonReader({
6056     totalProperty: "results",    // The property which contains the total dataset size (optional)
6057     root: "rows",                // The property which contains an Array of row objects
6058     id: "id"                     // The property within each row object that provides an ID for the record (optional)
6059 }, RecordDef);
6060 </code></pre>
6061  * <p>
6062  * This would consume a JSON file like this:
6063  * <pre><code>
6064 { 'results': 2, 'rows': [
6065     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6066     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6067 }
6068 </code></pre>
6069  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6070  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6071  * paged from the remote server.
6072  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6073  * @cfg {String} root name of the property which contains the Array of row objects.
6074  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6075  * @constructor
6076  * Create a new JsonReader
6077  * @param {Object} meta Metadata configuration options
6078  * @param {Object} recordType Either an Array of field definition objects,
6079  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6080  */
6081 Roo.data.JsonReader = function(meta, recordType){
6082     
6083     meta = meta || {};
6084     // set some defaults:
6085     Roo.applyIf(meta, {
6086         totalProperty: 'total',
6087         successProperty : 'success',
6088         root : 'data',
6089         id : 'id'
6090     });
6091     
6092     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6093 };
6094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6095     
6096     /**
6097      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
6098      * Used by Store query builder to append _requestMeta to params.
6099      * 
6100      */
6101     metaFromRemote : false,
6102     /**
6103      * This method is only used by a DataProxy which has retrieved data from a remote server.
6104      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6105      * @return {Object} data A data block which is used by an Roo.data.Store object as
6106      * a cache of Roo.data.Records.
6107      */
6108     read : function(response){
6109         var json = response.responseText;
6110        
6111         var o = /* eval:var:o */ eval("("+json+")");
6112         if(!o) {
6113             throw {message: "JsonReader.read: Json object not found"};
6114         }
6115         
6116         if(o.metaData){
6117             
6118             delete this.ef;
6119             this.metaFromRemote = true;
6120             this.meta = o.metaData;
6121             this.recordType = Roo.data.Record.create(o.metaData.fields);
6122             this.onMetaChange(this.meta, this.recordType, o);
6123         }
6124         return this.readRecords(o);
6125     },
6126
6127     // private function a store will implement
6128     onMetaChange : function(meta, recordType, o){
6129
6130     },
6131
6132     /**
6133          * @ignore
6134          */
6135     simpleAccess: function(obj, subsc) {
6136         return obj[subsc];
6137     },
6138
6139         /**
6140          * @ignore
6141          */
6142     getJsonAccessor: function(){
6143         var re = /[\[\.]/;
6144         return function(expr) {
6145             try {
6146                 return(re.test(expr))
6147                     ? new Function("obj", "return obj." + expr)
6148                     : function(obj){
6149                         return obj[expr];
6150                     };
6151             } catch(e){}
6152             return Roo.emptyFn;
6153         };
6154     }(),
6155
6156     /**
6157      * Create a data block containing Roo.data.Records from an XML document.
6158      * @param {Object} o An object which contains an Array of row objects in the property specified
6159      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6160      * which contains the total size of the dataset.
6161      * @return {Object} data A data block which is used by an Roo.data.Store object as
6162      * a cache of Roo.data.Records.
6163      */
6164     readRecords : function(o){
6165         /**
6166          * After any data loads, the raw JSON data is available for further custom processing.
6167          * @type Object
6168          */
6169         this.jsonData = o;
6170         var s = this.meta, Record = this.recordType,
6171             f = Record.prototype.fields, fi = f.items, fl = f.length;
6172
6173 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6174         if (!this.ef) {
6175             if(s.totalProperty) {
6176                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6177                 }
6178                 if(s.successProperty) {
6179                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6180                 }
6181                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6182                 if (s.id) {
6183                         var g = this.getJsonAccessor(s.id);
6184                         this.getId = function(rec) {
6185                                 var r = g(rec);
6186                                 return (r === undefined || r === "") ? null : r;
6187                         };
6188                 } else {
6189                         this.getId = function(){return null;};
6190                 }
6191             this.ef = [];
6192             for(var jj = 0; jj < fl; jj++){
6193                 f = fi[jj];
6194                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6195                 this.ef[jj] = this.getJsonAccessor(map);
6196             }
6197         }
6198
6199         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6200         if(s.totalProperty){
6201             var vt = parseInt(this.getTotal(o), 10);
6202             if(!isNaN(vt)){
6203                 totalRecords = vt;
6204             }
6205         }
6206         if(s.successProperty){
6207             var vs = this.getSuccess(o);
6208             if(vs === false || vs === 'false'){
6209                 success = false;
6210             }
6211         }
6212         var records = [];
6213             for(var i = 0; i < c; i++){
6214                     var n = root[i];
6215                 var values = {};
6216                 var id = this.getId(n);
6217                 for(var j = 0; j < fl; j++){
6218                     f = fi[j];
6219                 var v = this.ef[j](n);
6220                 if (!f.convert) {
6221                     Roo.log('missing convert for ' + f.name);
6222                     Roo.log(f);
6223                     continue;
6224                 }
6225                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6226                 }
6227                 var record = new Record(values, id);
6228                 record.json = n;
6229                 records[i] = record;
6230             }
6231             return {
6232                 success : success,
6233                 records : records,
6234                 totalRecords : totalRecords
6235             };
6236     }
6237 });/*
6238  * Based on:
6239  * Ext JS Library 1.1.1
6240  * Copyright(c) 2006-2007, Ext JS, LLC.
6241  *
6242  * Originally Released Under LGPL - original licence link has changed is not relivant.
6243  *
6244  * Fork - LGPL
6245  * <script type="text/javascript">
6246  */
6247
6248 /**
6249  * @class Roo.data.XmlReader
6250  * @extends Roo.data.DataReader
6251  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6252  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6253  * <p>
6254  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6255  * header in the HTTP response must be set to "text/xml".</em>
6256  * <p>
6257  * Example code:
6258  * <pre><code>
6259 var RecordDef = Roo.data.Record.create([
6260    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6261    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6262 ]);
6263 var myReader = new Roo.data.XmlReader({
6264    totalRecords: "results", // The element which contains the total dataset size (optional)
6265    record: "row",           // The repeated element which contains row information
6266    id: "id"                 // The element within the row that provides an ID for the record (optional)
6267 }, RecordDef);
6268 </code></pre>
6269  * <p>
6270  * This would consume an XML file like this:
6271  * <pre><code>
6272 &lt;?xml?>
6273 &lt;dataset>
6274  &lt;results>2&lt;/results>
6275  &lt;row>
6276    &lt;id>1&lt;/id>
6277    &lt;name>Bill&lt;/name>
6278    &lt;occupation>Gardener&lt;/occupation>
6279  &lt;/row>
6280  &lt;row>
6281    &lt;id>2&lt;/id>
6282    &lt;name>Ben&lt;/name>
6283    &lt;occupation>Horticulturalist&lt;/occupation>
6284  &lt;/row>
6285 &lt;/dataset>
6286 </code></pre>
6287  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6288  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6289  * paged from the remote server.
6290  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6291  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6292  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6293  * a record identifier value.
6294  * @constructor
6295  * Create a new XmlReader
6296  * @param {Object} meta Metadata configuration options
6297  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6298  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6299  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6300  */
6301 Roo.data.XmlReader = function(meta, recordType){
6302     meta = meta || {};
6303     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6304 };
6305 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6306     /**
6307      * This method is only used by a DataProxy which has retrieved data from a remote server.
6308          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6309          * to contain a method called 'responseXML' that returns an XML document object.
6310      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6311      * a cache of Roo.data.Records.
6312      */
6313     read : function(response){
6314         var doc = response.responseXML;
6315         if(!doc) {
6316             throw {message: "XmlReader.read: XML Document not available"};
6317         }
6318         return this.readRecords(doc);
6319     },
6320
6321     /**
6322      * Create a data block containing Roo.data.Records from an XML document.
6323          * @param {Object} doc A parsed XML document.
6324      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6325      * a cache of Roo.data.Records.
6326      */
6327     readRecords : function(doc){
6328         /**
6329          * After any data loads/reads, the raw XML Document is available for further custom processing.
6330          * @type XMLDocument
6331          */
6332         this.xmlData = doc;
6333         var root = doc.documentElement || doc;
6334         var q = Roo.DomQuery;
6335         var recordType = this.recordType, fields = recordType.prototype.fields;
6336         var sid = this.meta.id;
6337         var totalRecords = 0, success = true;
6338         if(this.meta.totalRecords){
6339             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6340         }
6341         
6342         if(this.meta.success){
6343             var sv = q.selectValue(this.meta.success, root, true);
6344             success = sv !== false && sv !== 'false';
6345         }
6346         var records = [];
6347         var ns = q.select(this.meta.record, root);
6348         for(var i = 0, len = ns.length; i < len; i++) {
6349                 var n = ns[i];
6350                 var values = {};
6351                 var id = sid ? q.selectValue(sid, n) : undefined;
6352                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6353                     var f = fields.items[j];
6354                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6355                     v = f.convert(v);
6356                     values[f.name] = v;
6357                 }
6358                 var record = new recordType(values, id);
6359                 record.node = n;
6360                 records[records.length] = record;
6361             }
6362
6363             return {
6364                 success : success,
6365                 records : records,
6366                 totalRecords : 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  * @class Roo.data.ArrayReader
6382  * @extends Roo.data.DataReader
6383  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6384  * Each element of that Array represents a row of data fields. The
6385  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6386  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6387  * <p>
6388  * Example code:.
6389  * <pre><code>
6390 var RecordDef = Roo.data.Record.create([
6391     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6392     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6393 ]);
6394 var myReader = new Roo.data.ArrayReader({
6395     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6396 }, RecordDef);
6397 </code></pre>
6398  * <p>
6399  * This would consume an Array like this:
6400  * <pre><code>
6401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6402   </code></pre>
6403  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6404  * @constructor
6405  * Create a new JsonReader
6406  * @param {Object} meta Metadata configuration options.
6407  * @param {Object} recordType Either an Array of field definition objects
6408  * as specified to {@link Roo.data.Record#create},
6409  * or an {@link Roo.data.Record} object
6410  * created using {@link Roo.data.Record#create}.
6411  */
6412 Roo.data.ArrayReader = function(meta, recordType){
6413     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6414 };
6415
6416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6417     /**
6418      * Create a data block containing Roo.data.Records from an XML document.
6419      * @param {Object} o An Array of row objects which represents the dataset.
6420      * @return {Object} data A data block which is used by an Roo.data.Store object as
6421      * a cache of Roo.data.Records.
6422      */
6423     readRecords : function(o){
6424         var sid = this.meta ? this.meta.id : null;
6425         var recordType = this.recordType, fields = recordType.prototype.fields;
6426         var records = [];
6427         var root = o;
6428             for(var i = 0; i < root.length; i++){
6429                     var n = root[i];
6430                 var values = {};
6431                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6432                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6433                 var f = fields.items[j];
6434                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6435                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6436                 v = f.convert(v);
6437                 values[f.name] = v;
6438             }
6439                 var record = new recordType(values, id);
6440                 record.json = n;
6441                 records[records.length] = record;
6442             }
6443             return {
6444                 records : records,
6445                 totalRecords : records.length
6446             };
6447     }
6448 });/*
6449  * Based on:
6450  * Ext JS Library 1.1.1
6451  * Copyright(c) 2006-2007, Ext JS, LLC.
6452  *
6453  * Originally Released Under LGPL - original licence link has changed is not relivant.
6454  *
6455  * Fork - LGPL
6456  * <script type="text/javascript">
6457  */
6458
6459
6460 /**
6461  * @class Roo.data.Tree
6462  * @extends Roo.util.Observable
6463  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6464  * in the tree have most standard DOM functionality.
6465  * @constructor
6466  * @param {Node} root (optional) The root node
6467  */
6468 Roo.data.Tree = function(root){
6469    this.nodeHash = {};
6470    /**
6471     * The root node for this tree
6472     * @type Node
6473     */
6474    this.root = null;
6475    if(root){
6476        this.setRootNode(root);
6477    }
6478    this.addEvents({
6479        /**
6480         * @event append
6481         * Fires when a new child node is appended to a node in this tree.
6482         * @param {Tree} tree The owner tree
6483         * @param {Node} parent The parent node
6484         * @param {Node} node The newly appended node
6485         * @param {Number} index The index of the newly appended node
6486         */
6487        "append" : true,
6488        /**
6489         * @event remove
6490         * Fires when a child node is removed from a node in this tree.
6491         * @param {Tree} tree The owner tree
6492         * @param {Node} parent The parent node
6493         * @param {Node} node The child node removed
6494         */
6495        "remove" : true,
6496        /**
6497         * @event move
6498         * Fires when a node is moved to a new location in the tree
6499         * @param {Tree} tree The owner tree
6500         * @param {Node} node The node moved
6501         * @param {Node} oldParent The old parent of this node
6502         * @param {Node} newParent The new parent of this node
6503         * @param {Number} index The index it was moved to
6504         */
6505        "move" : true,
6506        /**
6507         * @event insert
6508         * Fires when a new child node is inserted in a node in this tree.
6509         * @param {Tree} tree The owner tree
6510         * @param {Node} parent The parent node
6511         * @param {Node} node The child node inserted
6512         * @param {Node} refNode The child node the node was inserted before
6513         */
6514        "insert" : true,
6515        /**
6516         * @event beforeappend
6517         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6518         * @param {Tree} tree The owner tree
6519         * @param {Node} parent The parent node
6520         * @param {Node} node The child node to be appended
6521         */
6522        "beforeappend" : true,
6523        /**
6524         * @event beforeremove
6525         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6526         * @param {Tree} tree The owner tree
6527         * @param {Node} parent The parent node
6528         * @param {Node} node The child node to be removed
6529         */
6530        "beforeremove" : true,
6531        /**
6532         * @event beforemove
6533         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6534         * @param {Tree} tree The owner tree
6535         * @param {Node} node The node being moved
6536         * @param {Node} oldParent The parent of the node
6537         * @param {Node} newParent The new parent the node is moving to
6538         * @param {Number} index The index it is being moved to
6539         */
6540        "beforemove" : true,
6541        /**
6542         * @event beforeinsert
6543         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6544         * @param {Tree} tree The owner tree
6545         * @param {Node} parent The parent node
6546         * @param {Node} node The child node to be inserted
6547         * @param {Node} refNode The child node the node is being inserted before
6548         */
6549        "beforeinsert" : true
6550    });
6551
6552     Roo.data.Tree.superclass.constructor.call(this);
6553 };
6554
6555 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6556     pathSeparator: "/",
6557
6558     proxyNodeEvent : function(){
6559         return this.fireEvent.apply(this, arguments);
6560     },
6561
6562     /**
6563      * Returns the root node for this tree.
6564      * @return {Node}
6565      */
6566     getRootNode : function(){
6567         return this.root;
6568     },
6569
6570     /**
6571      * Sets the root node for this tree.
6572      * @param {Node} node
6573      * @return {Node}
6574      */
6575     setRootNode : function(node){
6576         this.root = node;
6577         node.ownerTree = this;
6578         node.isRoot = true;
6579         this.registerNode(node);
6580         return node;
6581     },
6582
6583     /**
6584      * Gets a node in this tree by its id.
6585      * @param {String} id
6586      * @return {Node}
6587      */
6588     getNodeById : function(id){
6589         return this.nodeHash[id];
6590     },
6591
6592     registerNode : function(node){
6593         this.nodeHash[node.id] = node;
6594     },
6595
6596     unregisterNode : function(node){
6597         delete this.nodeHash[node.id];
6598     },
6599
6600     toString : function(){
6601         return "[Tree"+(this.id?" "+this.id:"")+"]";
6602     }
6603 });
6604
6605 /**
6606  * @class Roo.data.Node
6607  * @extends Roo.util.Observable
6608  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6609  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6610  * @constructor
6611  * @param {Object} attributes The attributes/config for the node
6612  */
6613 Roo.data.Node = function(attributes){
6614     /**
6615      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6616      * @type {Object}
6617      */
6618     this.attributes = attributes || {};
6619     this.leaf = this.attributes.leaf;
6620     /**
6621      * The node id. @type String
6622      */
6623     this.id = this.attributes.id;
6624     if(!this.id){
6625         this.id = Roo.id(null, "ynode-");
6626         this.attributes.id = this.id;
6627     }
6628     /**
6629      * All child nodes of this node. @type Array
6630      */
6631     this.childNodes = [];
6632     if(!this.childNodes.indexOf){ // indexOf is a must
6633         this.childNodes.indexOf = function(o){
6634             for(var i = 0, len = this.length; i < len; i++){
6635                 if(this[i] == o) {
6636                     return i;
6637                 }
6638             }
6639             return -1;
6640         };
6641     }
6642     /**
6643      * The parent node for this node. @type Node
6644      */
6645     this.parentNode = null;
6646     /**
6647      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6648      */
6649     this.firstChild = null;
6650     /**
6651      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6652      */
6653     this.lastChild = null;
6654     /**
6655      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6656      */
6657     this.previousSibling = null;
6658     /**
6659      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6660      */
6661     this.nextSibling = null;
6662
6663     this.addEvents({
6664        /**
6665         * @event append
6666         * Fires when a new child node is appended
6667         * @param {Tree} tree The owner tree
6668         * @param {Node} this This node
6669         * @param {Node} node The newly appended node
6670         * @param {Number} index The index of the newly appended node
6671         */
6672        "append" : true,
6673        /**
6674         * @event remove
6675         * Fires when a child node is removed
6676         * @param {Tree} tree The owner tree
6677         * @param {Node} this This node
6678         * @param {Node} node The removed node
6679         */
6680        "remove" : true,
6681        /**
6682         * @event move
6683         * Fires when this node is moved to a new location in the tree
6684         * @param {Tree} tree The owner tree
6685         * @param {Node} this This node
6686         * @param {Node} oldParent The old parent of this node
6687         * @param {Node} newParent The new parent of this node
6688         * @param {Number} index The index it was moved to
6689         */
6690        "move" : true,
6691        /**
6692         * @event insert
6693         * Fires when a new child node is inserted.
6694         * @param {Tree} tree The owner tree
6695         * @param {Node} this This node
6696         * @param {Node} node The child node inserted
6697         * @param {Node} refNode The child node the node was inserted before
6698         */
6699        "insert" : true,
6700        /**
6701         * @event beforeappend
6702         * Fires before a new child is appended, return false to cancel the append.
6703         * @param {Tree} tree The owner tree
6704         * @param {Node} this This node
6705         * @param {Node} node The child node to be appended
6706         */
6707        "beforeappend" : true,
6708        /**
6709         * @event beforeremove
6710         * Fires before a child is removed, return false to cancel the remove.
6711         * @param {Tree} tree The owner tree
6712         * @param {Node} this This node
6713         * @param {Node} node The child node to be removed
6714         */
6715        "beforeremove" : true,
6716        /**
6717         * @event beforemove
6718         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6719         * @param {Tree} tree The owner tree
6720         * @param {Node} this This node
6721         * @param {Node} oldParent The parent of this node
6722         * @param {Node} newParent The new parent this node is moving to
6723         * @param {Number} index The index it is being moved to
6724         */
6725        "beforemove" : true,
6726        /**
6727         * @event beforeinsert
6728         * Fires before a new child is inserted, return false to cancel the insert.
6729         * @param {Tree} tree The owner tree
6730         * @param {Node} this This node
6731         * @param {Node} node The child node to be inserted
6732         * @param {Node} refNode The child node the node is being inserted before
6733         */
6734        "beforeinsert" : true
6735    });
6736     this.listeners = this.attributes.listeners;
6737     Roo.data.Node.superclass.constructor.call(this);
6738 };
6739
6740 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6741     fireEvent : function(evtName){
6742         // first do standard event for this node
6743         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6744             return false;
6745         }
6746         // then bubble it up to the tree if the event wasn't cancelled
6747         var ot = this.getOwnerTree();
6748         if(ot){
6749             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6750                 return false;
6751             }
6752         }
6753         return true;
6754     },
6755
6756     /**
6757      * Returns true if this node is a leaf
6758      * @return {Boolean}
6759      */
6760     isLeaf : function(){
6761         return this.leaf === true;
6762     },
6763
6764     // private
6765     setFirstChild : function(node){
6766         this.firstChild = node;
6767     },
6768
6769     //private
6770     setLastChild : function(node){
6771         this.lastChild = node;
6772     },
6773
6774
6775     /**
6776      * Returns true if this node is the last child of its parent
6777      * @return {Boolean}
6778      */
6779     isLast : function(){
6780        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6781     },
6782
6783     /**
6784      * Returns true if this node is the first child of its parent
6785      * @return {Boolean}
6786      */
6787     isFirst : function(){
6788        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6789     },
6790
6791     hasChildNodes : function(){
6792         return !this.isLeaf() && this.childNodes.length > 0;
6793     },
6794
6795     /**
6796      * Insert node(s) as the last child node of this node.
6797      * @param {Node/Array} node The node or Array of nodes to append
6798      * @return {Node} The appended node if single append, or null if an array was passed
6799      */
6800     appendChild : function(node){
6801         var multi = false;
6802         if(node instanceof Array){
6803             multi = node;
6804         }else if(arguments.length > 1){
6805             multi = arguments;
6806         }
6807         // if passed an array or multiple args do them one by one
6808         if(multi){
6809             for(var i = 0, len = multi.length; i < len; i++) {
6810                 this.appendChild(multi[i]);
6811             }
6812         }else{
6813             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6814                 return false;
6815             }
6816             var index = this.childNodes.length;
6817             var oldParent = node.parentNode;
6818             // it's a move, make sure we move it cleanly
6819             if(oldParent){
6820                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6821                     return false;
6822                 }
6823                 oldParent.removeChild(node);
6824             }
6825             index = this.childNodes.length;
6826             if(index == 0){
6827                 this.setFirstChild(node);
6828             }
6829             this.childNodes.push(node);
6830             node.parentNode = this;
6831             var ps = this.childNodes[index-1];
6832             if(ps){
6833                 node.previousSibling = ps;
6834                 ps.nextSibling = node;
6835             }else{
6836                 node.previousSibling = null;
6837             }
6838             node.nextSibling = null;
6839             this.setLastChild(node);
6840             node.setOwnerTree(this.getOwnerTree());
6841             this.fireEvent("append", this.ownerTree, this, node, index);
6842             if(oldParent){
6843                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6844             }
6845             return node;
6846         }
6847     },
6848
6849     /**
6850      * Removes a child node from this node.
6851      * @param {Node} node The node to remove
6852      * @return {Node} The removed node
6853      */
6854     removeChild : function(node){
6855         var index = this.childNodes.indexOf(node);
6856         if(index == -1){
6857             return false;
6858         }
6859         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6860             return false;
6861         }
6862
6863         // remove it from childNodes collection
6864         this.childNodes.splice(index, 1);
6865
6866         // update siblings
6867         if(node.previousSibling){
6868             node.previousSibling.nextSibling = node.nextSibling;
6869         }
6870         if(node.nextSibling){
6871             node.nextSibling.previousSibling = node.previousSibling;
6872         }
6873
6874         // update child refs
6875         if(this.firstChild == node){
6876             this.setFirstChild(node.nextSibling);
6877         }
6878         if(this.lastChild == node){
6879             this.setLastChild(node.previousSibling);
6880         }
6881
6882         node.setOwnerTree(null);
6883         // clear any references from the node
6884         node.parentNode = null;
6885         node.previousSibling = null;
6886         node.nextSibling = null;
6887         this.fireEvent("remove", this.ownerTree, this, node);
6888         return node;
6889     },
6890
6891     /**
6892      * Inserts the first node before the second node in this nodes childNodes collection.
6893      * @param {Node} node The node to insert
6894      * @param {Node} refNode The node to insert before (if null the node is appended)
6895      * @return {Node} The inserted node
6896      */
6897     insertBefore : function(node, refNode){
6898         if(!refNode){ // like standard Dom, refNode can be null for append
6899             return this.appendChild(node);
6900         }
6901         // nothing to do
6902         if(node == refNode){
6903             return false;
6904         }
6905
6906         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6907             return false;
6908         }
6909         var index = this.childNodes.indexOf(refNode);
6910         var oldParent = node.parentNode;
6911         var refIndex = index;
6912
6913         // when moving internally, indexes will change after remove
6914         if(oldParent == this && this.childNodes.indexOf(node) < index){
6915             refIndex--;
6916         }
6917
6918         // it's a move, make sure we move it cleanly
6919         if(oldParent){
6920             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6921                 return false;
6922             }
6923             oldParent.removeChild(node);
6924         }
6925         if(refIndex == 0){
6926             this.setFirstChild(node);
6927         }
6928         this.childNodes.splice(refIndex, 0, node);
6929         node.parentNode = this;
6930         var ps = this.childNodes[refIndex-1];
6931         if(ps){
6932             node.previousSibling = ps;
6933             ps.nextSibling = node;
6934         }else{
6935             node.previousSibling = null;
6936         }
6937         node.nextSibling = refNode;
6938         refNode.previousSibling = node;
6939         node.setOwnerTree(this.getOwnerTree());
6940         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6941         if(oldParent){
6942             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6943         }
6944         return node;
6945     },
6946
6947     /**
6948      * Returns the child node at the specified index.
6949      * @param {Number} index
6950      * @return {Node}
6951      */
6952     item : function(index){
6953         return this.childNodes[index];
6954     },
6955
6956     /**
6957      * Replaces one child node in this node with another.
6958      * @param {Node} newChild The replacement node
6959      * @param {Node} oldChild The node to replace
6960      * @return {Node} The replaced node
6961      */
6962     replaceChild : function(newChild, oldChild){
6963         this.insertBefore(newChild, oldChild);
6964         this.removeChild(oldChild);
6965         return oldChild;
6966     },
6967
6968     /**
6969      * Returns the index of a child node
6970      * @param {Node} node
6971      * @return {Number} The index of the node or -1 if it was not found
6972      */
6973     indexOf : function(child){
6974         return this.childNodes.indexOf(child);
6975     },
6976
6977     /**
6978      * Returns the tree this node is in.
6979      * @return {Tree}
6980      */
6981     getOwnerTree : function(){
6982         // if it doesn't have one, look for one
6983         if(!this.ownerTree){
6984             var p = this;
6985             while(p){
6986                 if(p.ownerTree){
6987                     this.ownerTree = p.ownerTree;
6988                     break;
6989                 }
6990                 p = p.parentNode;
6991             }
6992         }
6993         return this.ownerTree;
6994     },
6995
6996     /**
6997      * Returns depth of this node (the root node has a depth of 0)
6998      * @return {Number}
6999      */
7000     getDepth : function(){
7001         var depth = 0;
7002         var p = this;
7003         while(p.parentNode){
7004             ++depth;
7005             p = p.parentNode;
7006         }
7007         return depth;
7008     },
7009
7010     // private
7011     setOwnerTree : function(tree){
7012         // if it's move, we need to update everyone
7013         if(tree != this.ownerTree){
7014             if(this.ownerTree){
7015                 this.ownerTree.unregisterNode(this);
7016             }
7017             this.ownerTree = tree;
7018             var cs = this.childNodes;
7019             for(var i = 0, len = cs.length; i < len; i++) {
7020                 cs[i].setOwnerTree(tree);
7021             }
7022             if(tree){
7023                 tree.registerNode(this);
7024             }
7025         }
7026     },
7027
7028     /**
7029      * Returns the path for this node. The path can be used to expand or select this node programmatically.
7030      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7031      * @return {String} The path
7032      */
7033     getPath : function(attr){
7034         attr = attr || "id";
7035         var p = this.parentNode;
7036         var b = [this.attributes[attr]];
7037         while(p){
7038             b.unshift(p.attributes[attr]);
7039             p = p.parentNode;
7040         }
7041         var sep = this.getOwnerTree().pathSeparator;
7042         return sep + b.join(sep);
7043     },
7044
7045     /**
7046      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7047      * function call will be the scope provided or the current node. The arguments to the function
7048      * will be the args provided or the current node. If the function returns false at any point,
7049      * the bubble is stopped.
7050      * @param {Function} fn The function to call
7051      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7052      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7053      */
7054     bubble : function(fn, scope, args){
7055         var p = this;
7056         while(p){
7057             if(fn.call(scope || p, args || p) === false){
7058                 break;
7059             }
7060             p = p.parentNode;
7061         }
7062     },
7063
7064     /**
7065      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7066      * function call will be the scope provided or the current node. The arguments to the function
7067      * will be the args provided or the current node. If the function returns false at any point,
7068      * the cascade is stopped on that branch.
7069      * @param {Function} fn The function to call
7070      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7071      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7072      */
7073     cascade : function(fn, scope, args){
7074         if(fn.call(scope || this, args || this) !== false){
7075             var cs = this.childNodes;
7076             for(var i = 0, len = cs.length; i < len; i++) {
7077                 cs[i].cascade(fn, scope, args);
7078             }
7079         }
7080     },
7081
7082     /**
7083      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7084      * function call will be the scope provided or the current node. The arguments to the function
7085      * will be the args provided or the current node. If the function returns false at any point,
7086      * the iteration stops.
7087      * @param {Function} fn The function to call
7088      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7090      */
7091     eachChild : function(fn, scope, args){
7092         var cs = this.childNodes;
7093         for(var i = 0, len = cs.length; i < len; i++) {
7094                 if(fn.call(scope || this, args || cs[i]) === false){
7095                     break;
7096                 }
7097         }
7098     },
7099
7100     /**
7101      * Finds the first child that has the attribute with the specified value.
7102      * @param {String} attribute The attribute name
7103      * @param {Mixed} value The value to search for
7104      * @return {Node} The found child or null if none was found
7105      */
7106     findChild : function(attribute, value){
7107         var cs = this.childNodes;
7108         for(var i = 0, len = cs.length; i < len; i++) {
7109                 if(cs[i].attributes[attribute] == value){
7110                     return cs[i];
7111                 }
7112         }
7113         return null;
7114     },
7115
7116     /**
7117      * Finds the first child by a custom function. The child matches if the function passed
7118      * returns true.
7119      * @param {Function} fn
7120      * @param {Object} scope (optional)
7121      * @return {Node} The found child or null if none was found
7122      */
7123     findChildBy : function(fn, scope){
7124         var cs = this.childNodes;
7125         for(var i = 0, len = cs.length; i < len; i++) {
7126                 if(fn.call(scope||cs[i], cs[i]) === true){
7127                     return cs[i];
7128                 }
7129         }
7130         return null;
7131     },
7132
7133     /**
7134      * Sorts this nodes children using the supplied sort function
7135      * @param {Function} fn
7136      * @param {Object} scope (optional)
7137      */
7138     sort : function(fn, scope){
7139         var cs = this.childNodes;
7140         var len = cs.length;
7141         if(len > 0){
7142             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7143             cs.sort(sortFn);
7144             for(var i = 0; i < len; i++){
7145                 var n = cs[i];
7146                 n.previousSibling = cs[i-1];
7147                 n.nextSibling = cs[i+1];
7148                 if(i == 0){
7149                     this.setFirstChild(n);
7150                 }
7151                 if(i == len-1){
7152                     this.setLastChild(n);
7153                 }
7154             }
7155         }
7156     },
7157
7158     /**
7159      * Returns true if this node is an ancestor (at any point) of the passed node.
7160      * @param {Node} node
7161      * @return {Boolean}
7162      */
7163     contains : function(node){
7164         return node.isAncestor(this);
7165     },
7166
7167     /**
7168      * Returns true if the passed node is an ancestor (at any point) of this node.
7169      * @param {Node} node
7170      * @return {Boolean}
7171      */
7172     isAncestor : function(node){
7173         var p = this.parentNode;
7174         while(p){
7175             if(p == node){
7176                 return true;
7177             }
7178             p = p.parentNode;
7179         }
7180         return false;
7181     },
7182
7183     toString : function(){
7184         return "[Node"+(this.id?" "+this.id:"")+"]";
7185     }
7186 });/*
7187  * Based on:
7188  * Ext JS Library 1.1.1
7189  * Copyright(c) 2006-2007, Ext JS, LLC.
7190  *
7191  * Originally Released Under LGPL - original licence link has changed is not relivant.
7192  *
7193  * Fork - LGPL
7194  * <script type="text/javascript">
7195  */
7196  
7197
7198 /**
7199  * @class Roo.ComponentMgr
7200  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7201  * @singleton
7202  */
7203 Roo.ComponentMgr = function(){
7204     var all = new Roo.util.MixedCollection();
7205
7206     return {
7207         /**
7208          * Registers a component.
7209          * @param {Roo.Component} c The component
7210          */
7211         register : function(c){
7212             all.add(c);
7213         },
7214
7215         /**
7216          * Unregisters a component.
7217          * @param {Roo.Component} c The component
7218          */
7219         unregister : function(c){
7220             all.remove(c);
7221         },
7222
7223         /**
7224          * Returns a component by id
7225          * @param {String} id The component id
7226          */
7227         get : function(id){
7228             return all.get(id);
7229         },
7230
7231         /**
7232          * Registers a function that will be called when a specified component is added to ComponentMgr
7233          * @param {String} id The component id
7234          * @param {Funtction} fn The callback function
7235          * @param {Object} scope The scope of the callback
7236          */
7237         onAvailable : function(id, fn, scope){
7238             all.on("add", function(index, o){
7239                 if(o.id == id){
7240                     fn.call(scope || o, o);
7241                     all.un("add", fn, scope);
7242                 }
7243             });
7244         }
7245     };
7246 }();/*
7247  * Based on:
7248  * Ext JS Library 1.1.1
7249  * Copyright(c) 2006-2007, Ext JS, LLC.
7250  *
7251  * Originally Released Under LGPL - original licence link has changed is not relivant.
7252  *
7253  * Fork - LGPL
7254  * <script type="text/javascript">
7255  */
7256  
7257 /**
7258  * @class Roo.Component
7259  * @extends Roo.util.Observable
7260  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7261  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7262  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7263  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7264  * All visual components (widgets) that require rendering into a layout should subclass Component.
7265  * @constructor
7266  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7267  * 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
7268  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7269  */
7270 Roo.Component = function(config){
7271     config = config || {};
7272     if(config.tagName || config.dom || typeof config == "string"){ // element object
7273         config = {el: config, id: config.id || config};
7274     }
7275     this.initialConfig = config;
7276
7277     Roo.apply(this, config);
7278     this.addEvents({
7279         /**
7280          * @event disable
7281          * Fires after the component is disabled.
7282              * @param {Roo.Component} this
7283              */
7284         disable : true,
7285         /**
7286          * @event enable
7287          * Fires after the component is enabled.
7288              * @param {Roo.Component} this
7289              */
7290         enable : true,
7291         /**
7292          * @event beforeshow
7293          * Fires before the component is shown.  Return false to stop the show.
7294              * @param {Roo.Component} this
7295              */
7296         beforeshow : true,
7297         /**
7298          * @event show
7299          * Fires after the component is shown.
7300              * @param {Roo.Component} this
7301              */
7302         show : true,
7303         /**
7304          * @event beforehide
7305          * Fires before the component is hidden. Return false to stop the hide.
7306              * @param {Roo.Component} this
7307              */
7308         beforehide : true,
7309         /**
7310          * @event hide
7311          * Fires after the component is hidden.
7312              * @param {Roo.Component} this
7313              */
7314         hide : true,
7315         /**
7316          * @event beforerender
7317          * Fires before the component is rendered. Return false to stop the render.
7318              * @param {Roo.Component} this
7319              */
7320         beforerender : true,
7321         /**
7322          * @event render
7323          * Fires after the component is rendered.
7324              * @param {Roo.Component} this
7325              */
7326         render : true,
7327         /**
7328          * @event beforedestroy
7329          * Fires before the component is destroyed. Return false to stop the destroy.
7330              * @param {Roo.Component} this
7331              */
7332         beforedestroy : true,
7333         /**
7334          * @event destroy
7335          * Fires after the component is destroyed.
7336              * @param {Roo.Component} this
7337              */
7338         destroy : true
7339     });
7340     if(!this.id){
7341         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7342     }
7343     Roo.ComponentMgr.register(this);
7344     Roo.Component.superclass.constructor.call(this);
7345     this.initComponent();
7346     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7347         this.render(this.renderTo);
7348         delete this.renderTo;
7349     }
7350 };
7351
7352 // private
7353 Roo.Component.AUTO_ID = 1000;
7354
7355 Roo.extend(Roo.Component, Roo.util.Observable, {
7356     /**
7357      * @property {Boolean} hidden
7358      * true if this component is hidden. Read-only.
7359      */
7360     hidden : false,
7361     /**
7362      * true if this component is disabled. Read-only.
7363      */
7364     disabled : false,
7365     /**
7366      * true if this component has been rendered. Read-only.
7367      */
7368     rendered : false,
7369     
7370     /** @cfg {String} disableClass
7371      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7372      */
7373     disabledClass : "x-item-disabled",
7374         /** @cfg {Boolean} allowDomMove
7375          * Whether the component can move the Dom node when rendering (defaults to true).
7376          */
7377     allowDomMove : true,
7378     /** @cfg {String} hideMode
7379      * How this component should hidden. Supported values are
7380      * "visibility" (css visibility), "offsets" (negative offset position) and
7381      * "display" (css display) - defaults to "display".
7382      */
7383     hideMode: 'display',
7384
7385     // private
7386     ctype : "Roo.Component",
7387
7388     /** @cfg {String} actionMode 
7389      * which property holds the element that used for  hide() / show() / disable() / enable()
7390      * default is 'el' 
7391      */
7392     actionMode : "el",
7393
7394     // private
7395     getActionEl : function(){
7396         return this[this.actionMode];
7397     },
7398
7399     initComponent : Roo.emptyFn,
7400     /**
7401      * If this is a lazy rendering component, render it to its container element.
7402      * @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.
7403      */
7404     render : function(container, position){
7405         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7406             if(!container && this.el){
7407                 this.el = Roo.get(this.el);
7408                 container = this.el.dom.parentNode;
7409                 this.allowDomMove = false;
7410             }
7411             this.container = Roo.get(container);
7412             this.rendered = true;
7413             if(position !== undefined){
7414                 if(typeof position == 'number'){
7415                     position = this.container.dom.childNodes[position];
7416                 }else{
7417                     position = Roo.getDom(position);
7418                 }
7419             }
7420             this.onRender(this.container, position || null);
7421             if(this.cls){
7422                 this.el.addClass(this.cls);
7423                 delete this.cls;
7424             }
7425             if(this.style){
7426                 this.el.applyStyles(this.style);
7427                 delete this.style;
7428             }
7429             this.fireEvent("render", this);
7430             this.afterRender(this.container);
7431             if(this.hidden){
7432                 this.hide();
7433             }
7434             if(this.disabled){
7435                 this.disable();
7436             }
7437         }
7438         return this;
7439     },
7440
7441     // private
7442     // default function is not really useful
7443     onRender : function(ct, position){
7444         if(this.el){
7445             this.el = Roo.get(this.el);
7446             if(this.allowDomMove !== false){
7447                 ct.dom.insertBefore(this.el.dom, position);
7448             }
7449         }
7450     },
7451
7452     // private
7453     getAutoCreate : function(){
7454         var cfg = typeof this.autoCreate == "object" ?
7455                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7456         if(this.id && !cfg.id){
7457             cfg.id = this.id;
7458         }
7459         return cfg;
7460     },
7461
7462     // private
7463     afterRender : Roo.emptyFn,
7464
7465     /**
7466      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7467      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7468      */
7469     destroy : function(){
7470         if(this.fireEvent("beforedestroy", this) !== false){
7471             this.purgeListeners();
7472             this.beforeDestroy();
7473             if(this.rendered){
7474                 this.el.removeAllListeners();
7475                 this.el.remove();
7476                 if(this.actionMode == "container"){
7477                     this.container.remove();
7478                 }
7479             }
7480             this.onDestroy();
7481             Roo.ComponentMgr.unregister(this);
7482             this.fireEvent("destroy", this);
7483         }
7484     },
7485
7486         // private
7487     beforeDestroy : function(){
7488
7489     },
7490
7491         // private
7492         onDestroy : function(){
7493
7494     },
7495
7496     /**
7497      * Returns the underlying {@link Roo.Element}.
7498      * @return {Roo.Element} The element
7499      */
7500     getEl : function(){
7501         return this.el;
7502     },
7503
7504     /**
7505      * Returns the id of this component.
7506      * @return {String}
7507      */
7508     getId : function(){
7509         return this.id;
7510     },
7511
7512     /**
7513      * Try to focus this component.
7514      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7515      * @return {Roo.Component} this
7516      */
7517     focus : function(selectText){
7518         if(this.rendered){
7519             this.el.focus();
7520             if(selectText === true){
7521                 this.el.dom.select();
7522             }
7523         }
7524         return this;
7525     },
7526
7527     // private
7528     blur : function(){
7529         if(this.rendered){
7530             this.el.blur();
7531         }
7532         return this;
7533     },
7534
7535     /**
7536      * Disable this component.
7537      * @return {Roo.Component} this
7538      */
7539     disable : function(){
7540         if(this.rendered){
7541             this.onDisable();
7542         }
7543         this.disabled = true;
7544         this.fireEvent("disable", this);
7545         return this;
7546     },
7547
7548         // private
7549     onDisable : function(){
7550         this.getActionEl().addClass(this.disabledClass);
7551         this.el.dom.disabled = true;
7552     },
7553
7554     /**
7555      * Enable this component.
7556      * @return {Roo.Component} this
7557      */
7558     enable : function(){
7559         if(this.rendered){
7560             this.onEnable();
7561         }
7562         this.disabled = false;
7563         this.fireEvent("enable", this);
7564         return this;
7565     },
7566
7567         // private
7568     onEnable : function(){
7569         this.getActionEl().removeClass(this.disabledClass);
7570         this.el.dom.disabled = false;
7571     },
7572
7573     /**
7574      * Convenience function for setting disabled/enabled by boolean.
7575      * @param {Boolean} disabled
7576      */
7577     setDisabled : function(disabled){
7578         this[disabled ? "disable" : "enable"]();
7579     },
7580
7581     /**
7582      * Show this component.
7583      * @return {Roo.Component} this
7584      */
7585     show: function(){
7586         if(this.fireEvent("beforeshow", this) !== false){
7587             this.hidden = false;
7588             if(this.rendered){
7589                 this.onShow();
7590             }
7591             this.fireEvent("show", this);
7592         }
7593         return this;
7594     },
7595
7596     // private
7597     onShow : function(){
7598         var ae = this.getActionEl();
7599         if(this.hideMode == 'visibility'){
7600             ae.dom.style.visibility = "visible";
7601         }else if(this.hideMode == 'offsets'){
7602             ae.removeClass('x-hidden');
7603         }else{
7604             ae.dom.style.display = "";
7605         }
7606     },
7607
7608     /**
7609      * Hide this component.
7610      * @return {Roo.Component} this
7611      */
7612     hide: function(){
7613         if(this.fireEvent("beforehide", this) !== false){
7614             this.hidden = true;
7615             if(this.rendered){
7616                 this.onHide();
7617             }
7618             this.fireEvent("hide", this);
7619         }
7620         return this;
7621     },
7622
7623     // private
7624     onHide : function(){
7625         var ae = this.getActionEl();
7626         if(this.hideMode == 'visibility'){
7627             ae.dom.style.visibility = "hidden";
7628         }else if(this.hideMode == 'offsets'){
7629             ae.addClass('x-hidden');
7630         }else{
7631             ae.dom.style.display = "none";
7632         }
7633     },
7634
7635     /**
7636      * Convenience function to hide or show this component by boolean.
7637      * @param {Boolean} visible True to show, false to hide
7638      * @return {Roo.Component} this
7639      */
7640     setVisible: function(visible){
7641         if(visible) {
7642             this.show();
7643         }else{
7644             this.hide();
7645         }
7646         return this;
7647     },
7648
7649     /**
7650      * Returns true if this component is visible.
7651      */
7652     isVisible : function(){
7653         return this.getActionEl().isVisible();
7654     },
7655
7656     cloneConfig : function(overrides){
7657         overrides = overrides || {};
7658         var id = overrides.id || Roo.id();
7659         var cfg = Roo.applyIf(overrides, this.initialConfig);
7660         cfg.id = id; // prevent dup id
7661         return new this.constructor(cfg);
7662     }
7663 });