react-dnd-html5-backend icon indicating copy to clipboard operation
react-dnd-html5-backend copied to clipboard

Feature request: Include DataTransferItems in native sources.

Open 10xjs opened this issue 8 years ago • 0 comments

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);
  }
};

10xjs avatar Sep 12 '16 01:09 10xjs