react-dnd / react-dnd-html5-backend

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

Feature request: Include DataTransferItems in native sources. #47

Open 10xjs opened 8 years ago

10xjs commented 8 years ago

The DataTransferItems interface is the successor to the FilesList interface of DataTransfer objects. It's only currently supported by Chrome.

https://www.w3.org/TR/html51/editing.html#the-datatransfer-interface https://www.w3.org/TR/html51/editing.html#the-datatransferitemlist-interface

While the files property is not accessible on event.dataTransfer during drag events event, the items property is. This lets us respond to native drag data much earlier stage.


monkey patch 🙉

import HTML5Backend from 'react-dnd-html5-backend/lib/HTML5Backend';
import {isFirefox} from 'react-dnd-html5-backend/lib/BrowserDetector';
import {createNativeDragSource, matchNativeItemType}
  from 'react-dnd-html5-backend/lib/NativeDragSources';

HTML5Backend.prototype.updateCurrentNativeSourceItem = function(dataTransfer) {
  const items = Array.prototype.slice.call(dataTransfer.items || []);
  this.currentNativeSource.item.items = items;
};

// Wrapped methods:

const {handleTopDrop} = HTML5Backend.prototype;
HTML5Backend.prototype.handleTopDrop = function(e) {
  if (this.isDraggingNativeItem()) {
    this.updateCurrentNativeSourceItem(e.dataTransfer);
  }
  return handleTopDrop.call(this, e);
};

const {handleTopDragEnter} = HTML5Backend.prototype;
HTML5Backend.prototype.handleTopDragEnter = function(e) {
  if (this.isDraggingNativeItem()) {
    this.updateCurrentNativeSourceItem(e.dataTransfer);
  }
  return handleTopDragEnter.call(this, e);
};

const {handleTopDragOver} = HTML5Backend.prototype;
HTML5Backend.prototype.handleTopDragOver = function(e) {
  if (this.isDraggingNativeItem()) {
    this.updateCurrentNativeSourceItem(e.dataTransfer);
  }
  return handleTopDragOver.call(this, e);
};

// Patched methods:

HTML5Backend.prototype.handleTopDragEnterCapture = function(e) {
  this.dragEnterTargetIds = [];

  const isFirstEnter = this.enterLeaveCounter.enter(e.target);
  if (!isFirstEnter || this.monitor.isDragging()) {
    return;
  }

  const {dataTransfer} = e;
  const nativeType = matchNativeItemType(dataTransfer);

  if (nativeType) {
    this.beginDragNativeItem(nativeType/* PATCH */, dataTransfer/* END PATCH */);
  }
};

HTML5Backend.prototype.beginDragNativeItem = function(type, dataTransfer) {
  this.clearCurrentDragSourceNode();

  const SourceType = createNativeDragSource(type);
  this.currentNativeSource = new SourceType();
  /* PATCH */
  this.updateCurrentNativeSourceItem(dataTransfer);
  /* END PATCH*/
  this.currentNativeHandle = this.registry.addSource(type, this.currentNativeSource);
  this.actions.beginDrag([this.currentNativeHandle]);

  // On Firefox, if mousemove fires, the drag is over but browser failed to tell us.
  // This is not true for other browsers.
  if (isFirefox()) {
    window.addEventListener('mousemove', this.endDragNativeItem, true);
  }
};