Jared Jared - 4 months ago 38
Javascript Question

HTML drag event does not fire in firefox

I have a table on which I need to implement draggable header columns. I implemented it using Chrome as my browser, and everything worked fine. When I tested it in Firefox (17.0.1), I noticed that the

drag
event doesn't fire.
dragstart
does, though. I simplified the problem in the markup below. When loaded in Chrome, the top label updates each time the mouse moves while dragging. In Firefox it remains 0.

<!DOCTYPE html>
<html>
<head>
<title>TH Drag Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<style>
table,td,th {
border: solid thin black;
}
</style>
<script>
$(document).ready(function() {
$("th").bind("drag", function(event) {
$("#lbl").html(event.originalEvent.offsetX);
});
});
</script>
</head>
<body>
<span id="lbl">0</span>
<table>
<thead>
<tr>
<th draggable="true">Column A</th>
<th draggable="true">Column B</th>
</tr>
</thead>
<tbody>
<tr>
<td>One</td>
<td>Two</td>
</tr>
<tr>
<td>Three</td>
<td>Four</td>
</tr>
</tbody>
</table>
</body>
</html>

Answer

The bit that has been cut out http://pastebin.com/bD2g3SqL

EDIT:

This does work, however I'm yet to find a way to access the offsetX and offsetY properties, for some reason FF version of the event does not contain them.

<!DOCTYPE html>
<html>
<head>
<title>TH Drag Test</title>
<style>
table,td,th {
    border: solid thin black;
}
</style>
<script>
    function Init(){
        var n= document.getElementsByTagName("th");
        var j=0;

        for (var i=0; i<n.length; i++){
            n[i].addEventListener('drag', function (e){
                document.getElementById("lbl").textContent= j++;
            }, false);
        }

        for (var i=0; i<n.length; i++){
            n[i].addEventListener('dragstart', function (e){
                e.dataTransfer.setData('text/plain', 'node');
            }, false);
        }
    }
</script>
</head>
<body onload="Init();">
    <span id="lbl"></span>
    <table>
        <thead>
            <tr>
                <th draggable="true">Column A</th>
                <th draggable="true">Column B</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>One</td>
                <td>Two</td>
            </tr>
            <tr>
                <td>Three</td>
                <td>Four</td>
            </tr>
        </tbody>
    </table>
</body>
</html>

Apparently, what you need to do is to "initialize" the drag (source.)

EDIT2:

Apparently, there's a bug in the drag event (go figure) which does not update the clientX and clientY properties (source.) They are updated on some other events, like the dragover event, however that event will fire only while the object is being dragged over a plausible drop target. A way out of such a silly situation would be something as crude as this:

<!DOCTYPE html>
<html>
<head>
<title>TH Drag Test</title>
<style>
table,td,th {
    border: solid thin black;
}
</style>
<script>    
    var down= false;

    document.onmousemove= OnMouseMove;

    function Init(){
        var n= document.getElementsByTagName('th');

        for (var i=0; i<n.length; i++){
            n[i].onmousedown= OnMouseDown;
        }

        document.onmouseup= OnMouseUp;
    }

    function OnMouseDown(e){
        down= true;
    }

    function OnMouseUp(e){
        down= false;
    }

    function OnMouseMove(e){
        if (!down) return;

        document.getElementById('lbl').textContent= e.pageX ? ('x: ' + e.pageX + ' y: ' + e.pageY) : ('x: ' + (e.clientX + document.documentElement.scrollLeft + document.body.scrollLeft) + ' y: ' + (e.clientY + document.documentElement.scrollTop + document.body.scrollTop));
    }

</script>
</head>
<body onload="Init();">
    <span id="lbl"></span>
    <table>
        <thead>
            <tr>
                <th draggable="true">Column A</th>
                <th draggable="true">Column B</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>One</td>
                <td>Two</td>
            </tr>
            <tr>
                <td>Three</td>
                <td>Four</td>
            </tr>
        </tbody>
    </table>
</body>
</html>