react-dnd / react-dnd-html5-backend

HTML5 backend for React DnD [Legacy Repo]
MIT License
146 stars 97 forks source link

Feature request: option to not block non-ReactDnD drag operations #7

Open Macil opened 9 years ago

Macil commented 9 years ago

Right now all drag-and-drop operations that aren't managed by React-DnD are blocked. On pages that already have non-React-DnD drag-and-drop-handling code, this causes things to break while React-DnD is active. An option to disable this behavior would be useful.

For the current time, I've put up a version of react-dnd-html5-backend that's patched to have this disabled on npm.

fixpunkt commented 8 years ago

I'm currently facing a similiar problem, so thanks @AgentME for providing a fork with npm packages! However, it doesn't quite fix my problem and I'm trying to figure out what's going wrong.

In HTML5Backend.prototype.handleTopDropCapture, you have the following code which will prevent the backend from calling event.preventDefault():

if (!this.monitor.isDragging()) {
  // This is probably a native item type we don't understand.
  return;
}

However, in my case this.monitor.isDragging() always returns true, because react-dnd will just treat my non-react draggable element as a native draggable. How can I actually prevent this from happening? Is there something I'm missing here?

Macil commented 8 years ago

because react-dnd will just treat my non-react draggable element as a native draggable

Are those terms not synonymous here?

fixpunkt commented 8 years ago

Actually, yes, I was not making the distincion clear enough. I have non-react draggables that should not be processed by react-dnd, which is what I understand your fork is designed for. However, react-dnd will recognize my draggables as native draggables and then try to process them anyway (because, apparently, you can drag non-react stuff into react-dnd containers), which will cause monitor.isDragging() to return true, which will cause the above check to fail, which will in turn call event.preventDefault() on the drop event for those draggables, which prevents CKEditor from processing them correctly.

To restate my question: If I want to keep react-dnd from not blocking other dnd operations, is there anything else I have to do besides switching to your fork? Like, calling event.stopPropagation() on the dragstart event of the draggables?

Macil commented 8 years ago

Oh, the issue is that I only needed and tested that this allows files to be dragged into the browser onto non-React-DnD dropzones. I didn't test draggable non-React-DnD elements. More changes will be needed to support that which I haven't looked into.

fixpunkt commented 8 years ago

Ok, good to know. I think I'll have a go tomorrow.

fixpunkt commented 8 years ago

So, I tried if I can keep monitor.isDragging() from returning true by stopping drag events from bubbling from the CKEditor, but this didn't work.

I ended up using the vanilla HTML5 backend, preventing all drag events from bubbling and monkeypatching HTML5Backend.handleTopDropCapture() to only run when the dragged element is not one of my native draggables inside the CKEditor.

It would be really nice to have a better way of doing this, but I can't figure anything out right now since I don't really understand the internal architecture of the backend. I think one possibility might be to just never call event.preventDefault() when the drag event doesn't get handled by react-dnd, but I'm not certain which consequences this entails.

nickbouton commented 8 years ago

+1 for @AgentME's original sentiment here. We're using AlloyEditor (a React component based on CKEditor as well) in conjunction with React-DnD in a project side-by-side and I noticed that React-DnD was somewhat greedily clobbering our ability to drag-and-drop images into the editor.

@AgentME's fork fixed this for me (thanks!), but it would be great if this were an option of some sort in the official supported project as well.

nickpresta commented 8 years ago

@gaearon Is there anything I can do to help get the @AgentME fork merged in? The changes look relatively straightforward, and I'm currently experiencing the pain with another file upload (via HTML5 dnd).

Is there something I'm missing or is this backend supposed to be all powerful and prevent bubbling?

Thanks!

EDIT

After taking a closer look, I understand that you may want to use DnD to handle native items, such as file upload, which is why the original code exists. It seems unlikely that the inclusion of a feature that ignores some items would be included (perhaps an option, though).

I decided to take a look at what @AgentME did in his fork and built a "local" non-native backend in our application.

Here is what I ended up doing: https://gist.github.com/nickpresta/eb5cce69d650db4c2795

Macil commented 8 years ago

I think merging my fork would make sense if the issue @fixpunkt brought up was fixed: my fork leaves non-DnD draggable items broken.

brianium commented 8 years ago

@AgentME thanks for this! Super helpful

ncphillips commented 8 years ago

What is the status of this issue?

Should I switch to the fork provided by @AgentME? or the gist that @nickpresta shared?

0rvar commented 7 years ago

This behaviour causes our CodeMirror instance to ignore drag and drop, it does nothing when e.defaultPrevented === true. Is a fork the way to go? Is this a perma-issue?

0rvar commented 7 years ago

We managed to solve our problem this way:

import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContext } from 'react-dnd';

const ModifiedBackend = (...args) => {
    const instance = new HTML5Backend(...args);

    const listeners = [
        'handleTopDragStart',
        'handleTopDragStartCapture',
        'handleTopDragEndCapture',
        'handleTopDragEnter',
        'handleTopDragEnterCapture',
        'handleTopDragLeaveCapture',
        'handleTopDragOver',
        'handleTopDragOverCapture',
        'handleTopDrop',
        'handleTopDropCapture'
    ];
    listeners.forEach(name => {
        const original = instance[name];
        instance[name] = (e, ...extraArgs) => {
            if (!shouldIgnoreTarget(e.target)) {
                original(e, ...extraArgs);
            }
        };
    });

    return instance;
};

// Decorate root elements with this
export default DragDropContext(ModifiedBackend);

This does however feel like a hack, and we'd prefer an official solution

angelikatyborska commented 7 years ago

I also had this issue. Mounting a DragDropContext component anywhere rendered useless all the onDragOver, onDragStart and onDragStop listeners I had on my other components.

What worked in my particular situation is, basing on @awestroke's hack, to disable preventDefault for just the handleTopDragStart listener:

const ModifiedBackend = (...args) => {
  const instance = new HTML5Backend(...args);
  const original = instance.handleTopDragStart;

  instance.handleTopDragStart = (e, ...extraArgs) => {
    e.preventDefault = () => {};
    original(e, ...extraArgs);
  };

  return instance;
};
squirmsound commented 7 years ago

@angelikatyborska Where would this function sit? <---- Stupid question. I neglected to read. ;)

ncphillips commented 7 years ago

@darthtrevino @gaearon This repo is apparently deprecated and the code moved into react-dnd, but as far as I'm aware this is still open. This issue has been around for 1.5 years without even being commented on by any core contributors. IMO this is a pretty serious issue in a project that's still getting 375+ downloads a month.

How should this issue be moved forward: should a new issue be opened in react-dnd; is this not even on the roadmap for react-dnd; or is this project even being maintained?

darthtrevino commented 7 years ago

Please cut an issue in the main repository. If you have a fix ready, feel free to cut a PR and tag me to review it