Custom drag and drop Javascript does not work in firefox

Asked

Viewed 104 times

1

I’m making an XML reader to which I upload a file and it reads the content, in Chrome everything is working ok, but in firefox for some reason the drag and drop is not entering in $('#xmlenvio').change(..., I’m not looking for them to do for me, I just need to understand what is happening, because it does not generate any error in the console.

Firefox version: 61.0.2 (64-bit) Chrome version: 69.0.3497.92 (64-bit)

function dropHandler(ev) {
    ev.preventDefault();
    var file;

    if (ev.dataTransfer.items) {
        for (var i = 0; i < ev.dataTransfer.items.length; i++) {
            if (ev.dataTransfer.items[i].kind === 'file') {
                document.querySelector('#xmlEnvio').files = ev.dataTransfer.files;
            }
        }
    } 
    removeDragData(ev)
}

function dragOverHandler(ev) {
    ev.preventDefault();
}

function removeDragData(ev) {
    if (ev.dataTransfer.items) {
        ev.dataTransfer.items.clear();
    } else {
        ev.dataTransfer.clearData();
    }
}

$('#xmlEnvio').change(function(e){
    alert('chrome works');
    var input = this;
    file = input.files[0];
    $('.form-control.image-preview-filename').val(file.name);
    
    var reader = new FileReader();
    reader.onload = function() {
        var parsed = new DOMParser().parseFromString(this.result, "text/xml");
        
        console.log(parsed);
    }
    reader.readAsText(file);
    console.log('... file[' + 0 + '].name = ' + file.name);
});
.upload-drop-zone {
    height: 200px;
    border-width: 2px;
    margin-bottom: 20px;
}

.upload-drop-zone {
    color: #ccc;
    border-style: dashed;
    border-color: #ccc;
    line-height: 200px;
    text-align: center
}

.upload-drop-zone.drop {
    color: #222;
    border-color: #222;
}

.image-preview-input {
    position: relative;
    overflow: hidden;
    margin: 0px;    
    color: #333;
    background-color: #fff;
    border-color: #ccc;    
}
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container"> <br />
            <div class="col-sm-12 text-center"></div>
            <div class="col-sm-12">
                <div class="panel panel-default">
                    <form id="upload" action="#" method="POST" enctype="multipart/form-data" accept-charset="UTF-8">
                        <div class="panel-heading">
                            <strong>Select XML archive</strong>
                        </div>
                        <div class="panel-body">
                            <div class="input-group image-preview">
                                <input placeholder="" type="text" class="form-control image-preview-filename" disabled>
                                
                                <span class="input-group-btn"> 
                                    <div class="btn btn-default image-preview-input">
                                        <span class="glyphicon glyphicon-folder-open"></span>
                                        <span class="image-preview-input-title">Search</span>
                                        <input id="xmlEnvio" type="file" accept=".xml" name="xml"/>
                                    </div>
                                    <button type="submit" class="btn btn-labeled btn-primary">
                                        <span class="btn-label">
                                            <i class="glyphicon glyphicon-upload"></i>
                                        </span>
                                        Upload
                                    </button>
                                </span> </div>
                            <br />
                            <div ondrop="dropHandler(event)" ondragover="dragOverHandler(event);" class="upload-drop-zone" id="drop-zone">
                                Or drag XML to this area.
                            </div>
                        </div>
                    </form>
                </div>
            </div>	
        </div>
    </body>
</html>

2 answers

2

In Firefox, in this section, when you arrow the files in the input, the event is not triggered, already in Chrome it is triggered automatically.

document.querySelector('#xmlEnvio').files = ev.dataTransfer.files;

To fire manually, you can use the following code

document.querySelector('#xmlEnvio').dispatchEvent(new Event('change'));

The problem is that it will fire twice in Chrome.

But remember that you do NOT need to use input to parse Xmls. You can parse directly in dropHandler

function dropHandler(ev) {
    ev.preventDefault();

    const file = ev.dataTransfer.files[0];
    if ( ! file) return;

    const reader = new FileReader();
    reader.onload = function() {
        var parsed = new DOMParser().parseFromString(this.result, "text/xml");

        console.log('RESULT', parsed);
    }
    reader.readAsText(file);

    removeDragData(ev);
}

Editing: This way you can take advantage of the code and work cross-browser :)

function parseXML(file) {
    const reader = new FileReader();
    reader.onload = function() {
        const parsed = new DOMParser().parseFromString(this.result, "text/xml");

        console.log('RESULT', parsed);
    }
    reader.readAsText(file);
}

function dropHandler(ev) {
    ev.preventDefault();
    const file = ev.dataTransfer.files[0];
    parseXML(file);
    removeDragData(ev)
}

function dragOverHandler(ev) {
    ev.preventDefault();
}

function removeDragData(ev) {
    if (ev.dataTransfer.items) {
        ev.dataTransfer.items.clear();
    } else {
        ev.dataTransfer.clearData();
    }
}

$('#xmlEnvio').change(function(e){
    var input = this;
    const file = input.files[0];
    if ( ! file) return;

    parseXML(file);
});
  • I need it to stay on the onchange for the sake of reuse, as I will use the function both for the drag and drop issue and for when the client selects the file

  • As for shooting 2x in Chrome I had already found a "solution" in this way, but it is not satisfactory.

  • Easy, create a function called "parse" with Filereader reading, and call it in both dropHandler and onChange input

1


Firefox only triggers the change event if the user changes the field directly file, unlike in Chrome.

What you can do is trigger the event manually in the function removeDragData(), but this will trigger the change event 2 times in Chrome. To prevent the event from being triggered twice in Chrome, you can use a control variable. If the variable is true, event function is ignored with a return, if it’s false executes the function and changes the value to true and a setTimeout() of 1 second changes again to false. This way, when the event is triggered for the second time will enter the return and exit function.

Add a Trigger at the end of the function removeDragData(ev):

function removeDragData(ev) {
    if (ev.dataTransfer.items) {
        ev.dataTransfer.items.clear();
    } else {
        ev.dataTransfer.clearData();
    }

    $('#xmlEnvio').trigger('change');
}

Create a (global) control variable:

var mudou;

And at the start of the change event function enter 3 lines that handle the variable:

if(mudou) return;
mudou = true;
setTimeout(function(){ mudou = false }, 1000);

In the end, the code will stay this way:

function dropHandler(ev) {
   ev.preventDefault();
   var file;

   if (ev.dataTransfer.items) {
      for (var i = 0; i < ev.dataTransfer.items.length; i++) {
         if (ev.dataTransfer.items[i].kind === 'file') {
            document.querySelector('#xmlEnvio').files = ev.dataTransfer.files;
         }
      }
   } 
   removeDragData(ev)
}

function dragOverHandler(ev) {
    ev.preventDefault();
}

function removeDragData(ev) {
    if (ev.dataTransfer.items) {
        ev.dataTransfer.items.clear();
    } else {
        ev.dataTransfer.clearData();
    }

    $('#xmlEnvio').trigger('change');
}

var mudou;

$('#xmlEnvio').change(function(e){

   if(mudou) return;
   mudou = true;
   setTimeout(function(){ mudou = false }, 1000);

    alert('chrome works');
    var input = this;
    file = input.files[0];
    $('.form-control.image-preview-filename').val(file.name);

    var reader = new FileReader();
    reader.onload = function() {
        var parsed = new DOMParser().parseFromString(this.result, "text/xml");

        console.log(parsed);
    }
    reader.readAsText(file);
    console.log('... file[' + 0 + '].name = ' + file.name);
});

Browser other questions tagged

You are not signed in. Login or sign up in order to post.