Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove stopPropagation from drag&drop event handlers #144

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

enumag
Copy link

@enumag enumag commented Jan 28, 2016

I was trying to highlight the dropzone when a file is dragged but before he hovers the dropzone itself. Basically to show him where he should drag the files to.

I tried to solve it using this aproach.

It didn't work correctly because simple-ajax-uploader stopped propagation of the dragover event. After I removed it everything works fine.

Why was this event handler added? I presume there was some reason behind it.

@enumag
Copy link
Author

enumag commented Jan 28, 2016

Ok so the preventDefault actually needs to be called. I'm not sure why you added stopPropagation as well though - that's what causing my problems. When I remove the stopPropagation calles everything works fine.

@enumag enumag changed the title Remove dragover event handler Remove stopPropagation from drag&drop event handlers Jan 28, 2016
@enumag
Copy link
Author

enumag commented Jan 28, 2016

In my use case the stopPropagation needs to be removed only from dragover and drop. I removed it from dragenter just to be consistent.

@LPology
Copy link
Owner

LPology commented Jan 28, 2016

@enumag What browsers have you tested that in? stopPropagation was added according to Microsoft documentation:

https://msdn.microsoft.com/library/hh673539(v=vs.85).aspx

From their example:

function init() 
{
  // Set the drop-event handlers.
  var dropArea = document.getElementById("dropspot");
  dropArea.addEventListener("drop", dropHandler, false);
  dropArea.addEventListener("dragover", doNothing, false);
}

// Prevents the event from continuing so our handlers can process the event.
function doNothing(event)
{
  event.stopPropagation();
  event.preventDefault();
}

This example shows the same thing:

https://msdn.microsoft.com/en-us/library/hh580307(v=vs.85).aspx

@enumag
Copy link
Author

enumag commented Jan 28, 2016

I've tested in Firefox, Chrome and IE11.

Oh so you just copied it without knowing why? Well preventDefault stops the browser from doing its default operation - in this case opening the dragged file in the current tab - we need to do that for sure. StopPropagation halts bubbling of the event to make sure no other scripts will interfere with your own handler - I believe we don't actually need that.

@LPology
Copy link
Owner

LPology commented Jan 29, 2016

@enumag

First of all, the SO link you posted is a bad solution if you're trying to add a CSS class to a drop zone. That's because it uses dragover. The dragover event fires every 350ms, and it fires while dragging over the target. [0]

What you want instead is an event that fires once at the moment the drag enters the target. That would be the dragenter event.

Using stopPropagation on dragover is correct because it prevents dragover from being triggered on any parent elements. The problem is that your solution is bad. Making the code worse in order to accommodate a bad solution is the very definition of an anti-pattern.

So, to answer your question, no, I did not just copy that without knowing why.

Btw, the plugin's dragClass option is probably what you're looking for.

[0] https://www.w3.org/TR/2011/WD-html5-20110113/dnd.html

@enumag
Copy link
Author

enumag commented Jan 29, 2016

@LPology

I'm aware but dragenter doesn't really work in this case. Trust me, I've tried to get it working without dragover. It can't be done. The solution is bad but it's the only solution possible.

Letting the dragover event bubble isn't really a problem. JS constantly bubbles a lot of mouse-related events. Stopping propagation of one doesn't really make any difference. It doesn't make your code worse.

And no dragClass option is not what I'm looking for because I need to add the class before the cursor enters the dropzone - to show the user where the dropzone is. I want it to be invisible unless the user is trying to drag some files. That is why I bind the events to document and not the dropzone element and why dragenter doesn't work correctly and dragover has to be used.

@LPology
Copy link
Owner

LPology commented Jan 29, 2016

I misread your first comment. You're right, you can only use dragover to do that.

However, I disagree that letting dragover bubble couldn't be a problem. You're right about mouse events, but there is a difference. It is difficult to predict the intention of a user based on a mouse event. But when a user drags a file to upload, we can know they have one specific intention - to upload the file.

I submit that removing stopPropagation does make the code worse because we could no longer ensure that the behavior of the application matches that expectation.

On balance, the value of accommodating this specific use case doesn't justify losing that. For that reason, I am opposed to merging this change. I would be happy to consider any evidence that my opinion is wrong.

@enumag
Copy link
Author

enumag commented Jan 29, 2016

I do agree with yout that with the stopPropagation removed you can no longer be so sure about the behaviour. However the behavior could only break because of this by some other script listening to the same event and doing something bad. I believe that the probability of that happening is not very high because the drag events are not something commonly used (unlike normal mouse events). For this reason I believe that allowing such listeners for features like this outweights the disadvantages.

For now I managed to fix it by hacking your library without actually changing it. I still would prefer if this was merged though. Here is my code for anyone who might need it:

(function (ss) {

    // Fixes issue with dropzone highlighting.
    // @link https://github.com/LPology/Simple-Ajax-Uploader/pull/144

    var original = ss.SimpleUpload.prototype.addDropZone;

    ss.SimpleUpload.prototype.addDropZone = function (elem) {
        var self = this;

        original.call(self, elem);

        elem.ondragover = function(e) {
            e.preventDefault();
            return false;
        };

        elem.ondrop = function(e) {
            e.preventDefault();

            ss.removeClass(this, self._opts.dragClass);

            if (!self._dragFileCheck(e)) {
                return;
            }

            if (false !== self._addFiles(e.dataTransfer.files)) {
                self._cycleQueue();
            }
        };
    };

})(ss);

Thanks for your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants