Bug Tracker

Opened 13 years ago

Closed 12 years ago

#1437 closed bug (wontfix)

Sortables didn't recognize scroll offset to find new position

Reported by: Stuck Mojo Owned by: stefan
Priority: major Milestone:
Component: interface Version:
Keywords: Cc:
Blocked by: Blocking:

Description

<style type="text/css" media="all">
.sortHelper
{
	border: 3px dashed #666;
	width: auto !important;
}

</style>
<div id="sort1" class="groupWrapper" style="height:150px;width:200px;overflow:auto;">
	<div class="groupItem">A</div>
	<div class="groupItem">B</div>
	<div class="groupItem">C</div>
	<div class="groupItem">D</div>
	<div class="groupItem">E</div>
	<div class="groupItem">F</div>
	<div class="groupItem">G</div>
	<div class="groupItem">H</div>
	<div class="groupItem">I</div>
	<div class="groupItem">J</div>
	<div class="groupItem">K</div>
	<div class="groupItem">L</div>
	<div class="groupItem">M</div>
	<div class="groupItem">N</div>
	<div class="groupItem">O</div>
	<div class="groupItem">P</div>
	<div class="groupItem">Q</div>
	<div class="groupItem">R</div>
</div>

<script type="text/javascript">
$(document).ready(
	function () {
		$('div.groupWrapper').Sortable(
			{
				accept: 'groupItem',
				helperclass: 'sortHelper',
				tolerance: 'pointer'
			}
		);
	}
);

</script>

...just scroll some ticks down and try to drag an entry. The new position will not recogize the current offset of the scrollbars and will be calculated wrong.

A quick fix for me:

jQuery.iSort.checkhover = function(e,o)
{
	if (!jQuery.iDrag.dragged)
		return;
	
	var cur = false;
	var i = 0;
        // get the scroll data
	var tScroll = jQuery.iUtil.getScroll(jQuery.iDrop.overzone); 

	if ( e.dropCfg.el.size() > 0) {
		for (i = e.dropCfg.el.size(); i >0; i--) {
			if (e.dropCfg.el.get(i-1) != jQuery.iDrag.dragged) {
				if (!e.sortCfg.floats) {
					if ( 
					(e.dropCfg.el.get(i-1).pos.y - tScroll.t + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
					) {
						cur = e.dropCfg.el.get(i-1);
					} else {
						break;
					}
				} else {
					if (
					(e.dropCfg.el.get(i-1).pos.x - tScroll.l + e.dropCfg.el.get(i-1).pos.wb/2) > jQuery.iDrag.dragged.dragCfg.nx && 
					(e.dropCfg.el.get(i-1).pos.y - tScroll.t + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
					) {
						cur = e.dropCfg.el.get(i-1);
					}
				}
			}
		}
	}
	//helpos = jQuery.iUtil.getPos(jQuery.iSort.helper.get(0));
	if (cur && jQuery.iSort.inFrontOf != cur) {
		jQuery.iSort.inFrontOf = cur;
		jQuery(cur).before(jQuery.iSort.helper.get(0));
	} else if(!cur && (jQuery.iSort.inFrontOf != null || jQuery.iSort.helper.get(0).parentNode != e) ) {
		jQuery.iSort.inFrontOf = null;
		jQuery(e).append(jQuery.iSort.helper.get(0));
	}
	jQuery.iSort.helper.get(0).style.display = 'block';
}

Best regards, Jan

Change History (2)

comment:1 Changed 13 years ago by gregmac

The above code mostly fixed the issue, however, when you have something like:

<div style="height:10em;overflow:auto;">
  <ul id="sort1" class="groupWrapper" >
    <li class="sortable">A</li>
    <li class="sortable">B</li>
    <li class="sortable">C</li>
    <li class="sortable">D</li>
    <li class="sortable">E</li>
    <li class="sortable">F</li>
    <li class="sortable">G</li>
    <li class="sortable">H</li>
    <li class="sortable">I</li>
    <li class="sortable">J</li>
    <li class="sortable">K</li>
    <li class="sortable">L</li>
  </ul>
</div>
<script type="text/javascript">
$(document).ready(
	function () {
		$('.groupWrapper').Sortable(
			{
				accept: 'sortable',
				helperclass: 'sortHelper',
				tolerance: 'pointer'
			}
		);
	}
);
</script>

There are two issues:

  • The scroll position is not calculated properly because it only checks the immediate parent (the <ul>)
  • The items near the top and bottom of the <ul> are not positioned correctly (try dragging and item to the top or bottom). This becomes even more apparent if you have multiple <ul>'s with sortable items inside of the div. I believe this is related to #1205, as it fixes the problem.

Here is a patch, incorporating all of the fixes:

  • Implements the original solution from this ticket
  • Additionally calculates the scroll position for immediate parent AND all ancestors
  • Implements #1205 which fixes issues with mis-detecting the top/bottom of <ul>'s
Index: idrop.js
===================================================================
--- idrop.js	(revision 3)
+++ idrop.js	(working copy)
@@ -89,7 +89,7 @@
 				if (jQuery(jQuery.iDrag.dragged).is('.' + iEL.dropCfg.a)) {
 					if (iEL.dropCfg.m == false) {
 						iEL.dropCfg.p = jQuery.extend(
-							jQuery.iUtil.getPositionLite(iEL),
+							jQuery.iUtil.getPosition(iEL),
 							jQuery.iUtil.getSizeLite(iEL)
 						);//jQuery.iUtil.getPos(iEL);
 						iEL.dropCfg.m = true;
@@ -135,7 +135,7 @@
 				var iEL = jQuery.iDrop.zones[i].get(0);
 				if (jQuery(jQuery.iDrag.dragged).is('.' + iEL.dropCfg.a)) {
 					iEL.dropCfg.p = jQuery.extend(
-						jQuery.iUtil.getPositionLite(iEL),
+						jQuery.iUtil.getPosition(iEL),
 						jQuery.iUtil.getSizeLite(iEL)
 					);
 					if (iEL.dropCfg.ac) {
Index: isortables.js
===================================================================
--- isortables.js	(revision 3)
+++ isortables.js	(working copy)
@@ -148,12 +148,15 @@
 			return;
 		var cur = false;
 		var i = 0;
+		// get the scroll data
+		var tScroll = jQuery.iUtil.getScroll(jQuery.iDrop.overzone);
 		if ( e.dropCfg.el.size() > 0) {
 			for (i = e.dropCfg.el.size(); i >0; i--) {
 				if (e.dropCfg.el.get(i-1) != jQuery.iDrag.dragged) {
 					if (!e.sortCfg.floats) {
 						if ( 
-						(e.dropCfg.el.get(i-1).pos.y + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
+						(e.dropCfg.el.get(i-1).pos.y - tScroll.t + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny
 						) {
 							cur = e.dropCfg.el.get(i-1);
 						} else {
@@ -161,8 +164,8 @@
 						}
 					} else {
 						if (
-						(e.dropCfg.el.get(i-1).pos.x + e.dropCfg.el.get(i-1).pos.wb/2) > jQuery.iDrag.dragged.dragCfg.nx && 
-						(e.dropCfg.el.get(i-1).pos.y + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
+						(e.dropCfg.el.get(i-1).pos.x - tScroll.l + e.dropCfg.el.get(i-1).pos.wb/2) > jQuery.iDrag.dragged.dragCfg.nx &&
+						(e.dropCfg.el.get(i-1).pos.y - tScroll.t + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny
 						) {
 							cur = e.dropCfg.el.get(i-1);
 						}
Index: iutil.js
===================================================================
--- iutil.js	(revision 11)
+++ iutil.js	(working copy)
@@ -104,12 +104,16 @@
 	{
 		var t=0, l=0, w=0, h=0, iw=0, ih=0;
 		if (e && e.nodeName.toLowerCase() != 'body') {
-			t = e.scrollTop;
-			l = e.scrollLeft;
 			w = e.scrollWidth;
 			h = e.scrollHeight;
 			iw = 0;
 			ih = 0;
+			t = e.scrollTop;
+			l = e.scrollLeft;
+			while ((e = e.parentNode) && (e.nodeName.toLowerCase() != 'body')) {
+				t += e.scrollTop;
+				l += e.scrollLeft;
+			}
 		} else  {
 			if (document.documentElement) {
 				t = document.documentElement.scrollTop;

comment:2 Changed 12 years ago by scott.gonzal

Resolution: wontfix
Status: newclosed

Interface is no longer supported; consider switching to jQuery UI.

Note: See TracTickets for help on using tickets.