PDA

View Full Version : Scrolling a page while using drag and drop



superzebe
07-03-2006, 06:23 PM
Sorry if this has already been covered, but I'm having a problem. I found a javascript file that showed how to drag and drop image files, and I converted it to create a drag and drop table, so you could drag table rows and drop them in a new spot, rearranging the order. That part works fine, however, I'm having a problem with lists that are larger than the viewable page. I need the page to scroll when I click and drag something to the bottom or top. I'm using the window.scrollBy method to scroll 5 units if I'm within 15 of the top or bottom. But, now I'm having a problem with the mouseover effects.

I have a function that runs when the mouse is over one of the other rows while dragging. It basically highlights acceptable target 'drop rows' as light blue. When the page scrolls, however, it loses the mouse position and highlights rows that are several rows above or below the mouse, depending on which way the page scrolls. I know this has to do with resetting some value whenever I scroll, i.e. if I scroll up 5 units, I need to adjust something else 5 units to make up for that, but I don't know what.

Any ideas?

djr33
07-03-2006, 07:49 PM
Very complex problem. No question that you need to link to your page.

superzebe
07-03-2006, 08:08 PM
There's a lot more but for the sake of simplifying things, here's the code for the MouseMove event and the TestOver function. The dragDiv (it's actually a span) is the item on the page that gets dragged visually, i.e. it represents the dragged row up until the mouse button is released, at which point a test is done to determine if it was over a drop target, and then the rows in the table are moved (the dragged row is inserted before the target row). If you need to see the entire js file, I can post that too.


function doMouseMove() {
// Check if mouse button is down and if an element is being dragged
if ((event.button == 1) && (elDragged != null)) {

// Set new position
var intTop = event.clientY + document.body.scrollTop;
var intLeft = event.clientX + document.body.scrollLeft;

dragDiv.style.pixelTop = intTop - 5;
dragDiv.style.pixelLeft = intLeft - 5;

// Check mouse location. Scroll page if near edge.
if (event.clientY > (document.body.offsetHeight - 15)) {
window.scrollBy(0,5);
}
else if (event.clientY < (15)) {
window.scrollBy(0,-5);
}

dragDiv._top = dragDiv.offsetTop + document.body.scrollTop;
dragDiv._left = dragDiv.offsetLeft + document.body.scrollLeft;

var s = "Y=" + event.clientY + " scrollTop=" + document.body.scrollTop + " intTop=" + intTop + " dragDiv._top=" + dragDiv._top;
var s2 = " dragDiv.offsetTop=" + dragDiv.offsetTop;
window.status = s + s2;

// Test if over target
testOver(dragDiv._left, dragDiv._top);
event.returnValue = false;
}
}

function testOver(iLeft, iTop) {
// Test if the element is over a valid drop-target
var hit = false;
if (elDragged.getAttribute("onDropTarget") != null) {
for (var intLoop=0; intLoop<elDragged._targets.length; intLoop++) {
// Check all drop-targets
var el = elDragged._elTargets[intLoop];
if (null!=el) {
if ((iTop > el._top) && (iLeft > el._left) && (iLeft < el.offsetWidth + el._left) && (iTop < el.offsetHeight + el._top))
{
elDragged.overTarget = el;
var hit = true;
elDragged._over[intLoop] = true;

// Fire events when over
if (event.type == "mouseup") {
if (el.getAttribute("onDropTarget") != null)
eval(el.getAttribute("onDropTarget"));
}
else
{
if (el.getAttribute("onOverTarget") != null)
eval(el.getAttribute("onOverTarget"));
}
}
else
{
// Fire event when leaving
if ((el.getAttribute("onOutTarget")!=null) && (elDragged._over[intLoop])) {
elDragged.overTarget= el;
eval(el.getAttribute("onOutTarget"));
}
elDragged._over[intLoop] = false;
}
}
}
}
return hit;
}

djr33
07-03-2006, 08:09 PM
This isn't going to make sense unless you can LINK to a page so we can see what's going on.

superzebe
07-03-2006, 08:13 PM
This is on an interal site at the moment. I'll try to set up a test page tonight that's viewable to the general public.

djr33
07-03-2006, 08:16 PM
Alright... there ya go, then.

superzebe
07-03-2006, 09:59 PM
Ok, the following two posts will be a sample htm file, followed by the .js file. Just copy and paste into notepad and put the files in the same folder and it should work.

I made a few changes since the first post, trying to fix this thing, so it's not exactly the same issue as I described, but the root cause is the same. You'll see after you try to drag a row a second time. It helps to shrink your browser window some as well, to force it to scroll when trying to drag below (or above) the viewable window. Basically, the highlighted row doesn't match up with the mouse cursor.

superzebe
07-03-2006, 09:59 PM
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>

</head>
<body bgcolor="#FFFFFF" LEFTMARGIN="1" TOPMARGIN="1" BOTTOMMARGIN="0" RIGHTMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0">

<form name="ctl00" method="post" action="ManageTabs.aspx?ItemId=3" id="ctl00" onsubmit="if(parseInt(document.forms[0].NewTabTextChange.value) == 0) {document.forms[0].Tab0.value='';}">
<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE4MjY4MjYzODBkZKyWslvXWH3yn3s+/Y243hiaqaJz" />
</div>

<script type="text/javascript">
<!--
var theForm = document.forms['ctl00'];
if (!theForm) {
theForm = document.ctl00;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// -->
</script>


<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td valign="top" align="left"> <br>
<span class="titles"><img src="../resources/icons/PortfolioManage.gif" align="absmiddle">
Manage
Portfolio Tabs<br>
<img src="../resources/images/pixel.gif" width="300" height="1" vspace="3"></span><br>
Using the options below, you can modify how tabs are displayed in Portfolio.You can change the display order by clicking
and dragging the tab item to a new location in the tab order.To add a new tab, type new tab name
and press "Save Changes".Then, using the dropdown box select the report to display for that tab
and press "Save Changes" again.<br>

</td>
</tr>
</table>
<br><table>
<tr>

<td>| <a href="ManagePreferences.aspx">Back to Preferences</a> |&nbsp;</a>
</td>

</tr>
</table>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="8" valign="top" class="tabs"><img src="../resources/images/corner_left.gif" width="8" height="8"></td>
<td class="tabs" width="190" Nowrap>&nbsp;&nbsp;&nbsp;<strong>Existing Tabs</strong>&nbsp;</td>
<td align="left" class="tabs"><strong>Default Summary Report</strong>&nbsp;</td>
<td width="16" align="right" valign="top" class="tabs"><img src="../resources/images/corner_right.gif" width="8" height="8"></td>
</tr>
</table>


<table width="100%" border="0" cellspacing="0" bordercolorlight="#CCCCCC" bordercolordark="#FFFFFF">
<tr valign="top">
<td>


<style>
.MoveableRow
{
cursor: move;
}
.MoveableRowCell
{
border-bottom: solid 1px #DDDDDD;
}
.MoveableRowFirstCell
{
border-bottom: solid 1px #DDDDDD;
bgcolor: #ffcc33;
}
</style>
<div>
<script type="text/javascript" language="javascript" src="DragAndDrop.js"></script>


<tr id="dropRow1" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab22" value="ConstMgmt" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow1" name="ReportIddropRow1" value="50" />
</tr>
<tr id="dropRow2" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab25" value="SCR2" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow2" name="ReportIddropRow2" value="74" />
</tr>
<tr id="dropRow3" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab27" value="Testing222Tab" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow3" name="ReportIddropRow3" value="161" />
</tr>
<tr id="dropRow4" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab23" value="Workflow" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow4" name="ReportIddropRow4" value="51" />
</tr>
<tr id="dropRow5" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab24" value="ALTL" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow5" name="ReportIddropRow5" value="160" />
</tr>
<tr id="dropRow6" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab39" value="Test 1" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow6" name="ReportIddropRow6" value="" />
</tr>
<tr id="dropRow7" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab40" value="Test 2" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow7" name="ReportIddropRow7" value="" />
</tr>
<tr id="dropRow8" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab41" value="Test 3" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow8" name="ReportIddropRow8" value="" />
</tr>
<tr id="dropRow9" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab42" value="Test 4" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow9" name="ReportIddropRow9" value="" />
</tr>
<tr id="dropRow10" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab43" value="Test 5" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow10" name="ReportIddropRow10" value="" />
</tr>
<tr id="dropRow11" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab44" value="Test 6" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow11" name="ReportIddropRow11" value="" />
</tr>
<tr id="dropRow12" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab45" value="Test 7" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow12" name="ReportIddropRow12" value="" />
</tr>
<tr id="dropRow13" dragEnabled onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" class="MoveableRow">

<td width="10" class="MoveableRowFirstCell">&nbsp;</td>
<td width="180" class="MoveableRowCell">
<input type="text" name="Tab46" value="Test 8" maxlength="14"> &nbsp;</td><input type="hidden" id="ReportIddropRow13" name="ReportIddropRow13" value="" />
</tr>


<span id="Dragger" dragEnabled STYLE="position: absolute; width: 25em; height: 1em;border: 1pt black solid; z-index: 10; background-color: LightGrey; display: none;" onOverTarget="doOverTarget()" onOutTarget="doOutTarget()" onDropTarget="DropItemHere()" dropTarget="dropRow1,dropRow2,dropRow3,dropRow4,dropRow5"></span>
</div>



<BR></td></tr>
</table>
<strong>Add a new tab</strong><BR>
<input type="hidden" name="NewTabTextChange" value="0">
<input type="text" name="Tab0" value="New tab name" onKeyPress="document.forms[0].NewTabTextChange.value='1';" maxlength="14" size="16"> <BR>

<input name="ctl01" type="submit" style="width:100" class="buttons" value="Save Changes" />
</td>
</tr>
</table>
</form>

</td></tr></table>

</td>
</tr>
</table></td>
</tr>
<tr>
<td align="left" valign="top" colspan="6" height="15">

<br>

</td>
</td>
</tr>
</table>
<p>&nbsp;</p>
</body>
</html>

superzebe
07-03-2006, 10:00 PM
/* The drag-drop framework is copyright 1997-98 insideDHTML.com, LLC.
This code can be reused as long as this entire comment is not removed.
For more information, see www.insideDHTML.com */

var elDragged = null; // Track drag-source in global variable.
var originalX = 0;
var originalY = 0;
var scrollOffset = 0;
var dragDiv;

function testOver(iLeft, iTop) {
window.status = window.status = " iTop=" + iTop;
// Test if the element is over a valid drop-target
var hit = false;
if (elDragged.getAttribute("onDropTarget") != null) {
for (var intLoop=0; intLoop<elDragged._targets.length; intLoop++) {
// Check all drop-targets
var el = elDragged._elTargets[intLoop];
if (null!=el) {
if ((iTop > el._top) && (iLeft > el._left) && (iLeft < el.offsetWidth + el._left) && (iTop < el.offsetHeight + el._top))
{
elDragged.overTarget = el;
var hit = true;
elDragged._over[intLoop] = true;

// Fire events when over
if (event.type == "mouseup") {
if (el.getAttribute("onDropTarget") != null)
eval(el.getAttribute("onDropTarget"));
}
else
{
if (el.getAttribute("onOverTarget") != null)
eval(el.getAttribute("onOverTarget"));
}
}
else
{
// Fire event when leaving
if ((el.getAttribute("onOutTarget")!=null) && (elDragged._over[intLoop])) {
elDragged.overTarget= el;
eval(el.getAttribute("onOutTarget"));
}
elDragged._over[intLoop] = false;
}
}
}
}
return hit;
}

function doMouseUp()
{
scrollOffset = 0;
if (elDragged != null)
{
elDragged.style.zIndex = 0;

if (testOver(dragDiv._left, dragDiv._top))
{
// Fire event on drag-source if dropped on target
if (elDragged.getAttribute("onTarget"))
{
eval(elDragged.getAttribute("onTarget"));
}
else if (elDragged.getAttribute("onNoTarget"))
eval(elDragged.getAttribute("onNoTarget"));
// Reset global variable
elDragged = null;
}
else
{
elDragged.style.pixelTop = originalY;
elDragged.style.pixelLeft = originalX;
}
}
if (dragDiv && dragDiv.style)
dragDiv.style.display = 'none';
}

function doMouseMove() {
// Check if mouse button is down and if an element is being dragged
if ((event.button == 1) && (elDragged != null)) {

// Set new position
var intTop = event.clientY + document.body.scrollTop;
var intLeft = event.clientX + document.body.scrollLeft;

dragDiv.style.pixelTop = intTop - 5;
dragDiv.style.pixelLeft = intLeft - 5;

dragDiv._top = dragDiv.offsetTop;
dragDiv._left = dragDiv.offsetLeft + document.body.scrollLeft;

var s = "Y=" + event.clientY + " scrollTop=" + document.body.scrollTop + " intTop=" + intTop + " dragDiv._top=" + dragDiv._top;
var s2 = " dragDiv.offsetTop=" + dragDiv.offsetTop;
window.status = s + s2;

// Test if over target
testOver(dragDiv._left, dragDiv._top);
event.returnValue = false;

// Check mouse location. Scroll page if near edge.
if (event.clientY > (document.body.offsetHeight - 15)) {
window.scrollBy(0,5);
}
else if (event.clientY < (15)) {
window.scrollBy(0,-5);
}
}
}

function checkDrag(elCheck) {
// Check if the clicked inside an element that supports dragging
// This allows rich HTML in drag-source
while (elCheck!=null) {
//Need to check if user clicks a control or link in the row. If so, return null.
if (elCheck.tagName == 'A' || elCheck.tagName == 'INPUT' || elCheck.tagName == 'SELECT')
return null;

if (null!=elCheck.getAttribute("dragEnabled"))
return elCheck;
elCheck = elCheck.parentElement;
}
return null
}

function doMouseDown() {
// On the mouse down, test if element can be dragged
var elCurrent = checkDrag(event.srcElement);

// For draggable elements, cache all calculations up front. This is for performance.
if (null != elCurrent) {
elDragged = elCurrent;

dragDiv = document.getElementById('Dragger');

dragDiv.style.pixelLeft = event.clientX + document.body.scrollLeft - 5;
dragDiv.style.pixelTop = event.clientY + document.body.scrollTop - 5;
dragDiv.style.display = '';
//dragDiv.innerHTML = elDragged.innerHTML;
dragDiv.innerHTML = '<--Drag this row to new destination-->';

// Make sure we are using pixel units everywhere
elDragged.style.top = elDragged.offsetTop + "px";
elDragged.style.left = elDragged.offsetLeft + "px";
var op = event.srcElement;

// Move the element
// Where the mouse is in the document
// Calculate what element the mouse is really in
var intLessTop = 0;
var intLessLeft = 0;
originalY = elDragged.offsetTop;
originalX = elDragged.offsetLeft;
var elCurrent = elDragged.offsetParent;

while (elCurrent != null) {
intLessTop += elCurrent.offsetTop;
intLessLeft += elCurrent.offsetLeft;
elCurrent = elCurrent.offsetParent;
}
elDragged._lessTop = intLessTop;
elDragged._lessLeft = intLessLeft;

// Calculate and cache target information
if (elDragged.parentNode && elDragged.parentNode.childNodes) {
//alert(elDragged.getAttribute("dropTarget").split(",").length);
//alert(elDragged.parentNode.childNodes.length);

elDragged._targets = elDragged.parentNode.childNodes; //get the parent of the dragged (the table) and then get its children (all the rows)
elDragged._over = new Array;
elDragged._elTargets = new Array;

for (var intLoop=0; intLoop < elDragged._targets.length; intLoop++) {
var el = document.all[elDragged._targets[intLoop].id]
if (null!=el) {
elDragged._elTargets[intLoop]= el;
var intLessTop = el.offsetTop;
var intLessLeft = el.offsetLeft;
var elCurrent = el.offsetParent;
var intTop = document.body.scrollTop;
var intLeft = document.body.scrollLeft;
while (elCurrent.offsetParent!=null) {
intLessTop+=elCurrent.offsetTop;
intLessLeft+=elCurrent.offsetLeft;
elCurrent = elCurrent.offsetParent;
}
el._top = intLessTop + intTop
el._left = intLessLeft + intLeft
}
}
}
}
}

function doDragTest() {
// Don't start text selections in dragged elements.
return (null==checkDrag(event.srcElement) && (elDragged==null))
}

// Process all mouse events.
document.onmousedown = doMouseDown;
document.onmousemove = doMouseMove;
document.onmouseup = doMouseUp;
document.ondragstart = doDragTest
document.onselectstart = doDragTest;

// Event handlers for demonstration
var originalBackgroundColor;

function doOverTarget() {
//Get the current background color, unless it's lightblue
if (elDragged.overTarget.currentStyle.backgroundColor != "lightblue")
originalBackgroundColor = elDragged.overTarget.currentStyle.backgroundColor;

//Set the background color of the moving row to lightblue
elDragged.overTarget.style.background = "lightblue";
}

function doOutTarget() {
elDragged.overTarget.style.background = originalBackgroundColor;
}

function DropItemHere() {
var DropTarget = elDragged.overTarget;
var DropItem = elDragged;
var parentTable;

//alert("Moved " + DropItem.id + " to " + DropTarget.id);

parentTable = DropTarget.parentNode;

while (parentTable.tagName != "TABLE")
parentTable = parentTable.parentNode;

var oTable = parentTable;

var itemRowNum, targetRowNum, row;

for (var i=0; i < oTable.rows.length; i++)
{
row = oTable.rows[i];

if (row.id == DropItem.id) {
itemRowNum = i; }
if (row.id == DropTarget.id) {
targetRowNum = i; }
row.style.background = originalBackgroundColor;
}

oTable.moveRow(itemRowNum, targetRowNum);
if(typeof(DoPageSpecificUpdates) == "function") DoPageSpecificUpdates(DropItem.id, targetRowNum); //This function is defined in the calling page
}

//window.scrollBy(0,50); // horizontal and vertical scroll increments