Custom drag and drop Javascript does not work in firefox

1

I'm doing an XML reader to which I upload a file and it reads the contents, in chrome everything is working ok, however in firefox for some reason the drag and drop is not entering $('#xmlenvio').change(... , not I'm looking for them to do it for me, I just need to understand what's happening, because it does not generate any errors on 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><scriptsrc="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>
    
asked by anonymous 17.09.2018 / 21:11

2 answers

1

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

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

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

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

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

Create a control (global) variable:

var mudou;

And at the beginning of the change event function insert 3 lines that treat the variable:

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

At the end, the code looks like this:

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);
});
    
17.09.2018 / 23:48
2

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

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 the input to parse the 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 cross-browser code and work:)

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);
});
    
17.09.2018 / 21:54