source: trunk/web/addons/job_monarch/lib/extjs/source/dd/DDCore.js @ 619

Last change on this file since 619 was 619, checked in by ramonb, 15 years ago

lib/:

  • added new AJAX dependancies: ExtJS, pChart, Lightbox2
File size: 94.2 KB
Line 
1/*
2 * Ext JS Library 2.2.1
3 * Copyright(c) 2006-2009, Ext JS, LLC.
4 * licensing@extjs.com
5 *
6 * http://extjs.com/license
7 */
8
9/*
10 * These classes are derivatives of the similarly named classes in the YUI Library.
11 * The original license:
12 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
13 * Code licensed under the BSD License:
14 * http://developer.yahoo.net/yui/license.txt
15 */
16
17(function() {
18
19var Event=Ext.EventManager;
20var Dom=Ext.lib.Dom;
21
22/**
23 * @class Ext.dd.DragDrop
24 * Defines the interface and base operation of items that that can be
25 * dragged or can be drop targets.  It was designed to be extended, overriding
26 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
27 * Up to three html elements can be associated with a DragDrop instance:
28 * <ul>
29 * <li>linked element: the element that is passed into the constructor.
30 * This is the element which defines the boundaries for interaction with
31 * other DragDrop objects.</li>
32 * <li>handle element(s): The drag operation only occurs if the element that
33 * was clicked matches a handle element.  By default this is the linked
34 * element, but there are times that you will want only a portion of the
35 * linked element to initiate the drag operation, and the setHandleElId()
36 * method provides a way to define this.</li>
37 * <li>drag element: this represents the element that would be moved along
38 * with the cursor during a drag operation.  By default, this is the linked
39 * element itself as in {@link Ext.dd.DD}.  setDragElId() lets you define
40 * a separate element that would be moved, as in {@link Ext.dd.DDProxy}.
41 * </li>
42 * </ul>
43 * This class should not be instantiated until the onload event to ensure that
44 * the associated elements are available.
45 * The following would define a DragDrop obj that would interact with any
46 * other DragDrop obj in the "group1" group:
47 * <pre>
48 *  dd = new Ext.dd.DragDrop("div1", "group1");
49 * </pre>
50 * Since none of the event handlers have been implemented, nothing would
51 * actually happen if you were to run the code above.  Normally you would
52 * override this class or one of the default implementations, but you can
53 * also override the methods you want on an instance of the class...
54 * <pre>
55 *  dd.onDragDrop = function(e, id) {
56 *  &nbsp;&nbsp;alert("dd was dropped on " + id);
57 *  }
58 * </pre>
59 * @constructor
60 * @param {String} id of the element that is linked to this instance
61 * @param {String} sGroup the group of related DragDrop objects
62 * @param {object} config an object containing configurable attributes
63 *                Valid properties for DragDrop:
64 *                    padding, isTarget, maintainOffset, primaryButtonOnly
65 */
66Ext.dd.DragDrop = function(id, sGroup, config) {
67    if(id) {
68        this.init(id, sGroup, config);
69    }
70};
71
72Ext.dd.DragDrop.prototype = {
73
74    /**
75     * The id of the element associated with this object.  This is what we
76     * refer to as the "linked element" because the size and position of
77     * this element is used to determine when the drag and drop objects have
78     * interacted.
79     * @property id
80     * @type String
81     */
82    id: null,
83
84    /**
85     * Configuration attributes passed into the constructor
86     * @property config
87     * @type object
88     */
89    config: null,
90
91    /**
92     * The id of the element that will be dragged.  By default this is same
93     * as the linked element , but could be changed to another element. Ex:
94     * Ext.dd.DDProxy
95     * @property dragElId
96     * @type String
97     * @private
98     */
99    dragElId: null,
100
101    /**
102     * The ID of the element that initiates the drag operation.  By default
103     * this is the linked element, but could be changed to be a child of this
104     * element.  This lets us do things like only starting the drag when the
105     * header element within the linked html element is clicked.
106     * @property handleElId
107     * @type String
108     * @private
109     */
110    handleElId: null,
111
112    /**
113     * An object who's property names identify HTML tags to be considered invalid as drag handles.
114     * A non-null property value identifies the tag as invalid. Defaults to the
115     * following value which prevents drag operations from being initiated by &lt;a> elements:<pre><code>
116{
117    A: "A"
118}</code></pre>
119     * @property invalidHandleTypes
120     * @type Object
121     */
122    invalidHandleTypes: null,
123
124    /**
125     * An object who's property names identify the IDs of elements to be considered invalid as drag handles.
126     * A non-null property value identifies the ID as invalid. For example, to prevent
127     * dragging from being initiated on element ID "foo", use:<pre><code>
128{
129    foo: true
130}</code></pre>
131     * @property invalidHandleIds
132     * @type Object
133     */
134    invalidHandleIds: null,
135
136    /**
137     * An Array of CSS class names for elements to be considered in valid as drag handles.
138     * @property invalidHandleClasses
139     * @type Array
140     */
141    invalidHandleClasses: null,
142
143    /**
144     * The linked element's absolute X position at the time the drag was
145     * started
146     * @property startPageX
147     * @type int
148     * @private
149     */
150    startPageX: 0,
151
152    /**
153     * The linked element's absolute X position at the time the drag was
154     * started
155     * @property startPageY
156     * @type int
157     * @private
158     */
159    startPageY: 0,
160
161    /**
162     * The group defines a logical collection of DragDrop objects that are
163     * related.  Instances only get events when interacting with other
164     * DragDrop object in the same group.  This lets us define multiple
165     * groups using a single DragDrop subclass if we want.
166     * @property groups
167     * @type object An object in the format {'group1':true, 'group2':true}
168     */
169    groups: null,
170
171    /**
172     * Individual drag/drop instances can be locked.  This will prevent
173     * onmousedown start drag.
174     * @property locked
175     * @type boolean
176     * @private
177     */
178    locked: false,
179
180    /**
181     * Lock this instance
182     * @method lock
183     */
184    lock: function() { this.locked = true; },
185
186    /**
187     * When set to true, other DD objects in cooperating DDGroups do not receive
188     * notification events when this DD object is dragged over them. Defaults to false.
189     * @property moveOnly
190     * @type boolean
191     */
192    moveOnly: false,
193
194    /**
195     * Unlock this instace
196     * @method unlock
197     */
198    unlock: function() { this.locked = false; },
199
200    /**
201     * By default, all instances can be a drop target.  This can be disabled by
202     * setting isTarget to false.
203     * @property isTarget
204     * @type boolean
205     */
206    isTarget: true,
207
208    /**
209     * The padding configured for this drag and drop object for calculating
210     * the drop zone intersection with this object.
211     * @property padding
212     * @type int[] An array containing the 4 padding values: [top, right, bottom, left]
213     */
214    padding: null,
215
216    /**
217     * Cached reference to the linked element
218     * @property _domRef
219     * @private
220     */
221    _domRef: null,
222
223    /**
224     * Internal typeof flag
225     * @property __ygDragDrop
226     * @private
227     */
228    __ygDragDrop: true,
229
230    /**
231     * Set to true when horizontal contraints are applied
232     * @property constrainX
233     * @type boolean
234     * @private
235     */
236    constrainX: false,
237
238    /**
239     * Set to true when vertical contraints are applied
240     * @property constrainY
241     * @type boolean
242     * @private
243     */
244    constrainY: false,
245
246    /**
247     * The left constraint
248     * @property minX
249     * @type int
250     * @private
251     */
252    minX: 0,
253
254    /**
255     * The right constraint
256     * @property maxX
257     * @type int
258     * @private
259     */
260    maxX: 0,
261
262    /**
263     * The up constraint
264     * @property minY
265     * @type int
266     * @type int
267     * @private
268     */
269    minY: 0,
270
271    /**
272     * The down constraint
273     * @property maxY
274     * @type int
275     * @private
276     */
277    maxY: 0,
278
279    /**
280     * Maintain offsets when we resetconstraints.  Set to true when you want
281     * the position of the element relative to its parent to stay the same
282     * when the page changes
283     *
284     * @property maintainOffset
285     * @type boolean
286     */
287    maintainOffset: false,
288
289    /**
290     * Array of pixel locations the element will snap to if we specified a
291     * horizontal graduation/interval.  This array is generated automatically
292     * when you define a tick interval.
293     * @property xTicks
294     * @type int[]
295     */
296    xTicks: null,
297
298    /**
299     * Array of pixel locations the element will snap to if we specified a
300     * vertical graduation/interval.  This array is generated automatically
301     * when you define a tick interval.
302     * @property yTicks
303     * @type int[]
304     */
305    yTicks: null,
306
307    /**
308     * By default the drag and drop instance will only respond to the primary
309     * button click (left button for a right-handed mouse).  Set to true to
310     * allow drag and drop to start with any mouse click that is propogated
311     * by the browser
312     * @property primaryButtonOnly
313     * @type boolean
314     */
315    primaryButtonOnly: true,
316
317    /**
318     * The availabe property is false until the linked dom element is accessible.
319     * @property available
320     * @type boolean
321     */
322    available: false,
323
324    /**
325     * By default, drags can only be initiated if the mousedown occurs in the
326     * region the linked element is.  This is done in part to work around a
327     * bug in some browsers that mis-report the mousedown if the previous
328     * mouseup happened outside of the window.  This property is set to true
329     * if outer handles are defined.
330     *
331     * @property hasOuterHandles
332     * @type boolean
333     * @default false
334     */
335    hasOuterHandles: false,
336
337    /**
338     * Code that executes immediately before the startDrag event
339     * @method b4StartDrag
340     * @private
341     */
342    b4StartDrag: function(x, y) { },
343
344    /**
345     * Abstract method called after a drag/drop object is clicked
346     * and the drag or mousedown time thresholds have beeen met.
347     * @method startDrag
348     * @param {int} X click location
349     * @param {int} Y click location
350     */
351    startDrag: function(x, y) { /* override this */ },
352
353    /**
354     * Code that executes immediately before the onDrag event
355     * @method b4Drag
356     * @private
357     */
358    b4Drag: function(e) { },
359
360    /**
361     * Abstract method called during the onMouseMove event while dragging an
362     * object.
363     * @method onDrag
364     * @param {Event} e the mousemove event
365     */
366    onDrag: function(e) { /* override this */ },
367
368    /**
369     * Abstract method called when this element fist begins hovering over
370     * another DragDrop obj
371     * @method onDragEnter
372     * @param {Event} e the mousemove event
373     * @param {String|DragDrop[]} id In POINT mode, the element
374     * id this is hovering over.  In INTERSECT mode, an array of one or more
375     * dragdrop items being hovered over.
376     */
377    onDragEnter: function(e, id) { /* override this */ },
378
379    /**
380     * Code that executes immediately before the onDragOver event
381     * @method b4DragOver
382     * @private
383     */
384    b4DragOver: function(e) { },
385
386    /**
387     * Abstract method called when this element is hovering over another
388     * DragDrop obj
389     * @method onDragOver
390     * @param {Event} e the mousemove event
391     * @param {String|DragDrop[]} id In POINT mode, the element
392     * id this is hovering over.  In INTERSECT mode, an array of dd items
393     * being hovered over.
394     */
395    onDragOver: function(e, id) { /* override this */ },
396
397    /**
398     * Code that executes immediately before the onDragOut event
399     * @method b4DragOut
400     * @private
401     */
402    b4DragOut: function(e) { },
403
404    /**
405     * Abstract method called when we are no longer hovering over an element
406     * @method onDragOut
407     * @param {Event} e the mousemove event
408     * @param {String|DragDrop[]} id In POINT mode, the element
409     * id this was hovering over.  In INTERSECT mode, an array of dd items
410     * that the mouse is no longer over.
411     */
412    onDragOut: function(e, id) { /* override this */ },
413
414    /**
415     * Code that executes immediately before the onDragDrop event
416     * @method b4DragDrop
417     * @private
418     */
419    b4DragDrop: function(e) { },
420
421    /**
422     * Abstract method called when this item is dropped on another DragDrop
423     * obj
424     * @method onDragDrop
425     * @param {Event} e the mouseup event
426     * @param {String|DragDrop[]} id In POINT mode, the element
427     * id this was dropped on.  In INTERSECT mode, an array of dd items this
428     * was dropped on.
429     */
430    onDragDrop: function(e, id) { /* override this */ },
431
432    /**
433     * Abstract method called when this item is dropped on an area with no
434     * drop target
435     * @method onInvalidDrop
436     * @param {Event} e the mouseup event
437     */
438    onInvalidDrop: function(e) { /* override this */ },
439
440    /**
441     * Code that executes immediately before the endDrag event
442     * @method b4EndDrag
443     * @private
444     */
445    b4EndDrag: function(e) { },
446
447    /**
448     * Fired when we are done dragging the object
449     * @method endDrag
450     * @param {Event} e the mouseup event
451     */
452    endDrag: function(e) { /* override this */ },
453
454    /**
455     * Code executed immediately before the onMouseDown event
456     * @method b4MouseDown
457     * @param {Event} e the mousedown event
458     * @private
459     */
460    b4MouseDown: function(e) {  },
461
462    /**
463     * Event handler that fires when a drag/drop obj gets a mousedown
464     * @method onMouseDown
465     * @param {Event} e the mousedown event
466     */
467    onMouseDown: function(e) { /* override this */ },
468
469    /**
470     * Event handler that fires when a drag/drop obj gets a mouseup
471     * @method onMouseUp
472     * @param {Event} e the mouseup event
473     */
474    onMouseUp: function(e) { /* override this */ },
475
476    /**
477     * Override the onAvailable method to do what is needed after the initial
478     * position was determined.
479     * @method onAvailable
480     */
481    onAvailable: function () {
482    },
483
484    /**
485     * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
486     * @type Object
487     */
488    defaultPadding : {left:0, right:0, top:0, bottom:0},
489
490    /**
491     * Initializes the drag drop object's constraints to restrict movement to a certain element.
492 *
493 * Usage:
494 <pre><code>
495 var dd = new Ext.dd.DDProxy("dragDiv1", "proxytest",
496                { dragElId: "existingProxyDiv" });
497 dd.startDrag = function(){
498     this.constrainTo("parent-id");
499 };
500 </code></pre>
501 * Or you can initalize it using the {@link Ext.Element} object:
502 <pre><code>
503 Ext.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
504     startDrag : function(){
505         this.constrainTo("parent-id");
506     }
507 });
508 </code></pre>
509     * @param {Mixed} constrainTo The element to constrain to.
510     * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
511     * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
512     * an object containing the sides to pad. For example: {right:10, bottom:10}
513     * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
514     */
515    constrainTo : function(constrainTo, pad, inContent){
516        if(typeof pad == "number"){
517            pad = {left: pad, right:pad, top:pad, bottom:pad};
518        }
519        pad = pad || this.defaultPadding;
520        var b = Ext.get(this.getEl()).getBox();
521        var ce = Ext.get(constrainTo);
522        var s = ce.getScroll();
523        var c, cd = ce.dom;
524        if(cd == document.body){
525            c = { x: s.left, y: s.top, width: Ext.lib.Dom.getViewWidth(), height: Ext.lib.Dom.getViewHeight()};
526        }else{
527            var xy = ce.getXY();
528            c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
529        }
530
531
532        var topSpace = b.y - c.y;
533        var leftSpace = b.x - c.x;
534
535        this.resetConstraints();
536        this.setXConstraint(leftSpace - (pad.left||0), // left
537                c.width - leftSpace - b.width - (pad.right||0), //right
538                                this.xTickSize
539        );
540        this.setYConstraint(topSpace - (pad.top||0), //top
541                c.height - topSpace - b.height - (pad.bottom||0), //bottom
542                                this.yTickSize
543        );
544    },
545
546    /**
547     * Returns a reference to the linked element
548     * @method getEl
549     * @return {HTMLElement} the html element
550     */
551    getEl: function() {
552        if (!this._domRef) {
553            this._domRef = Ext.getDom(this.id);
554        }
555
556        return this._domRef;
557    },
558
559    /**
560     * Returns a reference to the actual element to drag.  By default this is
561     * the same as the html element, but it can be assigned to another
562     * element. An example of this can be found in Ext.dd.DDProxy
563     * @method getDragEl
564     * @return {HTMLElement} the html element
565     */
566    getDragEl: function() {
567        return Ext.getDom(this.dragElId);
568    },
569
570    /**
571     * Sets up the DragDrop object.  Must be called in the constructor of any
572     * Ext.dd.DragDrop subclass
573     * @method init
574     * @param id the id of the linked element
575     * @param {String} sGroup the group of related items
576     * @param {object} config configuration attributes
577     */
578    init: function(id, sGroup, config) {
579        this.initTarget(id, sGroup, config);
580        Event.on(this.id, "mousedown", this.handleMouseDown, this);
581        // Event.on(this.id, "selectstart", Event.preventDefault);
582    },
583
584    /**
585     * Initializes Targeting functionality only... the object does not
586     * get a mousedown handler.
587     * @method initTarget
588     * @param id the id of the linked element
589     * @param {String} sGroup the group of related items
590     * @param {object} config configuration attributes
591     */
592    initTarget: function(id, sGroup, config) {
593
594        // configuration attributes
595        this.config = config || {};
596
597        // create a local reference to the drag and drop manager
598        this.DDM = Ext.dd.DDM;
599        // initialize the groups array
600        this.groups = {};
601
602        // assume that we have an element reference instead of an id if the
603        // parameter is not a string
604        if (typeof id !== "string") {
605            id = Ext.id(id);
606        }
607
608        // set the id
609        this.id = id;
610
611        // add to an interaction group
612        this.addToGroup((sGroup) ? sGroup : "default");
613
614        // We don't want to register this as the handle with the manager
615        // so we just set the id rather than calling the setter.
616        this.handleElId = id;
617
618        // the linked element is the element that gets dragged by default
619        this.setDragElId(id);
620
621        // by default, clicked anchors will not start drag operations.
622        this.invalidHandleTypes = { A: "A" };
623        this.invalidHandleIds = {};
624        this.invalidHandleClasses = [];
625
626        this.applyConfig();
627
628        this.handleOnAvailable();
629    },
630
631    /**
632     * Applies the configuration parameters that were passed into the constructor.
633     * This is supposed to happen at each level through the inheritance chain.  So
634     * a DDProxy implentation will execute apply config on DDProxy, DD, and
635     * DragDrop in order to get all of the parameters that are available in
636     * each object.
637     * @method applyConfig
638     */
639    applyConfig: function() {
640
641        // configurable properties:
642        //    padding, isTarget, maintainOffset, primaryButtonOnly
643        this.padding           = this.config.padding || [0, 0, 0, 0];
644        this.isTarget          = (this.config.isTarget !== false);
645        this.maintainOffset    = (this.config.maintainOffset);
646        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
647
648    },
649
650    /**
651     * Executed when the linked element is available
652     * @method handleOnAvailable
653     * @private
654     */
655    handleOnAvailable: function() {
656        this.available = true;
657        this.resetConstraints();
658        this.onAvailable();
659    },
660
661     /**
662     * Configures the padding for the target zone in px.  Effectively expands
663     * (or reduces) the virtual object size for targeting calculations.
664     * Supports css-style shorthand; if only one parameter is passed, all sides
665     * will have that padding, and if only two are passed, the top and bottom
666     * will have the first param, the left and right the second.
667     * @method setPadding
668     * @param {int} iTop    Top pad
669     * @param {int} iRight  Right pad
670     * @param {int} iBot    Bot pad
671     * @param {int} iLeft   Left pad
672     */
673    setPadding: function(iTop, iRight, iBot, iLeft) {
674        // this.padding = [iLeft, iRight, iTop, iBot];
675        if (!iRight && 0 !== iRight) {
676            this.padding = [iTop, iTop, iTop, iTop];
677        } else if (!iBot && 0 !== iBot) {
678            this.padding = [iTop, iRight, iTop, iRight];
679        } else {
680            this.padding = [iTop, iRight, iBot, iLeft];
681        }
682    },
683
684    /**
685     * Stores the initial placement of the linked element.
686     * @method setInitialPosition
687     * @param {int} diffX   the X offset, default 0
688     * @param {int} diffY   the Y offset, default 0
689     */
690    setInitPosition: function(diffX, diffY) {
691        var el = this.getEl();
692
693        if (!this.DDM.verifyEl(el)) {
694            return;
695        }
696
697        var dx = diffX || 0;
698        var dy = diffY || 0;
699
700        var p = Dom.getXY( el );
701
702        this.initPageX = p[0] - dx;
703        this.initPageY = p[1] - dy;
704
705        this.lastPageX = p[0];
706        this.lastPageY = p[1];
707
708
709        this.setStartPosition(p);
710    },
711
712    /**
713     * Sets the start position of the element.  This is set when the obj
714     * is initialized, the reset when a drag is started.
715     * @method setStartPosition
716     * @param pos current position (from previous lookup)
717     * @private
718     */
719    setStartPosition: function(pos) {
720        var p = pos || Dom.getXY( this.getEl() );
721        this.deltaSetXY = null;
722
723        this.startPageX = p[0];
724        this.startPageY = p[1];
725    },
726
727    /**
728     * Add this instance to a group of related drag/drop objects.  All
729     * instances belong to at least one group, and can belong to as many
730     * groups as needed.
731     * @method addToGroup
732     * @param sGroup {string} the name of the group
733     */
734    addToGroup: function(sGroup) {
735        this.groups[sGroup] = true;
736        this.DDM.regDragDrop(this, sGroup);
737    },
738
739    /**
740     * Remove's this instance from the supplied interaction group
741     * @method removeFromGroup
742     * @param {string}  sGroup  The group to drop
743     */
744    removeFromGroup: function(sGroup) {
745        if (this.groups[sGroup]) {
746            delete this.groups[sGroup];
747        }
748
749        this.DDM.removeDDFromGroup(this, sGroup);
750    },
751
752    /**
753     * Allows you to specify that an element other than the linked element
754     * will be moved with the cursor during a drag
755     * @method setDragElId
756     * @param id {string} the id of the element that will be used to initiate the drag
757     */
758    setDragElId: function(id) {
759        this.dragElId = id;
760    },
761
762    /**
763     * Allows you to specify a child of the linked element that should be
764     * used to initiate the drag operation.  An example of this would be if
765     * you have a content div with text and links.  Clicking anywhere in the
766     * content area would normally start the drag operation.  Use this method
767     * to specify that an element inside of the content div is the element
768     * that starts the drag operation.
769     * @method setHandleElId
770     * @param id {string} the id of the element that will be used to
771     * initiate the drag.
772     */
773    setHandleElId: function(id) {
774        if (typeof id !== "string") {
775            id = Ext.id(id);
776        }
777        this.handleElId = id;
778        this.DDM.regHandle(this.id, id);
779    },
780
781    /**
782     * Allows you to set an element outside of the linked element as a drag
783     * handle
784     * @method setOuterHandleElId
785     * @param id the id of the element that will be used to initiate the drag
786     */
787    setOuterHandleElId: function(id) {
788        if (typeof id !== "string") {
789            id = Ext.id(id);
790        }
791        Event.on(id, "mousedown",
792                this.handleMouseDown, this);
793        this.setHandleElId(id);
794
795        this.hasOuterHandles = true;
796    },
797
798    /**
799     * Remove all drag and drop hooks for this element
800     * @method unreg
801     */
802    unreg: function() {
803        Event.un(this.id, "mousedown",
804                this.handleMouseDown);
805        this._domRef = null;
806        this.DDM._remove(this);
807    },
808
809    destroy : function(){
810        this.unreg();
811    },
812
813    /**
814     * Returns true if this instance is locked, or the drag drop mgr is locked
815     * (meaning that all drag/drop is disabled on the page.)
816     * @method isLocked
817     * @return {boolean} true if this obj or all drag/drop is locked, else
818     * false
819     */
820    isLocked: function() {
821        return (this.DDM.isLocked() || this.locked);
822    },
823
824    /**
825     * Fired when this object is clicked
826     * @method handleMouseDown
827     * @param {Event} e
828     * @param {Ext.dd.DragDrop} oDD the clicked dd object (this dd obj)
829     * @private
830     */
831    handleMouseDown: function(e, oDD){
832        if (this.primaryButtonOnly && e.button != 0) {
833            return;
834        }
835
836        if (this.isLocked()) {
837            return;
838        }
839
840        this.DDM.refreshCache(this.groups);
841
842        var pt = new Ext.lib.Point(Ext.lib.Event.getPageX(e), Ext.lib.Event.getPageY(e));
843        if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
844        } else {
845            if (this.clickValidator(e)) {
846
847                // set the initial element position
848                this.setStartPosition();
849
850
851                this.b4MouseDown(e);
852                this.onMouseDown(e);
853
854                this.DDM.handleMouseDown(e, this);
855
856                this.DDM.stopEvent(e);
857            } else {
858
859
860            }
861        }
862    },
863
864    clickValidator: function(e) {
865        var target = e.getTarget();
866        return ( this.isValidHandleChild(target) &&
867                    (this.id == this.handleElId ||
868                        this.DDM.handleWasClicked(target, this.id)) );
869    },
870
871    /**
872     * Allows you to specify a tag name that should not start a drag operation
873     * when clicked.  This is designed to facilitate embedding links within a
874     * drag handle that do something other than start the drag.
875     * @method addInvalidHandleType
876     * @param {string} tagName the type of element to exclude
877     */
878    addInvalidHandleType: function(tagName) {
879        var type = tagName.toUpperCase();
880        this.invalidHandleTypes[type] = type;
881    },
882
883    /**
884     * Lets you to specify an element id for a child of a drag handle
885     * that should not initiate a drag
886     * @method addInvalidHandleId
887     * @param {string} id the element id of the element you wish to ignore
888     */
889    addInvalidHandleId: function(id) {
890        if (typeof id !== "string") {
891            id = Ext.id(id);
892        }
893        this.invalidHandleIds[id] = id;
894    },
895
896    /**
897     * Lets you specify a css class of elements that will not initiate a drag
898     * @method addInvalidHandleClass
899     * @param {string} cssClass the class of the elements you wish to ignore
900     */
901    addInvalidHandleClass: function(cssClass) {
902        this.invalidHandleClasses.push(cssClass);
903    },
904
905    /**
906     * Unsets an excluded tag name set by addInvalidHandleType
907     * @method removeInvalidHandleType
908     * @param {string} tagName the type of element to unexclude
909     */
910    removeInvalidHandleType: function(tagName) {
911        var type = tagName.toUpperCase();
912        // this.invalidHandleTypes[type] = null;
913        delete this.invalidHandleTypes[type];
914    },
915
916    /**
917     * Unsets an invalid handle id
918     * @method removeInvalidHandleId
919     * @param {string} id the id of the element to re-enable
920     */
921    removeInvalidHandleId: function(id) {
922        if (typeof id !== "string") {
923            id = Ext.id(id);
924        }
925        delete this.invalidHandleIds[id];
926    },
927
928    /**
929     * Unsets an invalid css class
930     * @method removeInvalidHandleClass
931     * @param {string} cssClass the class of the element(s) you wish to
932     * re-enable
933     */
934    removeInvalidHandleClass: function(cssClass) {
935        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
936            if (this.invalidHandleClasses[i] == cssClass) {
937                delete this.invalidHandleClasses[i];
938            }
939        }
940    },
941
942    /**
943     * Checks the tag exclusion list to see if this click should be ignored
944     * @method isValidHandleChild
945     * @param {HTMLElement} node the HTMLElement to evaluate
946     * @return {boolean} true if this is a valid tag type, false if not
947     */
948    isValidHandleChild: function(node) {
949
950        var valid = true;
951        // var n = (node.nodeName == "#text") ? node.parentNode : node;
952        var nodeName;
953        try {
954            nodeName = node.nodeName.toUpperCase();
955        } catch(e) {
956            nodeName = node.nodeName;
957        }
958        valid = valid && !this.invalidHandleTypes[nodeName];
959        valid = valid && !this.invalidHandleIds[node.id];
960
961        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
962            valid = !Ext.fly(node).hasClass(this.invalidHandleClasses[i]);
963        }
964
965
966        return valid;
967
968    },
969
970    /**
971     * Create the array of horizontal tick marks if an interval was specified
972     * in setXConstraint().
973     * @method setXTicks
974     * @private
975     */
976    setXTicks: function(iStartX, iTickSize) {
977        this.xTicks = [];
978        this.xTickSize = iTickSize;
979
980        var tickMap = {};
981
982        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
983            if (!tickMap[i]) {
984                this.xTicks[this.xTicks.length] = i;
985                tickMap[i] = true;
986            }
987        }
988
989        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
990            if (!tickMap[i]) {
991                this.xTicks[this.xTicks.length] = i;
992                tickMap[i] = true;
993            }
994        }
995
996        this.xTicks.sort(this.DDM.numericSort) ;
997    },
998
999    /**
1000     * Create the array of vertical tick marks if an interval was specified in
1001     * setYConstraint().
1002     * @method setYTicks
1003     * @private
1004     */
1005    setYTicks: function(iStartY, iTickSize) {
1006        this.yTicks = [];
1007        this.yTickSize = iTickSize;
1008
1009        var tickMap = {};
1010
1011        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1012            if (!tickMap[i]) {
1013                this.yTicks[this.yTicks.length] = i;
1014                tickMap[i] = true;
1015            }
1016        }
1017
1018        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1019            if (!tickMap[i]) {
1020                this.yTicks[this.yTicks.length] = i;
1021                tickMap[i] = true;
1022            }
1023        }
1024
1025        this.yTicks.sort(this.DDM.numericSort) ;
1026    },
1027
1028    /**
1029     * By default, the element can be dragged any place on the screen.  Use
1030     * this method to limit the horizontal travel of the element.  Pass in
1031     * 0,0 for the parameters if you want to lock the drag to the y axis.
1032     * @method setXConstraint
1033     * @param {int} iLeft the number of pixels the element can move to the left
1034     * @param {int} iRight the number of pixels the element can move to the
1035     * right
1036     * @param {int} iTickSize optional parameter for specifying that the
1037     * element
1038     * should move iTickSize pixels at a time.
1039     */
1040    setXConstraint: function(iLeft, iRight, iTickSize) {
1041        this.leftConstraint = iLeft;
1042        this.rightConstraint = iRight;
1043
1044        this.minX = this.initPageX - iLeft;
1045        this.maxX = this.initPageX + iRight;
1046        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1047
1048        this.constrainX = true;
1049    },
1050
1051    /**
1052     * Clears any constraints applied to this instance.  Also clears ticks
1053     * since they can't exist independent of a constraint at this time.
1054     * @method clearConstraints
1055     */
1056    clearConstraints: function() {
1057        this.constrainX = false;
1058        this.constrainY = false;
1059        this.clearTicks();
1060    },
1061
1062    /**
1063     * Clears any tick interval defined for this instance
1064     * @method clearTicks
1065     */
1066    clearTicks: function() {
1067        this.xTicks = null;
1068        this.yTicks = null;
1069        this.xTickSize = 0;
1070        this.yTickSize = 0;
1071    },
1072
1073    /**
1074     * By default, the element can be dragged any place on the screen.  Set
1075     * this to limit the vertical travel of the element.  Pass in 0,0 for the
1076     * parameters if you want to lock the drag to the x axis.
1077     * @method setYConstraint
1078     * @param {int} iUp the number of pixels the element can move up
1079     * @param {int} iDown the number of pixels the element can move down
1080     * @param {int} iTickSize optional parameter for specifying that the
1081     * element should move iTickSize pixels at a time.
1082     */
1083    setYConstraint: function(iUp, iDown, iTickSize) {
1084        this.topConstraint = iUp;
1085        this.bottomConstraint = iDown;
1086
1087        this.minY = this.initPageY - iUp;
1088        this.maxY = this.initPageY + iDown;
1089        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1090
1091        this.constrainY = true;
1092
1093    },
1094
1095    /**
1096     * resetConstraints must be called if you manually reposition a dd element.
1097     * @method resetConstraints
1098     * @param {boolean} maintainOffset
1099     */
1100    resetConstraints: function() {
1101
1102
1103        // Maintain offsets if necessary
1104        if (this.initPageX || this.initPageX === 0) {
1105            // figure out how much this thing has moved
1106            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1107            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1108
1109            this.setInitPosition(dx, dy);
1110
1111        // This is the first time we have detected the element's position
1112        } else {
1113            this.setInitPosition();
1114        }
1115
1116        if (this.constrainX) {
1117            this.setXConstraint( this.leftConstraint,
1118                                 this.rightConstraint,
1119                                 this.xTickSize        );
1120        }
1121
1122        if (this.constrainY) {
1123            this.setYConstraint( this.topConstraint,
1124                                 this.bottomConstraint,
1125                                 this.yTickSize         );
1126        }
1127    },
1128
1129    /**
1130     * Normally the drag element is moved pixel by pixel, but we can specify
1131     * that it move a number of pixels at a time.  This method resolves the
1132     * location when we have it set up like this.
1133     * @method getTick
1134     * @param {int} val where we want to place the object
1135     * @param {int[]} tickArray sorted array of valid points
1136     * @return {int} the closest tick
1137     * @private
1138     */
1139    getTick: function(val, tickArray) {
1140
1141        if (!tickArray) {
1142            // If tick interval is not defined, it is effectively 1 pixel,
1143            // so we return the value passed to us.
1144            return val;
1145        } else if (tickArray[0] >= val) {
1146            // The value is lower than the first tick, so we return the first
1147            // tick.
1148            return tickArray[0];
1149        } else {
1150            for (var i=0, len=tickArray.length; i<len; ++i) {
1151                var next = i + 1;
1152                if (tickArray[next] && tickArray[next] >= val) {
1153                    var diff1 = val - tickArray[i];
1154                    var diff2 = tickArray[next] - val;
1155                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1156                }
1157            }
1158
1159            // The value is larger than the last tick, so we return the last
1160            // tick.
1161            return tickArray[tickArray.length - 1];
1162        }
1163    },
1164
1165    /**
1166     * toString method
1167     * @method toString
1168     * @return {string} string representation of the dd obj
1169     */
1170    toString: function() {
1171        return ("DragDrop " + this.id);
1172    }
1173
1174};
1175
1176})();
1177/**
1178 * The drag and drop utility provides a framework for building drag and drop
1179 * applications.  In addition to enabling drag and drop for specific elements,
1180 * the drag and drop elements are tracked by the manager class, and the
1181 * interactions between the various elements are tracked during the drag and
1182 * the implementing code is notified about these important moments.
1183 */
1184
1185// Only load the library once.  Rewriting the manager class would orphan
1186// existing drag and drop instances.
1187if (!Ext.dd.DragDropMgr) {
1188
1189/**
1190 * @class Ext.dd.DragDropMgr
1191 * DragDropMgr is a singleton that tracks the element interaction for
1192 * all DragDrop items in the window.  Generally, you will not call
1193 * this class directly, but it does have helper methods that could
1194 * be useful in your DragDrop implementations.
1195 * @singleton
1196 */
1197Ext.dd.DragDropMgr = function() {
1198
1199    var Event = Ext.EventManager;
1200
1201    return {
1202
1203        /**
1204         * Two dimensional Array of registered DragDrop objects.  The first
1205         * dimension is the DragDrop item group, the second the DragDrop
1206         * object.
1207         * @property ids
1208         * @type {string: string}
1209         * @private
1210         * @static
1211         */
1212        ids: {},
1213
1214        /**
1215         * Array of element ids defined as drag handles.  Used to determine
1216         * if the element that generated the mousedown event is actually the
1217         * handle and not the html element itself.
1218         * @property handleIds
1219         * @type {string: string}
1220         * @private
1221         * @static
1222         */
1223        handleIds: {},
1224
1225        /**
1226         * the DragDrop object that is currently being dragged
1227         * @property dragCurrent
1228         * @type DragDrop
1229         * @private
1230         * @static
1231         **/
1232        dragCurrent: null,
1233
1234        /**
1235         * the DragDrop object(s) that are being hovered over
1236         * @property dragOvers
1237         * @type Array
1238         * @private
1239         * @static
1240         */
1241        dragOvers: {},
1242
1243        /**
1244         * the X distance between the cursor and the object being dragged
1245         * @property deltaX
1246         * @type int
1247         * @private
1248         * @static
1249         */
1250        deltaX: 0,
1251
1252        /**
1253         * the Y distance between the cursor and the object being dragged
1254         * @property deltaY
1255         * @type int
1256         * @private
1257         * @static
1258         */
1259        deltaY: 0,
1260
1261        /**
1262         * Flag to determine if we should prevent the default behavior of the
1263         * events we define. By default this is true, but this can be set to
1264         * false if you need the default behavior (not recommended)
1265         * @property preventDefault
1266         * @type boolean
1267         * @static
1268         */
1269        preventDefault: true,
1270
1271        /**
1272         * Flag to determine if we should stop the propagation of the events
1273         * we generate. This is true by default but you may want to set it to
1274         * false if the html element contains other features that require the
1275         * mouse click.
1276         * @property stopPropagation
1277         * @type boolean
1278         * @static
1279         */
1280        stopPropagation: true,
1281
1282        /**
1283         * Internal flag that is set to true when drag and drop has been
1284         * intialized
1285         * @property initialized
1286         * @private
1287         * @static
1288         */
1289        initialized: false,
1290
1291        /**
1292         * All drag and drop can be disabled.
1293         * @property locked
1294         * @private
1295         * @static
1296         */
1297        locked: false,
1298
1299        /**
1300         * Called the first time an element is registered.
1301         * @method init
1302         * @private
1303         * @static
1304         */
1305        init: function() {
1306            this.initialized = true;
1307        },
1308
1309        /**
1310         * In point mode, drag and drop interaction is defined by the
1311         * location of the cursor during the drag/drop
1312         * @property POINT
1313         * @type int
1314         * @static
1315         */
1316        POINT: 0,
1317
1318        /**
1319         * In intersect mode, drag and drop interaction is defined by the
1320         * overlap of two or more drag and drop objects.
1321         * @property INTERSECT
1322         * @type int
1323         * @static
1324         */
1325        INTERSECT: 1,
1326
1327        /**
1328         * The current drag and drop mode.  Default: POINT
1329         * @property mode
1330         * @type int
1331         * @static
1332         */
1333        mode: 0,
1334
1335        /**
1336         * Runs method on all drag and drop objects
1337         * @method _execOnAll
1338         * @private
1339         * @static
1340         */
1341        _execOnAll: function(sMethod, args) {
1342            for (var i in this.ids) {
1343                for (var j in this.ids[i]) {
1344                    var oDD = this.ids[i][j];
1345                    if (! this.isTypeOfDD(oDD)) {
1346                        continue;
1347                    }
1348                    oDD[sMethod].apply(oDD, args);
1349                }
1350            }
1351        },
1352
1353        /**
1354         * Drag and drop initialization.  Sets up the global event handlers
1355         * @method _onLoad
1356         * @private
1357         * @static
1358         */
1359        _onLoad: function() {
1360
1361            this.init();
1362
1363
1364            Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1365            Event.on(document, "mousemove", this.handleMouseMove, this, true);
1366            Event.on(window,   "unload",    this._onUnload, this, true);
1367            Event.on(window,   "resize",    this._onResize, this, true);
1368            // Event.on(window,   "mouseout",    this._test);
1369
1370        },
1371
1372        /**
1373         * Reset constraints on all drag and drop objs
1374         * @method _onResize
1375         * @private
1376         * @static
1377         */
1378        _onResize: function(e) {
1379            this._execOnAll("resetConstraints", []);
1380        },
1381
1382        /**
1383         * Lock all drag and drop functionality
1384         * @method lock
1385         * @static
1386         */
1387        lock: function() { this.locked = true; },
1388
1389        /**
1390         * Unlock all drag and drop functionality
1391         * @method unlock
1392         * @static
1393         */
1394        unlock: function() { this.locked = false; },
1395
1396        /**
1397         * Is drag and drop locked?
1398         * @method isLocked
1399         * @return {boolean} True if drag and drop is locked, false otherwise.
1400         * @static
1401         */
1402        isLocked: function() { return this.locked; },
1403
1404        /**
1405         * Location cache that is set for all drag drop objects when a drag is
1406         * initiated, cleared when the drag is finished.
1407         * @property locationCache
1408         * @private
1409         * @static
1410         */
1411        locationCache: {},
1412
1413        /**
1414         * Set useCache to false if you want to force object the lookup of each
1415         * drag and drop linked element constantly during a drag.
1416         * @property useCache
1417         * @type boolean
1418         * @static
1419         */
1420        useCache: true,
1421
1422        /**
1423         * The number of pixels that the mouse needs to move after the
1424         * mousedown before the drag is initiated.  Default=3;
1425         * @property clickPixelThresh
1426         * @type int
1427         * @static
1428         */
1429        clickPixelThresh: 3,
1430
1431        /**
1432         * The number of milliseconds after the mousedown event to initiate the
1433         * drag if we don't get a mouseup event. Default=1000
1434         * @property clickTimeThresh
1435         * @type int
1436         * @static
1437         */
1438        clickTimeThresh: 350,
1439
1440        /**
1441         * Flag that indicates that either the drag pixel threshold or the
1442         * mousdown time threshold has been met
1443         * @property dragThreshMet
1444         * @type boolean
1445         * @private
1446         * @static
1447         */
1448        dragThreshMet: false,
1449
1450        /**
1451         * Timeout used for the click time threshold
1452         * @property clickTimeout
1453         * @type Object
1454         * @private
1455         * @static
1456         */
1457        clickTimeout: null,
1458
1459        /**
1460         * The X position of the mousedown event stored for later use when a
1461         * drag threshold is met.
1462         * @property startX
1463         * @type int
1464         * @private
1465         * @static
1466         */
1467        startX: 0,
1468
1469        /**
1470         * The Y position of the mousedown event stored for later use when a
1471         * drag threshold is met.
1472         * @property startY
1473         * @type int
1474         * @private
1475         * @static
1476         */
1477        startY: 0,
1478
1479        /**
1480         * Each DragDrop instance must be registered with the DragDropMgr.
1481         * This is executed in DragDrop.init()
1482         * @method regDragDrop
1483         * @param {DragDrop} oDD the DragDrop object to register
1484         * @param {String} sGroup the name of the group this element belongs to
1485         * @static
1486         */
1487        regDragDrop: function(oDD, sGroup) {
1488            if (!this.initialized) { this.init(); }
1489
1490            if (!this.ids[sGroup]) {
1491                this.ids[sGroup] = {};
1492            }
1493            this.ids[sGroup][oDD.id] = oDD;
1494        },
1495
1496        /**
1497         * Removes the supplied dd instance from the supplied group. Executed
1498         * by DragDrop.removeFromGroup, so don't call this function directly.
1499         * @method removeDDFromGroup
1500         * @private
1501         * @static
1502         */
1503        removeDDFromGroup: function(oDD, sGroup) {
1504            if (!this.ids[sGroup]) {
1505                this.ids[sGroup] = {};
1506            }
1507
1508            var obj = this.ids[sGroup];
1509            if (obj && obj[oDD.id]) {
1510                delete obj[oDD.id];
1511            }
1512        },
1513
1514        /**
1515         * Unregisters a drag and drop item.  This is executed in
1516         * DragDrop.unreg, use that method instead of calling this directly.
1517         * @method _remove
1518         * @private
1519         * @static
1520         */
1521        _remove: function(oDD) {
1522            for (var g in oDD.groups) {
1523                if (g && this.ids[g] && this.ids[g][oDD.id]) {
1524                    delete this.ids[g][oDD.id];
1525                }
1526            }
1527            delete this.handleIds[oDD.id];
1528        },
1529
1530        /**
1531         * Each DragDrop handle element must be registered.  This is done
1532         * automatically when executing DragDrop.setHandleElId()
1533         * @method regHandle
1534         * @param {String} sDDId the DragDrop id this element is a handle for
1535         * @param {String} sHandleId the id of the element that is the drag
1536         * handle
1537         * @static
1538         */
1539        regHandle: function(sDDId, sHandleId) {
1540            if (!this.handleIds[sDDId]) {
1541                this.handleIds[sDDId] = {};
1542            }
1543            this.handleIds[sDDId][sHandleId] = sHandleId;
1544        },
1545
1546        /**
1547         * Utility function to determine if a given element has been
1548         * registered as a drag drop item.
1549         * @method isDragDrop
1550         * @param {String} id the element id to check
1551         * @return {boolean} true if this element is a DragDrop item,
1552         * false otherwise
1553         * @static
1554         */
1555        isDragDrop: function(id) {
1556            return ( this.getDDById(id) ) ? true : false;
1557        },
1558
1559        /**
1560         * Returns the drag and drop instances that are in all groups the
1561         * passed in instance belongs to.
1562         * @method getRelated
1563         * @param {DragDrop} p_oDD the obj to get related data for
1564         * @param {boolean} bTargetsOnly if true, only return targetable objs
1565         * @return {DragDrop[]} the related instances
1566         * @static
1567         */
1568        getRelated: function(p_oDD, bTargetsOnly) {
1569            var oDDs = [];
1570            for (var i in p_oDD.groups) {
1571                for (j in this.ids[i]) {
1572                    var dd = this.ids[i][j];
1573                    if (! this.isTypeOfDD(dd)) {
1574                        continue;
1575                    }
1576                    if (!bTargetsOnly || dd.isTarget) {
1577                        oDDs[oDDs.length] = dd;
1578                    }
1579                }
1580            }
1581
1582            return oDDs;
1583        },
1584
1585        /**
1586         * Returns true if the specified dd target is a legal target for
1587         * the specifice drag obj
1588         * @method isLegalTarget
1589         * @param {DragDrop} the drag obj
1590         * @param {DragDrop} the target
1591         * @return {boolean} true if the target is a legal target for the
1592         * dd obj
1593         * @static
1594         */
1595        isLegalTarget: function (oDD, oTargetDD) {
1596            var targets = this.getRelated(oDD, true);
1597            for (var i=0, len=targets.length;i<len;++i) {
1598                if (targets[i].id == oTargetDD.id) {
1599                    return true;
1600                }
1601            }
1602
1603            return false;
1604        },
1605
1606        /**
1607         * My goal is to be able to transparently determine if an object is
1608         * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1609         * returns "object", oDD.constructor.toString() always returns
1610         * "DragDrop" and not the name of the subclass.  So for now it just
1611         * evaluates a well-known variable in DragDrop.
1612         * @method isTypeOfDD
1613         * @param {Object} the object to evaluate
1614         * @return {boolean} true if typeof oDD = DragDrop
1615         * @static
1616         */
1617        isTypeOfDD: function (oDD) {
1618            return (oDD && oDD.__ygDragDrop);
1619        },
1620
1621        /**
1622         * Utility function to determine if a given element has been
1623         * registered as a drag drop handle for the given Drag Drop object.
1624         * @method isHandle
1625         * @param {String} id the element id to check
1626         * @return {boolean} true if this element is a DragDrop handle, false
1627         * otherwise
1628         * @static
1629         */
1630        isHandle: function(sDDId, sHandleId) {
1631            return ( this.handleIds[sDDId] &&
1632                            this.handleIds[sDDId][sHandleId] );
1633        },
1634
1635        /**
1636         * Returns the DragDrop instance for a given id
1637         * @method getDDById
1638         * @param {String} id the id of the DragDrop object
1639         * @return {DragDrop} the drag drop object, null if it is not found
1640         * @static
1641         */
1642        getDDById: function(id) {
1643            for (var i in this.ids) {
1644                if (this.ids[i][id]) {
1645                    return this.ids[i][id];
1646                }
1647            }
1648            return null;
1649        },
1650
1651        /**
1652         * Fired after a registered DragDrop object gets the mousedown event.
1653         * Sets up the events required to track the object being dragged
1654         * @method handleMouseDown
1655         * @param {Event} e the event
1656         * @param oDD the DragDrop object being dragged
1657         * @private
1658         * @static
1659         */
1660        handleMouseDown: function(e, oDD) {
1661            if(Ext.QuickTips){
1662                Ext.QuickTips.disable();
1663            }
1664            if(this.dragCurrent){
1665                // the original browser mouseup wasn't handled (e.g. outside FF browser window)
1666                // so clean up first to avoid breaking the next drag
1667                this.handleMouseUp(e);
1668            }
1669           
1670            this.currentTarget = e.getTarget();
1671            this.dragCurrent = oDD;
1672
1673            var el = oDD.getEl();
1674
1675            // track start position
1676            this.startX = e.getPageX();
1677            this.startY = e.getPageY();
1678
1679            this.deltaX = this.startX - el.offsetLeft;
1680            this.deltaY = this.startY - el.offsetTop;
1681
1682            this.dragThreshMet = false;
1683
1684            this.clickTimeout = setTimeout(
1685                    function() {
1686                        var DDM = Ext.dd.DDM;
1687                        DDM.startDrag(DDM.startX, DDM.startY);
1688                    },
1689                    this.clickTimeThresh );
1690        },
1691
1692        /**
1693         * Fired when either the drag pixel threshol or the mousedown hold
1694         * time threshold has been met.
1695         * @method startDrag
1696         * @param x {int} the X position of the original mousedown
1697         * @param y {int} the Y position of the original mousedown
1698         * @static
1699         */
1700        startDrag: function(x, y) {
1701            clearTimeout(this.clickTimeout);
1702            if (this.dragCurrent) {
1703                this.dragCurrent.b4StartDrag(x, y);
1704                this.dragCurrent.startDrag(x, y);
1705            }
1706            this.dragThreshMet = true;
1707        },
1708
1709        /**
1710         * Internal function to handle the mouseup event.  Will be invoked
1711         * from the context of the document.
1712         * @method handleMouseUp
1713         * @param {Event} e the event
1714         * @private
1715         * @static
1716         */
1717        handleMouseUp: function(e) {
1718
1719            if(Ext.QuickTips){
1720                Ext.QuickTips.enable();
1721            }
1722            if (! this.dragCurrent) {
1723                return;
1724            }
1725
1726            clearTimeout(this.clickTimeout);
1727
1728            if (this.dragThreshMet) {
1729                this.fireEvents(e, true);
1730            } else {
1731            }
1732
1733            this.stopDrag(e);
1734
1735            this.stopEvent(e);
1736        },
1737
1738        /**
1739         * Utility to stop event propagation and event default, if these
1740         * features are turned on.
1741         * @method stopEvent
1742         * @param {Event} e the event as returned by this.getEvent()
1743         * @static
1744         */
1745        stopEvent: function(e){
1746            if(this.stopPropagation) {
1747                e.stopPropagation();
1748            }
1749
1750            if (this.preventDefault) {
1751                e.preventDefault();
1752            }
1753        },
1754
1755        /**
1756         * Internal function to clean up event handlers after the drag
1757         * operation is complete
1758         * @method stopDrag
1759         * @param {Event} e the event
1760         * @private
1761         * @static
1762         */
1763        stopDrag: function(e) {
1764            // Fire the drag end event for the item that was dragged
1765            if (this.dragCurrent) {
1766                if (this.dragThreshMet) {
1767                    this.dragCurrent.b4EndDrag(e);
1768                    this.dragCurrent.endDrag(e);
1769                }
1770
1771                this.dragCurrent.onMouseUp(e);
1772            }
1773
1774            this.dragCurrent = null;
1775            this.dragOvers = {};
1776        },
1777
1778        /**
1779         * Internal function to handle the mousemove event.  Will be invoked
1780         * from the context of the html element.
1781         *
1782         * @TODO figure out what we can do about mouse events lost when the
1783         * user drags objects beyond the window boundary.  Currently we can
1784         * detect this in internet explorer by verifying that the mouse is
1785         * down during the mousemove event.  Firefox doesn't give us the
1786         * button state on the mousemove event.
1787         * @method handleMouseMove
1788         * @param {Event} e the event
1789         * @private
1790         * @static
1791         */
1792        handleMouseMove: function(e) {
1793            if (! this.dragCurrent) {
1794                return true;
1795            }
1796
1797            // var button = e.which || e.button;
1798
1799            // check for IE mouseup outside of page boundary
1800            if (Ext.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801                this.stopEvent(e);
1802                return this.handleMouseUp(e);
1803            }
1804
1805            if (!this.dragThreshMet) {
1806                var diffX = Math.abs(this.startX - e.getPageX());
1807                var diffY = Math.abs(this.startY - e.getPageY());
1808                if (diffX > this.clickPixelThresh ||
1809                            diffY > this.clickPixelThresh) {
1810                    this.startDrag(this.startX, this.startY);
1811                }
1812            }
1813
1814            if (this.dragThreshMet) {
1815                this.dragCurrent.b4Drag(e);
1816                this.dragCurrent.onDrag(e);
1817                if(!this.dragCurrent.moveOnly){
1818                    this.fireEvents(e, false);
1819                }
1820            }
1821
1822            this.stopEvent(e);
1823
1824            return true;
1825        },
1826
1827        /**
1828         * Iterates over all of the DragDrop elements to find ones we are
1829         * hovering over or dropping on
1830         * @method fireEvents
1831         * @param {Event} e the event
1832         * @param {boolean} isDrop is this a drop op or a mouseover op?
1833         * @private
1834         * @static
1835         */
1836        fireEvents: function(e, isDrop) {
1837            var dc = this.dragCurrent;
1838
1839            // If the user did the mouse up outside of the window, we could
1840            // get here even though we have ended the drag.
1841            if (!dc || dc.isLocked()) {
1842                return;
1843            }
1844
1845            var pt = e.getPoint();
1846
1847            // cache the previous dragOver array
1848            var oldOvers = [];
1849
1850            var outEvts   = [];
1851            var overEvts  = [];
1852            var dropEvts  = [];
1853            var enterEvts = [];
1854
1855            // Check to see if the object(s) we were hovering over is no longer
1856            // being hovered over so we can fire the onDragOut event
1857            for (var i in this.dragOvers) {
1858
1859                var ddo = this.dragOvers[i];
1860
1861                if (! this.isTypeOfDD(ddo)) {
1862                    continue;
1863                }
1864
1865                if (! this.isOverTarget(pt, ddo, this.mode)) {
1866                    outEvts.push( ddo );
1867                }
1868
1869                oldOvers[i] = true;
1870                delete this.dragOvers[i];
1871            }
1872
1873            for (var sGroup in dc.groups) {
1874
1875                if ("string" != typeof sGroup) {
1876                    continue;
1877                }
1878
1879                for (i in this.ids[sGroup]) {
1880                    var oDD = this.ids[sGroup][i];
1881                    if (! this.isTypeOfDD(oDD)) {
1882                        continue;
1883                    }
1884
1885                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1886                        if (this.isOverTarget(pt, oDD, this.mode)) {
1887                            // look for drop interactions
1888                            if (isDrop) {
1889                                dropEvts.push( oDD );
1890                            // look for drag enter and drag over interactions
1891                            } else {
1892
1893                                // initial drag over: dragEnter fires
1894                                if (!oldOvers[oDD.id]) {
1895                                    enterEvts.push( oDD );
1896                                // subsequent drag overs: dragOver fires
1897                                } else {
1898                                    overEvts.push( oDD );
1899                                }
1900
1901                                this.dragOvers[oDD.id] = oDD;
1902                            }
1903                        }
1904                    }
1905                }
1906            }
1907
1908            if (this.mode) {
1909                if (outEvts.length) {
1910                    dc.b4DragOut(e, outEvts);
1911                    dc.onDragOut(e, outEvts);
1912                }
1913
1914                if (enterEvts.length) {
1915                    dc.onDragEnter(e, enterEvts);
1916                }
1917
1918                if (overEvts.length) {
1919                    dc.b4DragOver(e, overEvts);
1920                    dc.onDragOver(e, overEvts);
1921                }
1922
1923                if (dropEvts.length) {
1924                    dc.b4DragDrop(e, dropEvts);
1925                    dc.onDragDrop(e, dropEvts);
1926                }
1927
1928            } else {
1929                // fire dragout events
1930                var len = 0;
1931                for (i=0, len=outEvts.length; i<len; ++i) {
1932                    dc.b4DragOut(e, outEvts[i].id);
1933                    dc.onDragOut(e, outEvts[i].id);
1934                }
1935
1936                // fire enter events
1937                for (i=0,len=enterEvts.length; i<len; ++i) {
1938                    // dc.b4DragEnter(e, oDD.id);
1939                    dc.onDragEnter(e, enterEvts[i].id);
1940                }
1941
1942                // fire over events
1943                for (i=0,len=overEvts.length; i<len; ++i) {
1944                    dc.b4DragOver(e, overEvts[i].id);
1945                    dc.onDragOver(e, overEvts[i].id);
1946                }
1947
1948                // fire drop events
1949                for (i=0, len=dropEvts.length; i<len; ++i) {
1950                    dc.b4DragDrop(e, dropEvts[i].id);
1951                    dc.onDragDrop(e, dropEvts[i].id);
1952                }
1953
1954            }
1955
1956            // notify about a drop that did not find a target
1957            if (isDrop && !dropEvts.length) {
1958                dc.onInvalidDrop(e);
1959            }
1960
1961        },
1962
1963        /**
1964         * Helper function for getting the best match from the list of drag
1965         * and drop objects returned by the drag and drop events when we are
1966         * in INTERSECT mode.  It returns either the first object that the
1967         * cursor is over, or the object that has the greatest overlap with
1968         * the dragged element.
1969         * @method getBestMatch
1970         * @param  {DragDrop[]} dds The array of drag and drop objects
1971         * targeted
1972         * @return {DragDrop}       The best single match
1973         * @static
1974         */
1975        getBestMatch: function(dds) {
1976            var winner = null;
1977            // Return null if the input is not what we expect
1978            //if (!dds || !dds.length || dds.length == 0) {
1979               // winner = null;
1980            // If there is only one item, it wins
1981            //} else if (dds.length == 1) {
1982
1983            var len = dds.length;
1984
1985            if (len == 1) {
1986                winner = dds[0];
1987            } else {
1988                // Loop through the targeted items
1989                for (var i=0; i<len; ++i) {
1990                    var dd = dds[i];
1991                    // If the cursor is over the object, it wins.  If the
1992                    // cursor is over multiple matches, the first one we come
1993                    // to wins.
1994                    if (dd.cursorIsOver) {
1995                        winner = dd;
1996                        break;
1997                    // Otherwise the object with the most overlap wins
1998                    } else {
1999                        if (!winner ||
2000                            winner.overlap.getArea() < dd.overlap.getArea()) {
2001                            winner = dd;
2002                        }
2003                    }
2004                }
2005            }
2006
2007            return winner;
2008        },
2009
2010        /**
2011         * Refreshes the cache of the top-left and bottom-right points of the
2012         * drag and drop objects in the specified group(s).  This is in the
2013         * format that is stored in the drag and drop instance, so typical
2014         * usage is:
2015         * <code>
2016         * Ext.dd.DragDropMgr.refreshCache(ddinstance.groups);
2017         * </code>
2018         * Alternatively:
2019         * <code>
2020         * Ext.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021         * </code>
2022         * @TODO this really should be an indexed array.  Alternatively this
2023         * method could accept both.
2024         * @method refreshCache
2025         * @param {Object} groups an associative array of groups to refresh
2026         * @static
2027         */
2028        refreshCache: function(groups) {
2029            for (var sGroup in groups) {
2030                if ("string" != typeof sGroup) {
2031                    continue;
2032                }
2033                for (var i in this.ids[sGroup]) {
2034                    var oDD = this.ids[sGroup][i];
2035
2036                    if (this.isTypeOfDD(oDD)) {
2037                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2038                        var loc = this.getLocation(oDD);
2039                        if (loc) {
2040                            this.locationCache[oDD.id] = loc;
2041                        } else {
2042                            delete this.locationCache[oDD.id];
2043                            // this will unregister the drag and drop object if
2044                            // the element is not in a usable state
2045                            // oDD.unreg();
2046                        }
2047                    }
2048                }
2049            }
2050        },
2051
2052        /**
2053         * This checks to make sure an element exists and is in the DOM.  The
2054         * main purpose is to handle cases where innerHTML is used to remove
2055         * drag and drop objects from the DOM.  IE provides an 'unspecified
2056         * error' when trying to access the offsetParent of such an element
2057         * @method verifyEl
2058         * @param {HTMLElement} el the element to check
2059         * @return {boolean} true if the element looks usable
2060         * @static
2061         */
2062        verifyEl: function(el) {
2063            if (el) {
2064                var parent;
2065                if(Ext.isIE){
2066                    try{
2067                        parent = el.offsetParent;
2068                    }catch(e){}
2069                }else{
2070                    parent = el.offsetParent;
2071                }
2072                if (parent) {
2073                    return true;
2074                }
2075            }
2076
2077            return false;
2078        },
2079
2080        /**
2081         * Returns a Region object containing the drag and drop element's position
2082         * and size, including the padding configured for it
2083         * @method getLocation
2084         * @param {DragDrop} oDD the drag and drop object to get the
2085         *                       location for
2086         * @return {Ext.lib.Region} a Region object representing the total area
2087         *                             the element occupies, including any padding
2088         *                             the instance is configured for.
2089         * @static
2090         */
2091        getLocation: function(oDD) {
2092            if (! this.isTypeOfDD(oDD)) {
2093                return null;
2094            }
2095
2096            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2097
2098            try {
2099                pos= Ext.lib.Dom.getXY(el);
2100            } catch (e) { }
2101
2102            if (!pos) {
2103                return null;
2104            }
2105
2106            x1 = pos[0];
2107            x2 = x1 + el.offsetWidth;
2108            y1 = pos[1];
2109            y2 = y1 + el.offsetHeight;
2110
2111            t = y1 - oDD.padding[0];
2112            r = x2 + oDD.padding[1];
2113            b = y2 + oDD.padding[2];
2114            l = x1 - oDD.padding[3];
2115
2116            return new Ext.lib.Region( t, r, b, l );
2117        },
2118
2119        /**
2120         * Checks the cursor location to see if it over the target
2121         * @method isOverTarget
2122         * @param {Ext.lib.Point} pt The point to evaluate
2123         * @param {DragDrop} oTarget the DragDrop object we are inspecting
2124         * @return {boolean} true if the mouse is over the target
2125         * @private
2126         * @static
2127         */
2128        isOverTarget: function(pt, oTarget, intersect) {
2129            // use cache if available
2130            var loc = this.locationCache[oTarget.id];
2131            if (!loc || !this.useCache) {
2132                loc = this.getLocation(oTarget);
2133                this.locationCache[oTarget.id] = loc;
2134
2135            }
2136
2137            if (!loc) {
2138                return false;
2139            }
2140
2141            oTarget.cursorIsOver = loc.contains( pt );
2142
2143            // DragDrop is using this as a sanity check for the initial mousedown
2144            // in this case we are done.  In POINT mode, if the drag obj has no
2145            // contraints, we are also done. Otherwise we need to evaluate the
2146            // location of the target as related to the actual location of the
2147            // dragged element.
2148            var dc = this.dragCurrent;
2149            if (!dc || !dc.getTargetCoord ||
2150                    (!intersect && !dc.constrainX && !dc.constrainY)) {
2151                return oTarget.cursorIsOver;
2152            }
2153
2154            oTarget.overlap = null;
2155
2156            // Get the current location of the drag element, this is the
2157            // location of the mouse event less the delta that represents
2158            // where the original mousedown happened on the element.  We
2159            // need to consider constraints and ticks as well.
2160            var pos = dc.getTargetCoord(pt.x, pt.y);
2161
2162            var el = dc.getDragEl();
2163            var curRegion = new Ext.lib.Region( pos.y,
2164                                                   pos.x + el.offsetWidth,
2165                                                   pos.y + el.offsetHeight,
2166                                                   pos.x );
2167
2168            var overlap = curRegion.intersect(loc);
2169
2170            if (overlap) {
2171                oTarget.overlap = overlap;
2172                return (intersect) ? true : oTarget.cursorIsOver;
2173            } else {
2174                return false;
2175            }
2176        },
2177
2178        /**
2179         * unload event handler
2180         * @method _onUnload
2181         * @private
2182         * @static
2183         */
2184        _onUnload: function(e, me) {
2185            Ext.dd.DragDropMgr.unregAll();
2186        },
2187
2188        /**
2189         * Cleans up the drag and drop events and objects.
2190         * @method unregAll
2191         * @private
2192         * @static
2193         */
2194        unregAll: function() {
2195
2196            if (this.dragCurrent) {
2197                this.stopDrag();
2198                this.dragCurrent = null;
2199            }
2200
2201            this._execOnAll("unreg", []);
2202
2203            for (var i in this.elementCache) {
2204                delete this.elementCache[i];
2205            }
2206
2207            this.elementCache = {};
2208            this.ids = {};
2209        },
2210
2211        /**
2212         * A cache of DOM elements
2213         * @property elementCache
2214         * @private
2215         * @static
2216         */
2217        elementCache: {},
2218
2219        /**
2220         * Get the wrapper for the DOM element specified
2221         * @method getElWrapper
2222         * @param {String} id the id of the element to get
2223         * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
2224         * @private
2225         * @deprecated This wrapper isn't that useful
2226         * @static
2227         */
2228        getElWrapper: function(id) {
2229            var oWrapper = this.elementCache[id];
2230            if (!oWrapper || !oWrapper.el) {
2231                oWrapper = this.elementCache[id] =
2232                    new this.ElementWrapper(Ext.getDom(id));
2233            }
2234            return oWrapper;
2235        },
2236
2237        /**
2238         * Returns the actual DOM element
2239         * @method getElement
2240         * @param {String} id the id of the elment to get
2241         * @return {Object} The element
2242         * @deprecated use Ext.lib.Ext.getDom instead
2243         * @static
2244         */
2245        getElement: function(id) {
2246            return Ext.getDom(id);
2247        },
2248
2249        /**
2250         * Returns the style property for the DOM element (i.e.,
2251         * document.getElById(id).style)
2252         * @method getCss
2253         * @param {String} id the id of the elment to get
2254         * @return {Object} The style property of the element
2255         * @deprecated use Ext.lib.Dom instead
2256         * @static
2257         */
2258        getCss: function(id) {
2259            var el = Ext.getDom(id);
2260            return (el) ? el.style : null;
2261        },
2262
2263        /**
2264         * Inner class for cached elements
2265         * @class DragDropMgr.ElementWrapper
2266         * @for DragDropMgr
2267         * @private
2268         * @deprecated
2269         */
2270        ElementWrapper: function(el) {
2271                /**
2272                 * The element
2273                 * @property el
2274                 */
2275                this.el = el || null;
2276                /**
2277                 * The element id
2278                 * @property id
2279                 */
2280                this.id = this.el && el.id;
2281                /**
2282                 * A reference to the style property
2283                 * @property css
2284                 */
2285                this.css = this.el && el.style;
2286            },
2287
2288        /**
2289         * Returns the X position of an html element
2290         * @method getPosX
2291         * @param el the element for which to get the position
2292         * @return {int} the X coordinate
2293         * @for DragDropMgr
2294         * @deprecated use Ext.lib.Dom.getX instead
2295         * @static
2296         */
2297        getPosX: function(el) {
2298            return Ext.lib.Dom.getX(el);
2299        },
2300
2301        /**
2302         * Returns the Y position of an html element
2303         * @method getPosY
2304         * @param el the element for which to get the position
2305         * @return {int} the Y coordinate
2306         * @deprecated use Ext.lib.Dom.getY instead
2307         * @static
2308         */
2309        getPosY: function(el) {
2310            return Ext.lib.Dom.getY(el);
2311        },
2312
2313        /**
2314         * Swap two nodes.  In IE, we use the native method, for others we
2315         * emulate the IE behavior
2316         * @method swapNode
2317         * @param n1 the first node to swap
2318         * @param n2 the other node to swap
2319         * @static
2320         */
2321        swapNode: function(n1, n2) {
2322            if (n1.swapNode) {
2323                n1.swapNode(n2);
2324            } else {
2325                var p = n2.parentNode;
2326                var s = n2.nextSibling;
2327
2328                if (s == n1) {
2329                    p.insertBefore(n1, n2);
2330                } else if (n2 == n1.nextSibling) {
2331                    p.insertBefore(n2, n1);
2332                } else {
2333                    n1.parentNode.replaceChild(n2, n1);
2334                    p.insertBefore(n1, s);
2335                }
2336            }
2337        },
2338
2339        /**
2340         * Returns the current scroll position
2341         * @method getScroll
2342         * @private
2343         * @static
2344         */
2345        getScroll: function () {
2346            var t, l, dde=document.documentElement, db=document.body;
2347            if (dde && (dde.scrollTop || dde.scrollLeft)) {
2348                t = dde.scrollTop;
2349                l = dde.scrollLeft;
2350            } else if (db) {
2351                t = db.scrollTop;
2352                l = db.scrollLeft;
2353            } else {
2354
2355            }
2356            return { top: t, left: l };
2357        },
2358
2359        /**
2360         * Returns the specified element style property
2361         * @method getStyle
2362         * @param {HTMLElement} el          the element
2363         * @param {string}      styleProp   the style property
2364         * @return {string} The value of the style property
2365         * @deprecated use Ext.lib.Dom.getStyle
2366         * @static
2367         */
2368        getStyle: function(el, styleProp) {
2369            return Ext.fly(el).getStyle(styleProp);
2370        },
2371
2372        /**
2373         * Gets the scrollTop
2374         * @method getScrollTop
2375         * @return {int} the document's scrollTop
2376         * @static
2377         */
2378        getScrollTop: function () { return this.getScroll().top; },
2379
2380        /**
2381         * Gets the scrollLeft
2382         * @method getScrollLeft
2383         * @return {int} the document's scrollTop
2384         * @static
2385         */
2386        getScrollLeft: function () { return this.getScroll().left; },
2387
2388        /**
2389         * Sets the x/y position of an element to the location of the
2390         * target element.
2391         * @method moveToEl
2392         * @param {HTMLElement} moveEl      The element to move
2393         * @param {HTMLElement} targetEl    The position reference element
2394         * @static
2395         */
2396        moveToEl: function (moveEl, targetEl) {
2397            var aCoord = Ext.lib.Dom.getXY(targetEl);
2398            Ext.lib.Dom.setXY(moveEl, aCoord);
2399        },
2400
2401        /**
2402         * Numeric array sort function
2403         * @method numericSort
2404         * @static
2405         */
2406        numericSort: function(a, b) { return (a - b); },
2407
2408        /**
2409         * Internal counter
2410         * @property _timeoutCount
2411         * @private
2412         * @static
2413         */
2414        _timeoutCount: 0,
2415
2416        /**
2417         * Trying to make the load order less important.  Without this we get
2418         * an error if this file is loaded before the Event Utility.
2419         * @method _addListeners
2420         * @private
2421         * @static
2422         */
2423        _addListeners: function() {
2424            var DDM = Ext.dd.DDM;
2425            if ( Ext.lib.Event && document ) {
2426                DDM._onLoad();
2427            } else {
2428                if (DDM._timeoutCount > 2000) {
2429                } else {
2430                    setTimeout(DDM._addListeners, 10);
2431                    if (document && document.body) {
2432                        DDM._timeoutCount += 1;
2433                    }
2434                }
2435            }
2436        },
2437
2438        /**
2439         * Recursively searches the immediate parent and all child nodes for
2440         * the handle element in order to determine wheter or not it was
2441         * clicked.
2442         * @method handleWasClicked
2443         * @param node the html element to inspect
2444         * @static
2445         */
2446        handleWasClicked: function(node, id) {
2447            if (this.isHandle(id, node.id)) {
2448                return true;
2449            } else {
2450                // check to see if this is a text node child of the one we want
2451                var p = node.parentNode;
2452
2453                while (p) {
2454                    if (this.isHandle(id, p.id)) {
2455                        return true;
2456                    } else {
2457                        p = p.parentNode;
2458                    }
2459                }
2460            }
2461
2462            return false;
2463        }
2464
2465    };
2466
2467}();
2468
2469// shorter alias, save a few bytes
2470Ext.dd.DDM = Ext.dd.DragDropMgr;
2471Ext.dd.DDM._addListeners();
2472
2473}
2474
2475/**
2476 * @class Ext.dd.DD
2477 * A DragDrop implementation where the linked element follows the
2478 * mouse cursor during a drag.
2479 * @extends Ext.dd.DragDrop
2480 * @constructor
2481 * @param {String} id the id of the linked element
2482 * @param {String} sGroup the group of related DragDrop items
2483 * @param {object} config an object containing configurable attributes
2484 *                Valid properties for DD:
2485 *                    scroll
2486 */
2487Ext.dd.DD = function(id, sGroup, config) {
2488    if (id) {
2489        this.init(id, sGroup, config);
2490    }
2491};
2492
2493Ext.extend(Ext.dd.DD, Ext.dd.DragDrop, {
2494
2495    /**
2496     * When set to true, the utility automatically tries to scroll the browser
2497     * window when a drag and drop element is dragged near the viewport boundary.
2498     * Defaults to true.
2499     * @property scroll
2500     * @type boolean
2501     */
2502    scroll: true,
2503
2504    /**
2505     * Sets the pointer offset to the distance between the linked element's top
2506     * left corner and the location the element was clicked
2507     * @method autoOffset
2508     * @param {int} iPageX the X coordinate of the click
2509     * @param {int} iPageY the Y coordinate of the click
2510     */
2511    autoOffset: function(iPageX, iPageY) {
2512        var x = iPageX - this.startPageX;
2513        var y = iPageY - this.startPageY;
2514        this.setDelta(x, y);
2515    },
2516
2517    /**
2518     * Sets the pointer offset.  You can call this directly to force the
2519     * offset to be in a particular location (e.g., pass in 0,0 to set it
2520     * to the center of the object)
2521     * @method setDelta
2522     * @param {int} iDeltaX the distance from the left
2523     * @param {int} iDeltaY the distance from the top
2524     */
2525    setDelta: function(iDeltaX, iDeltaY) {
2526        this.deltaX = iDeltaX;
2527        this.deltaY = iDeltaY;
2528    },
2529
2530    /**
2531     * Sets the drag element to the location of the mousedown or click event,
2532     * maintaining the cursor location relative to the location on the element
2533     * that was clicked.  Override this if you want to place the element in a
2534     * location other than where the cursor is.
2535     * @method setDragElPos
2536     * @param {int} iPageX the X coordinate of the mousedown or drag event
2537     * @param {int} iPageY the Y coordinate of the mousedown or drag event
2538     */
2539    setDragElPos: function(iPageX, iPageY) {
2540        // the first time we do this, we are going to check to make sure
2541        // the element has css positioning
2542
2543        var el = this.getDragEl();
2544        this.alignElWithMouse(el, iPageX, iPageY);
2545    },
2546
2547    /**
2548     * Sets the element to the location of the mousedown or click event,
2549     * maintaining the cursor location relative to the location on the element
2550     * that was clicked.  Override this if you want to place the element in a
2551     * location other than where the cursor is.
2552     * @method alignElWithMouse
2553     * @param {HTMLElement} el the element to move
2554     * @param {int} iPageX the X coordinate of the mousedown or drag event
2555     * @param {int} iPageY the Y coordinate of the mousedown or drag event
2556     */
2557    alignElWithMouse: function(el, iPageX, iPageY) {
2558        var oCoord = this.getTargetCoord(iPageX, iPageY);
2559        var fly = el.dom ? el : Ext.fly(el, '_dd');
2560        if (!this.deltaSetXY) {
2561            var aCoord = [oCoord.x, oCoord.y];
2562            fly.setXY(aCoord);
2563            var newLeft = fly.getLeft(true);
2564            var newTop  = fly.getTop(true);
2565            this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2566        } else {
2567            fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2568        }
2569
2570        this.cachePosition(oCoord.x, oCoord.y);
2571        this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2572        return oCoord;
2573    },
2574
2575    /**
2576     * Saves the most recent position so that we can reset the constraints and
2577     * tick marks on-demand.  We need to know this so that we can calculate the
2578     * number of pixels the element is offset from its original position.
2579     * @method cachePosition
2580     * @param iPageX the current x position (optional, this just makes it so we
2581     * don't have to look it up again)
2582     * @param iPageY the current y position (optional, this just makes it so we
2583     * don't have to look it up again)
2584     */
2585    cachePosition: function(iPageX, iPageY) {
2586        if (iPageX) {
2587            this.lastPageX = iPageX;
2588            this.lastPageY = iPageY;
2589        } else {
2590            var aCoord = Ext.lib.Dom.getXY(this.getEl());
2591            this.lastPageX = aCoord[0];
2592            this.lastPageY = aCoord[1];
2593        }
2594    },
2595
2596    /**
2597     * Auto-scroll the window if the dragged object has been moved beyond the
2598     * visible window boundary.
2599     * @method autoScroll
2600     * @param {int} x the drag element's x position
2601     * @param {int} y the drag element's y position
2602     * @param {int} h the height of the drag element
2603     * @param {int} w the width of the drag element
2604     * @private
2605     */
2606    autoScroll: function(x, y, h, w) {
2607
2608        if (this.scroll) {
2609            // The client height
2610            var clientH = Ext.lib.Dom.getViewHeight();
2611
2612            // The client width
2613            var clientW = Ext.lib.Dom.getViewWidth();
2614
2615            // The amt scrolled down
2616            var st = this.DDM.getScrollTop();
2617
2618            // The amt scrolled right
2619            var sl = this.DDM.getScrollLeft();
2620
2621            // Location of the bottom of the element
2622            var bot = h + y;
2623
2624            // Location of the right of the element
2625            var right = w + x;
2626
2627            // The distance from the cursor to the bottom of the visible area,
2628            // adjusted so that we don't scroll if the cursor is beyond the
2629            // element drag constraints
2630            var toBot = (clientH + st - y - this.deltaY);
2631
2632            // The distance from the cursor to the right of the visible area
2633            var toRight = (clientW + sl - x - this.deltaX);
2634
2635
2636            // How close to the edge the cursor must be before we scroll
2637            // var thresh = (document.all) ? 100 : 40;
2638            var thresh = 40;
2639
2640            // How many pixels to scroll per autoscroll op.  This helps to reduce
2641            // clunky scrolling. IE is more sensitive about this ... it needs this
2642            // value to be higher.
2643            var scrAmt = (document.all) ? 80 : 30;
2644
2645            // Scroll down if we are near the bottom of the visible page and the
2646            // obj extends below the crease
2647            if ( bot > clientH && toBot < thresh ) {
2648                window.scrollTo(sl, st + scrAmt);
2649            }
2650
2651            // Scroll up if the window is scrolled down and the top of the object
2652            // goes above the top border
2653            if ( y < st && st > 0 && y - st < thresh ) {
2654                window.scrollTo(sl, st - scrAmt);
2655            }
2656
2657            // Scroll right if the obj is beyond the right border and the cursor is
2658            // near the border.
2659            if ( right > clientW && toRight < thresh ) {
2660                window.scrollTo(sl + scrAmt, st);
2661            }
2662
2663            // Scroll left if the window has been scrolled to the right and the obj
2664            // extends past the left border
2665            if ( x < sl && sl > 0 && x - sl < thresh ) {
2666                window.scrollTo(sl - scrAmt, st);
2667            }
2668        }
2669    },
2670
2671    /**
2672     * Finds the location the element should be placed if we want to move
2673     * it to where the mouse location less the click offset would place us.
2674     * @method getTargetCoord
2675     * @param {int} iPageX the X coordinate of the click
2676     * @param {int} iPageY the Y coordinate of the click
2677     * @return an object that contains the coordinates (Object.x and Object.y)
2678     * @private
2679     */
2680    getTargetCoord: function(iPageX, iPageY) {
2681
2682
2683        var x = iPageX - this.deltaX;
2684        var y = iPageY - this.deltaY;
2685
2686        if (this.constrainX) {
2687            if (x < this.minX) { x = this.minX; }
2688            if (x > this.maxX) { x = this.maxX; }
2689        }
2690
2691        if (this.constrainY) {
2692            if (y < this.minY) { y = this.minY; }
2693            if (y > this.maxY) { y = this.maxY; }
2694        }
2695
2696        x = this.getTick(x, this.xTicks);
2697        y = this.getTick(y, this.yTicks);
2698
2699
2700        return {x:x, y:y};
2701    },
2702
2703    /**
2704     * Sets up config options specific to this class. Overrides
2705     * Ext.dd.DragDrop, but all versions of this method through the
2706     * inheritance chain are called
2707     */
2708    applyConfig: function() {
2709        Ext.dd.DD.superclass.applyConfig.call(this);
2710        this.scroll = (this.config.scroll !== false);
2711    },
2712
2713    /**
2714     * Event that fires prior to the onMouseDown event.  Overrides
2715     * Ext.dd.DragDrop.
2716     */
2717    b4MouseDown: function(e) {
2718        // this.resetConstraints();
2719        this.autoOffset(e.getPageX(),
2720                            e.getPageY());
2721    },
2722
2723    /**
2724     * Event that fires prior to the onDrag event.  Overrides
2725     * Ext.dd.DragDrop.
2726     */
2727    b4Drag: function(e) {
2728        this.setDragElPos(e.getPageX(),
2729                            e.getPageY());
2730    },
2731
2732    toString: function() {
2733        return ("DD " + this.id);
2734    }
2735
2736    //////////////////////////////////////////////////////////////////////////
2737    // Debugging ygDragDrop events that can be overridden
2738    //////////////////////////////////////////////////////////////////////////
2739    /*
2740    startDrag: function(x, y) {
2741    },
2742
2743    onDrag: function(e) {
2744    },
2745
2746    onDragEnter: function(e, id) {
2747    },
2748
2749    onDragOver: function(e, id) {
2750    },
2751
2752    onDragOut: function(e, id) {
2753    },
2754
2755    onDragDrop: function(e, id) {
2756    },
2757
2758    endDrag: function(e) {
2759    }
2760
2761    */
2762
2763});
2764/**
2765 * @class Ext.dd.DDProxy
2766 * A DragDrop implementation that inserts an empty, bordered div into
2767 * the document that follows the cursor during drag operations.  At the time of
2768 * the click, the frame div is resized to the dimensions of the linked html
2769 * element, and moved to the exact location of the linked element.
2770 *
2771 * References to the "frame" element refer to the single proxy element that
2772 * was created to be dragged in place of all DDProxy elements on the
2773 * page.
2774 *
2775 * @extends Ext.dd.DD
2776 * @constructor
2777 * @param {String} id the id of the linked html element
2778 * @param {String} sGroup the group of related DragDrop objects
2779 * @param {object} config an object containing configurable attributes
2780 *                Valid properties for DDProxy in addition to those in DragDrop:
2781 *                   resizeFrame, centerFrame, dragElId
2782 */
2783Ext.dd.DDProxy = function(id, sGroup, config) {
2784    if (id) {
2785        this.init(id, sGroup, config);
2786        this.initFrame();
2787    }
2788};
2789
2790/**
2791 * The default drag frame div id
2792 * @property Ext.dd.DDProxy.dragElId
2793 * @type String
2794 * @static
2795 */
2796Ext.dd.DDProxy.dragElId = "ygddfdiv";
2797
2798Ext.extend(Ext.dd.DDProxy, Ext.dd.DD, {
2799
2800    /**
2801     * By default we resize the drag frame to be the same size as the element
2802     * we want to drag (this is to get the frame effect).  We can turn it off
2803     * if we want a different behavior.
2804     * @property resizeFrame
2805     * @type boolean
2806     */
2807    resizeFrame: true,
2808
2809    /**
2810     * By default the frame is positioned exactly where the drag element is, so
2811     * we use the cursor offset provided by Ext.dd.DD.  Another option that works only if
2812     * you do not have constraints on the obj is to have the drag frame centered
2813     * around the cursor.  Set centerFrame to true for this effect.
2814     * @property centerFrame
2815     * @type boolean
2816     */
2817    centerFrame: false,
2818
2819    /**
2820     * Creates the proxy element if it does not yet exist
2821     * @method createFrame
2822     */
2823    createFrame: function() {
2824        var self = this;
2825        var body = document.body;
2826
2827        if (!body || !body.firstChild) {
2828            setTimeout( function() { self.createFrame(); }, 50 );
2829            return;
2830        }
2831
2832        var div = this.getDragEl();
2833
2834        if (!div) {
2835            div    = document.createElement("div");
2836            div.id = this.dragElId;
2837            var s  = div.style;
2838
2839            s.position   = "absolute";
2840            s.visibility = "hidden";
2841            s.cursor     = "move";
2842            s.border     = "2px solid #aaa";
2843            s.zIndex     = 999;
2844
2845            // appendChild can blow up IE if invoked prior to the window load event
2846            // while rendering a table.  It is possible there are other scenarios
2847            // that would cause this to happen as well.
2848            body.insertBefore(div, body.firstChild);
2849        }
2850    },
2851
2852    /**
2853     * Initialization for the drag frame element.  Must be called in the
2854     * constructor of all subclasses
2855     * @method initFrame
2856     */
2857    initFrame: function() {
2858        this.createFrame();
2859    },
2860
2861    applyConfig: function() {
2862        Ext.dd.DDProxy.superclass.applyConfig.call(this);
2863
2864        this.resizeFrame = (this.config.resizeFrame !== false);
2865        this.centerFrame = (this.config.centerFrame);
2866        this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);
2867    },
2868
2869    /**
2870     * Resizes the drag frame to the dimensions of the clicked object, positions
2871     * it over the object, and finally displays it
2872     * @method showFrame
2873     * @param {int} iPageX X click position
2874     * @param {int} iPageY Y click position
2875     * @private
2876     */
2877    showFrame: function(iPageX, iPageY) {
2878        var el = this.getEl();
2879        var dragEl = this.getDragEl();
2880        var s = dragEl.style;
2881
2882        this._resizeProxy();
2883
2884        if (this.centerFrame) {
2885            this.setDelta( Math.round(parseInt(s.width,  10)/2),
2886                           Math.round(parseInt(s.height, 10)/2) );
2887        }
2888
2889        this.setDragElPos(iPageX, iPageY);
2890
2891        Ext.fly(dragEl).show();
2892    },
2893
2894    /**
2895     * The proxy is automatically resized to the dimensions of the linked
2896     * element when a drag is initiated, unless resizeFrame is set to false
2897     * @method _resizeProxy
2898     * @private
2899     */
2900    _resizeProxy: function() {
2901        if (this.resizeFrame) {
2902            var el = this.getEl();
2903            Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2904        }
2905    },
2906
2907    // overrides Ext.dd.DragDrop
2908    b4MouseDown: function(e) {
2909        var x = e.getPageX();
2910        var y = e.getPageY();
2911        this.autoOffset(x, y);
2912        this.setDragElPos(x, y);
2913    },
2914
2915    // overrides Ext.dd.DragDrop
2916    b4StartDrag: function(x, y) {
2917        // show the drag frame
2918        this.showFrame(x, y);
2919    },
2920
2921    // overrides Ext.dd.DragDrop
2922    b4EndDrag: function(e) {
2923        Ext.fly(this.getDragEl()).hide();
2924    },
2925
2926    // overrides Ext.dd.DragDrop
2927    // By default we try to move the element to the last location of the frame.
2928    // This is so that the default behavior mirrors that of Ext.dd.DD.
2929    endDrag: function(e) {
2930
2931        var lel = this.getEl();
2932        var del = this.getDragEl();
2933
2934        // Show the drag frame briefly so we can get its position
2935        del.style.visibility = "";
2936
2937        this.beforeMove();
2938        // Hide the linked element before the move to get around a Safari
2939        // rendering bug.
2940        lel.style.visibility = "hidden";
2941        Ext.dd.DDM.moveToEl(lel, del);
2942        del.style.visibility = "hidden";
2943        lel.style.visibility = "";
2944
2945        this.afterDrag();
2946    },
2947
2948    beforeMove : function(){
2949
2950    },
2951
2952    afterDrag : function(){
2953
2954    },
2955
2956    toString: function() {
2957        return ("DDProxy " + this.id);
2958    }
2959
2960});
2961/**
2962 * @class Ext.dd.DDTarget
2963 * A DragDrop implementation that does not move, but can be a drop
2964 * target.  You would get the same result by simply omitting implementation
2965 * for the event callbacks, but this way we reduce the processing cost of the
2966 * event listener and the callbacks.
2967 * @extends Ext.dd.DragDrop
2968 * @constructor
2969 * @param {String} id the id of the element that is a drop target
2970 * @param {String} sGroup the group of related DragDrop objects
2971 * @param {object} config an object containing configurable attributes
2972 *                 Valid properties for DDTarget in addition to those in
2973 *                 DragDrop:
2974 *                    none
2975 */
2976Ext.dd.DDTarget = function(id, sGroup, config) {
2977    if (id) {
2978        this.initTarget(id, sGroup, config);
2979    }
2980};
2981
2982// Ext.dd.DDTarget.prototype = new Ext.dd.DragDrop();
2983Ext.extend(Ext.dd.DDTarget, Ext.dd.DragDrop, {
2984    toString: function() {
2985        return ("DDTarget " + this.id);
2986    }
2987});
Note: See TracBrowser for help on using the repository browser.