3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * This is a derivative of the similarly named class in the YUI Library.
17 * The original license:
18 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19 * Code licensed under the BSD License:
20 * http://developer.yahoo.net/yui/license.txt
25 * @class Ext.dd.DragDropManager
26 * DragDropManager is a singleton that tracks the element interaction for
27 * all DragDrop items in the window. Generally, you will not call
28 * this class directly, but it does have helper methods that could
29 * be useful in your DragDrop implementations.
32 Ext.define('Ext.dd.DragDropManager', {
35 requires: ['Ext.util.Region'],
37 uses: ['Ext.tip.QuickTipManager'],
39 // shorter ClassName, to save bytes and use internally
40 alternateClassName: ['Ext.dd.DragDropMgr', 'Ext.dd.DDM'],
43 * Two dimensional Array of registered DragDrop objects. The first
44 * dimension is the DragDrop item group, the second the DragDrop
54 * Array of element ids defined as drag handles. Used to determine
55 * if the element that generated the mousedown event is actually the
56 * handle and not the html element itself.
65 * the DragDrop object that is currently being dragged
66 * @property dragCurrent
74 * the DragDrop object(s) that are being hovered over
83 * the X distance between the cursor and the object being dragged
92 * the Y distance between the cursor and the object being dragged
101 * Flag to determine if we should prevent the default behavior of the
102 * events we define. By default this is true, but this can be set to
103 * false if you need the default behavior (not recommended)
104 * @property preventDefault
108 preventDefault: true,
111 * Flag to determine if we should stop the propagation of the events
112 * we generate. This is true by default but you may want to set it to
113 * false if the html element contains other features that require the
115 * @property stopPropagation
119 stopPropagation: true,
122 * Internal flag that is set to true when drag and drop has been
124 * @property initialized
131 * All drag and drop can be disabled.
139 * Called the first time an element is registered.
145 this.initialized = true;
149 * In point mode, drag and drop interaction is defined by the
150 * location of the cursor during the drag/drop
158 * In intersect mode, drag and drop interaction is defined by the
159 * overlap of two or more drag and drop objects.
160 * @property INTERSECT
167 * The current drag and drop mode. Default: POINT
175 * Runs method on all drag and drop objects
180 _execOnAll: function(sMethod, args) {
181 for (var i in this.ids) {
182 for (var j in this.ids[i]) {
183 var oDD = this.ids[i][j];
184 if (! this.isTypeOfDD(oDD)) {
187 oDD[sMethod].apply(oDD, args);
193 * Drag and drop initialization. Sets up the global event handlers
198 _onLoad: function() {
202 var Event = Ext.EventManager;
203 Event.on(document, "mouseup", this.handleMouseUp, this, true);
204 Event.on(document, "mousemove", this.handleMouseMove, this, true);
205 Event.on(window, "unload", this._onUnload, this, true);
206 Event.on(window, "resize", this._onResize, this, true);
207 // Event.on(window, "mouseout", this._test);
212 * Reset constraints on all drag and drop objs
217 _onResize: function(e) {
218 this._execOnAll("resetConstraints", []);
222 * Lock all drag and drop functionality
226 lock: function() { this.locked = true; },
229 * Unlock all drag and drop functionality
233 unlock: function() { this.locked = false; },
236 * Is drag and drop locked?
238 * @return {boolean} True if drag and drop is locked, false otherwise.
241 isLocked: function() { return this.locked; },
244 * Location cache that is set for all drag drop objects when a drag is
245 * initiated, cleared when the drag is finished.
246 * @property locationCache
253 * Set useCache to false if you want to force object the lookup of each
254 * drag and drop linked element constantly during a drag.
262 * The number of pixels that the mouse needs to move after the
263 * mousedown before the drag is initiated. Default=3;
264 * @property clickPixelThresh
271 * The number of milliseconds after the mousedown event to initiate the
272 * drag if we don't get a mouseup event. Default=350
273 * @property clickTimeThresh
277 clickTimeThresh: 350,
280 * Flag that indicates that either the drag pixel threshold or the
281 * mousdown time threshold has been met
282 * @property dragThreshMet
287 dragThreshMet: false,
290 * Timeout used for the click time threshold
291 * @property clickTimeout
299 * The X position of the mousedown event stored for later use when a
300 * drag threshold is met.
309 * The Y position of the mousedown event stored for later use when a
310 * drag threshold is met.
319 * Each DragDrop instance must be registered with the DragDropManager.
320 * This is executed in DragDrop.init()
321 * @method regDragDrop
322 * @param {DragDrop} oDD the DragDrop object to register
323 * @param {String} sGroup the name of the group this element belongs to
326 regDragDrop: function(oDD, sGroup) {
327 if (!this.initialized) { this.init(); }
329 if (!this.ids[sGroup]) {
330 this.ids[sGroup] = {};
332 this.ids[sGroup][oDD.id] = oDD;
336 * Removes the supplied dd instance from the supplied group. Executed
337 * by DragDrop.removeFromGroup, so don't call this function directly.
338 * @method removeDDFromGroup
342 removeDDFromGroup: function(oDD, sGroup) {
343 if (!this.ids[sGroup]) {
344 this.ids[sGroup] = {};
347 var obj = this.ids[sGroup];
348 if (obj && obj[oDD.id]) {
354 * Unregisters a drag and drop item. This is executed in
355 * DragDrop.unreg, use that method instead of calling this directly.
360 _remove: function(oDD) {
361 for (var g in oDD.groups) {
362 if (g && this.ids[g] && this.ids[g][oDD.id]) {
363 delete this.ids[g][oDD.id];
366 delete this.handleIds[oDD.id];
370 * Each DragDrop handle element must be registered. This is done
371 * automatically when executing DragDrop.setHandleElId()
373 * @param {String} sDDId the DragDrop id this element is a handle for
374 * @param {String} sHandleId the id of the element that is the drag
378 regHandle: function(sDDId, sHandleId) {
379 if (!this.handleIds[sDDId]) {
380 this.handleIds[sDDId] = {};
382 this.handleIds[sDDId][sHandleId] = sHandleId;
386 * Utility function to determine if a given element has been
387 * registered as a drag drop item.
389 * @param {String} id the element id to check
390 * @return {boolean} true if this element is a DragDrop item,
394 isDragDrop: function(id) {
395 return ( this.getDDById(id) ) ? true : false;
399 * Returns the drag and drop instances that are in all groups the
400 * passed in instance belongs to.
402 * @param {DragDrop} p_oDD the obj to get related data for
403 * @param {boolean} bTargetsOnly if true, only return targetable objs
404 * @return {DragDrop[]} the related instances
407 getRelated: function(p_oDD, bTargetsOnly) {
409 for (var i in p_oDD.groups) {
410 for (var j in this.ids[i]) {
411 var dd = this.ids[i][j];
412 if (! this.isTypeOfDD(dd)) {
415 if (!bTargetsOnly || dd.isTarget) {
416 oDDs[oDDs.length] = dd;
425 * Returns true if the specified dd target is a legal target for
426 * the specifice drag obj
427 * @method isLegalTarget
428 * @param {DragDrop} oDD the drag obj
429 * @param {DragDrop} oTargetDD the target
430 * @return {boolean} true if the target is a legal target for the
434 isLegalTarget: function (oDD, oTargetDD) {
435 var targets = this.getRelated(oDD, true);
436 for (var i=0, len=targets.length;i<len;++i) {
437 if (targets[i].id == oTargetDD.id) {
446 * My goal is to be able to transparently determine if an object is
447 * typeof DragDrop, and the exact subclass of DragDrop. typeof
448 * returns "object", oDD.constructor.toString() always returns
449 * "DragDrop" and not the name of the subclass. So for now it just
450 * evaluates a well-known variable in DragDrop.
452 * @param {Object} the object to evaluate
453 * @return {boolean} true if typeof oDD = DragDrop
456 isTypeOfDD: function (oDD) {
457 return (oDD && oDD.__ygDragDrop);
461 * Utility function to determine if a given element has been
462 * registered as a drag drop handle for the given Drag Drop object.
464 * @param {String} id the element id to check
465 * @return {boolean} true if this element is a DragDrop handle, false
469 isHandle: function(sDDId, sHandleId) {
470 return ( this.handleIds[sDDId] &&
471 this.handleIds[sDDId][sHandleId] );
475 * Returns the DragDrop instance for a given id
477 * @param {String} id the id of the DragDrop object
478 * @return {DragDrop} the drag drop object, null if it is not found
481 getDDById: function(id) {
482 for (var i in this.ids) {
483 if (this.ids[i][id]) {
484 return this.ids[i][id];
491 * Fired after a registered DragDrop object gets the mousedown event.
492 * Sets up the events required to track the object being dragged
493 * @method handleMouseDown
494 * @param {Event} e the event
495 * @param oDD the DragDrop object being dragged
499 handleMouseDown: function(e, oDD) {
500 if(Ext.tip.QuickTipManager){
501 Ext.tip.QuickTipManager.ddDisable();
503 if(this.dragCurrent){
504 // the original browser mouseup wasn't handled (e.g. outside FF browser window)
505 // so clean up first to avoid breaking the next drag
506 this.handleMouseUp(e);
509 this.currentTarget = e.getTarget();
510 this.dragCurrent = oDD;
512 var el = oDD.getEl();
514 // track start position
515 this.startX = e.getPageX();
516 this.startY = e.getPageY();
518 this.deltaX = this.startX - el.offsetLeft;
519 this.deltaY = this.startY - el.offsetTop;
521 this.dragThreshMet = false;
523 this.clickTimeout = setTimeout(
525 var DDM = Ext.dd.DragDropManager;
526 DDM.startDrag(DDM.startX, DDM.startY);
528 this.clickTimeThresh );
532 * Fired when either the drag pixel threshol or the mousedown hold
533 * time threshold has been met.
535 * @param x {int} the X position of the original mousedown
536 * @param y {int} the Y position of the original mousedown
539 startDrag: function(x, y) {
540 clearTimeout(this.clickTimeout);
541 if (this.dragCurrent) {
542 this.dragCurrent.b4StartDrag(x, y);
543 this.dragCurrent.startDrag(x, y);
545 this.dragThreshMet = true;
549 * Internal function to handle the mouseup event. Will be invoked
550 * from the context of the document.
551 * @method handleMouseUp
552 * @param {Event} e the event
556 handleMouseUp: function(e) {
558 if(Ext.tip.QuickTipManager){
559 Ext.tip.QuickTipManager.ddEnable();
561 if (! this.dragCurrent) {
565 clearTimeout(this.clickTimeout);
567 if (this.dragThreshMet) {
568 this.fireEvents(e, true);
578 * Utility to stop event propagation and event default, if these
579 * features are turned on.
581 * @param {Event} e the event as returned by this.getEvent()
584 stopEvent: function(e){
585 if(this.stopPropagation) {
589 if (this.preventDefault) {
595 * Internal function to clean up event handlers after the drag
596 * operation is complete
598 * @param {Event} e the event
602 stopDrag: function(e) {
603 // Fire the drag end event for the item that was dragged
604 if (this.dragCurrent) {
605 if (this.dragThreshMet) {
606 this.dragCurrent.b4EndDrag(e);
607 this.dragCurrent.endDrag(e);
610 this.dragCurrent.onMouseUp(e);
613 this.dragCurrent = null;
618 * Internal function to handle the mousemove event. Will be invoked
619 * from the context of the html element.
621 * @TODO figure out what we can do about mouse events lost when the
622 * user drags objects beyond the window boundary. Currently we can
623 * detect this in internet explorer by verifying that the mouse is
624 * down during the mousemove event. Firefox doesn't give us the
625 * button state on the mousemove event.
626 * @method handleMouseMove
627 * @param {Event} e the event
631 handleMouseMove: function(e) {
632 if (! this.dragCurrent) {
635 // var button = e.which || e.button;
637 // check for IE mouseup outside of page boundary
638 if (Ext.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
640 return this.handleMouseUp(e);
643 if (!this.dragThreshMet) {
644 var diffX = Math.abs(this.startX - e.getPageX());
645 var diffY = Math.abs(this.startY - e.getPageY());
646 if (diffX > this.clickPixelThresh ||
647 diffY > this.clickPixelThresh) {
648 this.startDrag(this.startX, this.startY);
652 if (this.dragThreshMet) {
653 this.dragCurrent.b4Drag(e);
654 this.dragCurrent.onDrag(e);
655 if(!this.dragCurrent.moveOnly){
656 this.fireEvents(e, false);
666 * Iterates over all of the DragDrop elements to find ones we are
667 * hovering over or dropping on
669 * @param {Event} e the event
670 * @param {boolean} isDrop is this a drop op or a mouseover op?
674 fireEvents: function(e, isDrop) {
675 var dc = this.dragCurrent;
677 // If the user did the mouse up outside of the window, we could
678 // get here even though we have ended the drag.
679 if (!dc || dc.isLocked()) {
683 var pt = e.getPoint();
685 // cache the previous dragOver array
693 // Check to see if the object(s) we were hovering over is no longer
694 // being hovered over so we can fire the onDragOut event
695 for (var i in this.dragOvers) {
697 var ddo = this.dragOvers[i];
699 if (! this.isTypeOfDD(ddo)) {
703 if (! this.isOverTarget(pt, ddo, this.mode)) {
708 delete this.dragOvers[i];
711 for (var sGroup in dc.groups) {
713 if ("string" != typeof sGroup) {
717 for (i in this.ids[sGroup]) {
718 var oDD = this.ids[sGroup][i];
719 if (! this.isTypeOfDD(oDD)) {
723 if (oDD.isTarget && !oDD.isLocked() && ((oDD != dc) || (dc.ignoreSelf === false))) {
724 if (this.isOverTarget(pt, oDD, this.mode)) {
725 // look for drop interactions
727 dropEvts.push( oDD );
728 // look for drag enter and drag over interactions
731 // initial drag over: dragEnter fires
732 if (!oldOvers[oDD.id]) {
733 enterEvts.push( oDD );
734 // subsequent drag overs: dragOver fires
736 overEvts.push( oDD );
739 this.dragOvers[oDD.id] = oDD;
747 if (outEvts.length) {
748 dc.b4DragOut(e, outEvts);
749 dc.onDragOut(e, outEvts);
752 if (enterEvts.length) {
753 dc.onDragEnter(e, enterEvts);
756 if (overEvts.length) {
757 dc.b4DragOver(e, overEvts);
758 dc.onDragOver(e, overEvts);
761 if (dropEvts.length) {
762 dc.b4DragDrop(e, dropEvts);
763 dc.onDragDrop(e, dropEvts);
767 // fire dragout events
769 for (i=0, len=outEvts.length; i<len; ++i) {
770 dc.b4DragOut(e, outEvts[i].id);
771 dc.onDragOut(e, outEvts[i].id);
775 for (i=0,len=enterEvts.length; i<len; ++i) {
776 // dc.b4DragEnter(e, oDD.id);
777 dc.onDragEnter(e, enterEvts[i].id);
781 for (i=0,len=overEvts.length; i<len; ++i) {
782 dc.b4DragOver(e, overEvts[i].id);
783 dc.onDragOver(e, overEvts[i].id);
787 for (i=0, len=dropEvts.length; i<len; ++i) {
788 dc.b4DragDrop(e, dropEvts[i].id);
789 dc.onDragDrop(e, dropEvts[i].id);
794 // notify about a drop that did not find a target
795 if (isDrop && !dropEvts.length) {
802 * Helper function for getting the best match from the list of drag
803 * and drop objects returned by the drag and drop events when we are
804 * in INTERSECT mode. It returns either the first object that the
805 * cursor is over, or the object that has the greatest overlap with
806 * the dragged element.
807 * @method getBestMatch
808 * @param {DragDrop[]} dds The array of drag and drop objects
810 * @return {DragDrop} The best single match
813 getBestMatch: function(dds) {
815 // Return null if the input is not what we expect
816 //if (!dds || !dds.length || dds.length == 0) {
818 // If there is only one item, it wins
819 //} else if (dds.length == 1) {
821 var len = dds.length;
826 // Loop through the targeted items
827 for (var i=0; i<len; ++i) {
829 // If the cursor is over the object, it wins. If the
830 // cursor is over multiple matches, the first one we come
832 if (dd.cursorIsOver) {
835 // Otherwise the object with the most overlap wins
838 winner.overlap.getArea() < dd.overlap.getArea()) {
849 * Refreshes the cache of the top-left and bottom-right points of the
850 * drag and drop objects in the specified group(s). This is in the
851 * format that is stored in the drag and drop instance, so typical
854 * Ext.dd.DragDropManager.refreshCache(ddinstance.groups);
858 * Ext.dd.DragDropManager.refreshCache({group1:true, group2:true});
860 * @TODO this really should be an indexed array. Alternatively this
861 * method could accept both.
862 * @method refreshCache
863 * @param {Object} groups an associative array of groups to refresh
866 refreshCache: function(groups) {
867 for (var sGroup in groups) {
868 if ("string" != typeof sGroup) {
871 for (var i in this.ids[sGroup]) {
872 var oDD = this.ids[sGroup][i];
874 if (this.isTypeOfDD(oDD)) {
875 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
876 var loc = this.getLocation(oDD);
878 this.locationCache[oDD.id] = loc;
880 delete this.locationCache[oDD.id];
881 // this will unregister the drag and drop object if
882 // the element is not in a usable state
891 * This checks to make sure an element exists and is in the DOM. The
892 * main purpose is to handle cases where innerHTML is used to remove
893 * drag and drop objects from the DOM. IE provides an 'unspecified
894 * error' when trying to access the offsetParent of such an element
896 * @param {HTMLElement} el the element to check
897 * @return {boolean} true if the element looks usable
900 verifyEl: function(el) {
905 parent = el.offsetParent;
908 parent = el.offsetParent;
919 * Returns a Region object containing the drag and drop element's position
920 * and size, including the padding configured for it
921 * @method getLocation
922 * @param {DragDrop} oDD the drag and drop object to get the
924 * @return {Ext.util.Region} a Region object representing the total area
925 * the element occupies, including any padding
926 * the instance is configured for.
929 getLocation: function(oDD) {
930 if (! this.isTypeOfDD(oDD)) {
934 //delegate getLocation method to the
935 //drag and drop target.
937 return oDD.getRegion();
940 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
943 pos= Ext.core.Element.getXY(el);
951 x2 = x1 + el.offsetWidth;
953 y2 = y1 + el.offsetHeight;
955 t = y1 - oDD.padding[0];
956 r = x2 + oDD.padding[1];
957 b = y2 + oDD.padding[2];
958 l = x1 - oDD.padding[3];
960 return Ext.create('Ext.util.Region', t, r, b, l);
964 * Checks the cursor location to see if it over the target
965 * @method isOverTarget
966 * @param {Ext.util.Point} pt The point to evaluate
967 * @param {DragDrop} oTarget the DragDrop object we are inspecting
968 * @return {boolean} true if the mouse is over the target
972 isOverTarget: function(pt, oTarget, intersect) {
973 // use cache if available
974 var loc = this.locationCache[oTarget.id];
975 if (!loc || !this.useCache) {
976 loc = this.getLocation(oTarget);
977 this.locationCache[oTarget.id] = loc;
985 oTarget.cursorIsOver = loc.contains( pt );
987 // DragDrop is using this as a sanity check for the initial mousedown
988 // in this case we are done. In POINT mode, if the drag obj has no
989 // contraints, we are also done. Otherwise we need to evaluate the
990 // location of the target as related to the actual location of the
992 var dc = this.dragCurrent;
993 if (!dc || !dc.getTargetCoord ||
994 (!intersect && !dc.constrainX && !dc.constrainY)) {
995 return oTarget.cursorIsOver;
998 oTarget.overlap = null;
1000 // Get the current location of the drag element, this is the
1001 // location of the mouse event less the delta that represents
1002 // where the original mousedown happened on the element. We
1003 // need to consider constraints and ticks as well.
1004 var pos = dc.getTargetCoord(pt.x, pt.y);
1006 var el = dc.getDragEl();
1007 var curRegion = Ext.create('Ext.util.Region', pos.y,
1008 pos.x + el.offsetWidth,
1009 pos.y + el.offsetHeight,
1012 var overlap = curRegion.intersect(loc);
1015 oTarget.overlap = overlap;
1016 return (intersect) ? true : oTarget.cursorIsOver;
1023 * unload event handler
1028 _onUnload: function(e, me) {
1029 Ext.dd.DragDropManager.unregAll();
1033 * Cleans up the drag and drop events and objects.
1038 unregAll: function() {
1040 if (this.dragCurrent) {
1042 this.dragCurrent = null;
1045 this._execOnAll("unreg", []);
1047 for (var i in this.elementCache) {
1048 delete this.elementCache[i];
1051 this.elementCache = {};
1056 * A cache of DOM elements
1057 * @property elementCache
1064 * Get the wrapper for the DOM element specified
1065 * @method getElWrapper
1066 * @param {String} id the id of the element to get
1067 * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
1069 * @deprecated This wrapper isn't that useful
1072 getElWrapper: function(id) {
1073 var oWrapper = this.elementCache[id];
1074 if (!oWrapper || !oWrapper.el) {
1075 oWrapper = this.elementCache[id] =
1076 new this.ElementWrapper(Ext.getDom(id));
1082 * Returns the actual DOM element
1083 * @method getElement
1084 * @param {String} id the id of the elment to get
1085 * @return {Object} The element
1086 * @deprecated use Ext.lib.Ext.getDom instead
1089 getElement: function(id) {
1090 return Ext.getDom(id);
1094 * Returns the style property for the DOM element (i.e.,
1095 * document.getElById(id).style)
1097 * @param {String} id the id of the elment to get
1098 * @return {Object} The style property of the element
1101 getCss: function(id) {
1102 var el = Ext.getDom(id);
1103 return (el) ? el.style : null;
1107 * Inner class for cached elements
1108 * @class Ext.dd.DragDropManager.ElementWrapper
1109 * @for DragDropManager
1113 ElementWrapper: function(el) {
1118 this.el = el || null;
1123 this.id = this.el && el.id;
1125 * A reference to the style property
1128 this.css = this.el && el.style;
1132 * Returns the X position of an html element
1134 * @param el the element for which to get the position
1135 * @return {int} the X coordinate
1136 * @for DragDropManager
1139 getPosX: function(el) {
1140 return Ext.core.Element.getX(el);
1144 * Returns the Y position of an html element
1146 * @param el the element for which to get the position
1147 * @return {int} the Y coordinate
1150 getPosY: function(el) {
1151 return Ext.core.Element.getY(el);
1155 * Swap two nodes. In IE, we use the native method, for others we
1156 * emulate the IE behavior
1158 * @param n1 the first node to swap
1159 * @param n2 the other node to swap
1162 swapNode: function(n1, n2) {
1166 var p = n2.parentNode;
1167 var s = n2.nextSibling;
1170 p.insertBefore(n1, n2);
1171 } else if (n2 == n1.nextSibling) {
1172 p.insertBefore(n2, n1);
1174 n1.parentNode.replaceChild(n2, n1);
1175 p.insertBefore(n1, s);
1181 * Returns the current scroll position
1186 getScroll: function () {
1187 var doc = window.document,
1188 docEl = doc.documentElement,
1194 top = window.scrollYOffset;
1195 left = window.scrollXOffset;
1197 if (docEl && (docEl.scrollTop || docEl.scrollLeft)) {
1198 top = docEl.scrollTop;
1199 left = docEl.scrollLeft;
1201 top = body.scrollTop;
1202 left = body.scrollLeft;
1212 * Returns the specified element style property
1214 * @param {HTMLElement} el the element
1215 * @param {string} styleProp the style property
1216 * @return {string} The value of the style property
1219 getStyle: function(el, styleProp) {
1220 return Ext.fly(el).getStyle(styleProp);
1224 * Gets the scrollTop
1225 * @method getScrollTop
1226 * @return {int} the document's scrollTop
1229 getScrollTop: function () {
1230 return this.getScroll().top;
1234 * Gets the scrollLeft
1235 * @method getScrollLeft
1236 * @return {int} the document's scrollTop
1239 getScrollLeft: function () {
1240 return this.getScroll().left;
1244 * Sets the x/y position of an element to the location of the
1247 * @param {HTMLElement} moveEl The element to move
1248 * @param {HTMLElement} targetEl The position reference element
1251 moveToEl: function (moveEl, targetEl) {
1252 var aCoord = Ext.core.Element.getXY(targetEl);
1253 Ext.core.Element.setXY(moveEl, aCoord);
1257 * Numeric array sort function
1258 * @method numericSort
1261 numericSort: function(a, b) {
1267 * @property _timeoutCount
1274 * Trying to make the load order less important. Without this we get
1275 * an error if this file is loaded before the Event Utility.
1276 * @method _addListeners
1280 _addListeners: function() {
1284 if (this._timeoutCount > 2000) {
1286 setTimeout(this._addListeners, 10);
1287 if (document && document.body) {
1288 this._timeoutCount += 1;
1295 * Recursively searches the immediate parent and all child nodes for
1296 * the handle element in order to determine wheter or not it was
1298 * @method handleWasClicked
1299 * @param node the html element to inspect
1302 handleWasClicked: function(node, id) {
1303 if (this.isHandle(id, node.id)) {
1306 // check to see if this is a text node child of the one we want
1307 var p = node.parentNode;
1310 if (this.isHandle(id, p.id)) {
1321 this._addListeners();