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>

Answers:

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>
Answer

I had nightmares fixing this issue for Firefox. I needed to drag a div onto a diary and detect the coordinates of the drop so I knew which date and time the user had selected.

To get the drag event to fire I added the below line to the dragstart event handler:

event.dataTransfer.setData('Text', this.id);

However, the hardest thing to work out was how to get the x and y coordinates when the drag ended, as these are not returned in the dragend event handler in Firefox. I tried using mouse events as mentioned above, but I found that these did not work while the drag is in progress and are only called after the dragend event handler has been called. So, I only used the dragend event to detect when the user had released the div, and then used the next mouse moved event to get the coordinates and do any other work that is required. I found this works in IE, Firefox and Chrome. Here is the html / javascript of a demo:

 <div>
<div id = "todrag" class = "testdiv" draggable="true"><p>Please drag me</p></div>

<div id = "destination" class = "testdiv"><p>To here</p></div>
<p id = "coords"></p>
<p id = "compareords"></p>
</div>

<script>
    var down = true;
    var m_xcoordDrag = 0;
    var m_ycoordDrag = 0;
    var m_xcoordMove = 0;
    var m_ycoordMove = 0;
    var m_dragReleased = false;
    var m_coordselement = document.getElementById("coords");
    var m_compareordselement = document.getElementById("compareords");

    function OnMouseMove(e) {
        m_xcoordMove = e.x;
        m_ycoordMove = e.y;
        m_coordselement.innerHTML = e.x + "," + e.y;

        if (m_dragReleased) {
            m_compareordselement.innerHTML = "X:" + m_xcoordDrag + ", " + m_xcoordMove + " Y:" + m_ycoordDrag + ", " + m_ycoordMove;

            m_dragReleased = false;
        }
    }

    dragstart = function (event) {

        event.dataTransfer.setData('Text', this.id);
        stop = false;
    }

    dragend = function (event) {
        m_dragReleased = true;

        m_xcoordDrag = event.x;
        m_ycoordDrag = event.y;
    }

    document.onmousemove = OnMouseMove;

    var toDrag = document.getElementById("todrag");

    toDrag.addEventListener('dragstart', dragstart);
    toDrag.addEventListener('dragend', dragend);

</script>

I hope this helps!

Answer

Firefox requires 'something' (that we call 'init' here) to be set in dragstart event to initialize the rest of drag events to occur.

This is probably because all of the DOM elements are draggable="true" by default in XUL. (reference: https://bugzilla.mozilla.org/show_bug.cgi?id=646823#c4)

Example:

<div id="something" draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'node');">Drag me</div>

Chrome doesn't require such 'initialization'.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.