You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1157 lines
40 KiB
1157 lines
40 KiB
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
(global = global || self, factory(global.ReactDnDHTML5Backend = {}));
|
|
}(this, (function (exports) { 'use strict';
|
|
|
|
// cheap lodash replacements
|
|
function memoize(fn) {
|
|
var result = null;
|
|
|
|
var memoized = function memoized() {
|
|
if (result == null) {
|
|
result = fn();
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
return memoized;
|
|
}
|
|
/**
|
|
* drop-in replacement for _.without
|
|
*/
|
|
|
|
function without(items, item) {
|
|
return items.filter(function (i) {
|
|
return i !== item;
|
|
});
|
|
}
|
|
function union(itemsA, itemsB) {
|
|
var set = new Set();
|
|
|
|
var insertItem = function insertItem(item) {
|
|
return set.add(item);
|
|
};
|
|
|
|
itemsA.forEach(insertItem);
|
|
itemsB.forEach(insertItem);
|
|
var result = [];
|
|
set.forEach(function (key) {
|
|
return result.push(key);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
var EnterLeaveCounter =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function EnterLeaveCounter(isNodeInDocument) {
|
|
_classCallCheck(this, EnterLeaveCounter);
|
|
|
|
this.entered = [];
|
|
this.isNodeInDocument = isNodeInDocument;
|
|
}
|
|
|
|
_createClass(EnterLeaveCounter, [{
|
|
key: "enter",
|
|
value: function enter(enteringNode) {
|
|
var _this = this;
|
|
|
|
var previousLength = this.entered.length;
|
|
|
|
var isNodeEntered = function isNodeEntered(node) {
|
|
return _this.isNodeInDocument(node) && (!node.contains || node.contains(enteringNode));
|
|
};
|
|
|
|
this.entered = union(this.entered.filter(isNodeEntered), [enteringNode]);
|
|
return previousLength === 0 && this.entered.length > 0;
|
|
}
|
|
}, {
|
|
key: "leave",
|
|
value: function leave(leavingNode) {
|
|
var previousLength = this.entered.length;
|
|
this.entered = without(this.entered.filter(this.isNodeInDocument), leavingNode);
|
|
return previousLength > 0 && this.entered.length === 0;
|
|
}
|
|
}, {
|
|
key: "reset",
|
|
value: function reset() {
|
|
this.entered = [];
|
|
}
|
|
}]);
|
|
|
|
return EnterLeaveCounter;
|
|
}();
|
|
|
|
var isFirefox = memoize(function () {
|
|
return /firefox/i.test(navigator.userAgent);
|
|
});
|
|
var isSafari = memoize(function () {
|
|
return Boolean(window.safari);
|
|
});
|
|
|
|
function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties$1(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass$1(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties$1(Constructor.prototype, protoProps); if (staticProps) _defineProperties$1(Constructor, staticProps); return Constructor; }
|
|
|
|
var MonotonicInterpolant =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function MonotonicInterpolant(xs, ys) {
|
|
_classCallCheck$1(this, MonotonicInterpolant);
|
|
|
|
var length = xs.length; // Rearrange xs and ys so that xs is sorted
|
|
|
|
var indexes = [];
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
indexes.push(i);
|
|
}
|
|
|
|
indexes.sort(function (a, b) {
|
|
return xs[a] < xs[b] ? -1 : 1;
|
|
}); // Get consecutive differences and slopes
|
|
var dxs = [];
|
|
var ms = [];
|
|
var dx;
|
|
var dy;
|
|
|
|
for (var _i = 0; _i < length - 1; _i++) {
|
|
dx = xs[_i + 1] - xs[_i];
|
|
dy = ys[_i + 1] - ys[_i];
|
|
dxs.push(dx);
|
|
ms.push(dy / dx);
|
|
} // Get degree-1 coefficients
|
|
|
|
|
|
var c1s = [ms[0]];
|
|
|
|
for (var _i2 = 0; _i2 < dxs.length - 1; _i2++) {
|
|
var m2 = ms[_i2];
|
|
var mNext = ms[_i2 + 1];
|
|
|
|
if (m2 * mNext <= 0) {
|
|
c1s.push(0);
|
|
} else {
|
|
dx = dxs[_i2];
|
|
var dxNext = dxs[_i2 + 1];
|
|
var common = dx + dxNext;
|
|
c1s.push(3 * common / ((common + dxNext) / m2 + (common + dx) / mNext));
|
|
}
|
|
}
|
|
|
|
c1s.push(ms[ms.length - 1]); // Get degree-2 and degree-3 coefficients
|
|
|
|
var c2s = [];
|
|
var c3s = [];
|
|
var m;
|
|
|
|
for (var _i3 = 0; _i3 < c1s.length - 1; _i3++) {
|
|
m = ms[_i3];
|
|
var c1 = c1s[_i3];
|
|
var invDx = 1 / dxs[_i3];
|
|
|
|
var _common = c1 + c1s[_i3 + 1] - m - m;
|
|
|
|
c2s.push((m - c1 - _common) * invDx);
|
|
c3s.push(_common * invDx * invDx);
|
|
}
|
|
|
|
this.xs = xs;
|
|
this.ys = ys;
|
|
this.c1s = c1s;
|
|
this.c2s = c2s;
|
|
this.c3s = c3s;
|
|
}
|
|
|
|
_createClass$1(MonotonicInterpolant, [{
|
|
key: "interpolate",
|
|
value: function interpolate(x) {
|
|
var xs = this.xs,
|
|
ys = this.ys,
|
|
c1s = this.c1s,
|
|
c2s = this.c2s,
|
|
c3s = this.c3s; // The rightmost point in the dataset should give an exact result
|
|
|
|
var i = xs.length - 1;
|
|
|
|
if (x === xs[i]) {
|
|
return ys[i];
|
|
} // Search for the interval x is in, returning the corresponding y if x is one of the original xs
|
|
|
|
|
|
var low = 0;
|
|
var high = c3s.length - 1;
|
|
var mid;
|
|
|
|
while (low <= high) {
|
|
mid = Math.floor(0.5 * (low + high));
|
|
var xHere = xs[mid];
|
|
|
|
if (xHere < x) {
|
|
low = mid + 1;
|
|
} else if (xHere > x) {
|
|
high = mid - 1;
|
|
} else {
|
|
return ys[mid];
|
|
}
|
|
}
|
|
|
|
i = Math.max(0, high); // Interpolate
|
|
|
|
var diff = x - xs[i];
|
|
var diffSq = diff * diff;
|
|
return ys[i] + c1s[i] * diff + c2s[i] * diffSq + c3s[i] * diff * diffSq;
|
|
}
|
|
}]);
|
|
|
|
return MonotonicInterpolant;
|
|
}();
|
|
|
|
var ELEMENT_NODE = 1;
|
|
function getNodeClientOffset(node) {
|
|
var el = node.nodeType === ELEMENT_NODE ? node : node.parentElement;
|
|
|
|
if (!el) {
|
|
return null;
|
|
}
|
|
|
|
var _el$getBoundingClient = el.getBoundingClientRect(),
|
|
top = _el$getBoundingClient.top,
|
|
left = _el$getBoundingClient.left;
|
|
|
|
return {
|
|
x: left,
|
|
y: top
|
|
};
|
|
}
|
|
function getEventClientOffset(e) {
|
|
return {
|
|
x: e.clientX,
|
|
y: e.clientY
|
|
};
|
|
}
|
|
|
|
function isImageNode(node) {
|
|
return node.nodeName === 'IMG' && (isFirefox() || !document.documentElement.contains(node));
|
|
}
|
|
|
|
function getDragPreviewSize(isImage, dragPreview, sourceWidth, sourceHeight) {
|
|
var dragPreviewWidth = isImage ? dragPreview.width : sourceWidth;
|
|
var dragPreviewHeight = isImage ? dragPreview.height : sourceHeight; // Work around @2x coordinate discrepancies in browsers
|
|
|
|
if (isSafari() && isImage) {
|
|
dragPreviewHeight /= window.devicePixelRatio;
|
|
dragPreviewWidth /= window.devicePixelRatio;
|
|
}
|
|
|
|
return {
|
|
dragPreviewWidth: dragPreviewWidth,
|
|
dragPreviewHeight: dragPreviewHeight
|
|
};
|
|
}
|
|
|
|
function getDragPreviewOffset(sourceNode, dragPreview, clientOffset, anchorPoint, offsetPoint) {
|
|
// The browsers will use the image intrinsic size under different conditions.
|
|
// Firefox only cares if it's an image, but WebKit also wants it to be detached.
|
|
var isImage = isImageNode(dragPreview);
|
|
var dragPreviewNode = isImage ? sourceNode : dragPreview;
|
|
var dragPreviewNodeOffsetFromClient = getNodeClientOffset(dragPreviewNode);
|
|
var offsetFromDragPreview = {
|
|
x: clientOffset.x - dragPreviewNodeOffsetFromClient.x,
|
|
y: clientOffset.y - dragPreviewNodeOffsetFromClient.y
|
|
};
|
|
var sourceWidth = sourceNode.offsetWidth,
|
|
sourceHeight = sourceNode.offsetHeight;
|
|
var anchorX = anchorPoint.anchorX,
|
|
anchorY = anchorPoint.anchorY;
|
|
|
|
var _getDragPreviewSize = getDragPreviewSize(isImage, dragPreview, sourceWidth, sourceHeight),
|
|
dragPreviewWidth = _getDragPreviewSize.dragPreviewWidth,
|
|
dragPreviewHeight = _getDragPreviewSize.dragPreviewHeight;
|
|
|
|
var calculateYOffset = function calculateYOffset() {
|
|
var interpolantY = new MonotonicInterpolant([0, 0.5, 1], [// Dock to the top
|
|
offsetFromDragPreview.y, // Align at the center
|
|
offsetFromDragPreview.y / sourceHeight * dragPreviewHeight, // Dock to the bottom
|
|
offsetFromDragPreview.y + dragPreviewHeight - sourceHeight]);
|
|
var y = interpolantY.interpolate(anchorY); // Work around Safari 8 positioning bug
|
|
|
|
if (isSafari() && isImage) {
|
|
// We'll have to wait for @3x to see if this is entirely correct
|
|
y += (window.devicePixelRatio - 1) * dragPreviewHeight;
|
|
}
|
|
|
|
return y;
|
|
};
|
|
|
|
var calculateXOffset = function calculateXOffset() {
|
|
// Interpolate coordinates depending on anchor point
|
|
// If you know a simpler way to do this, let me know
|
|
var interpolantX = new MonotonicInterpolant([0, 0.5, 1], [// Dock to the left
|
|
offsetFromDragPreview.x, // Align at the center
|
|
offsetFromDragPreview.x / sourceWidth * dragPreviewWidth, // Dock to the right
|
|
offsetFromDragPreview.x + dragPreviewWidth - sourceWidth]);
|
|
return interpolantX.interpolate(anchorX);
|
|
}; // Force offsets if specified in the options.
|
|
|
|
|
|
var offsetX = offsetPoint.offsetX,
|
|
offsetY = offsetPoint.offsetY;
|
|
var isManualOffsetX = offsetX === 0 || offsetX;
|
|
var isManualOffsetY = offsetY === 0 || offsetY;
|
|
return {
|
|
x: isManualOffsetX ? offsetX : calculateXOffset(),
|
|
y: isManualOffsetY ? offsetY : calculateYOffset()
|
|
};
|
|
}
|
|
|
|
var FILE = '__NATIVE_FILE__';
|
|
var URL = '__NATIVE_URL__';
|
|
var TEXT = '__NATIVE_TEXT__';
|
|
|
|
var NativeTypes = /*#__PURE__*/Object.freeze({
|
|
__proto__: null,
|
|
FILE: FILE,
|
|
URL: URL,
|
|
TEXT: TEXT
|
|
});
|
|
|
|
function getDataFromDataTransfer(dataTransfer, typesToTry, defaultValue) {
|
|
var result = typesToTry.reduce(function (resultSoFar, typeToTry) {
|
|
return resultSoFar || dataTransfer.getData(typeToTry);
|
|
}, '');
|
|
return result != null ? result : defaultValue;
|
|
}
|
|
|
|
var _nativeTypesConfig;
|
|
|
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
var nativeTypesConfig = (_nativeTypesConfig = {}, _defineProperty(_nativeTypesConfig, FILE, {
|
|
exposeProperties: {
|
|
files: function files(dataTransfer) {
|
|
return Array.prototype.slice.call(dataTransfer.files);
|
|
},
|
|
items: function items(dataTransfer) {
|
|
return dataTransfer.items;
|
|
}
|
|
},
|
|
matchesTypes: ['Files']
|
|
}), _defineProperty(_nativeTypesConfig, URL, {
|
|
exposeProperties: {
|
|
urls: function urls(dataTransfer, matchesTypes) {
|
|
return getDataFromDataTransfer(dataTransfer, matchesTypes, '').split('\n');
|
|
}
|
|
},
|
|
matchesTypes: ['Url', 'text/uri-list']
|
|
}), _defineProperty(_nativeTypesConfig, TEXT, {
|
|
exposeProperties: {
|
|
text: function text(dataTransfer, matchesTypes) {
|
|
return getDataFromDataTransfer(dataTransfer, matchesTypes, '');
|
|
}
|
|
},
|
|
matchesTypes: ['Text', 'text/plain']
|
|
}), _nativeTypesConfig);
|
|
|
|
function _classCallCheck$2(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties$2(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass$2(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties$2(Constructor.prototype, protoProps); if (staticProps) _defineProperties$2(Constructor, staticProps); return Constructor; }
|
|
|
|
var NativeDragSource =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function NativeDragSource(config) {
|
|
_classCallCheck$2(this, NativeDragSource);
|
|
|
|
this.config = config;
|
|
this.item = {};
|
|
this.initializeExposedProperties();
|
|
}
|
|
|
|
_createClass$2(NativeDragSource, [{
|
|
key: "initializeExposedProperties",
|
|
value: function initializeExposedProperties() {
|
|
var _this = this;
|
|
|
|
Object.keys(this.config.exposeProperties).forEach(function (property) {
|
|
Object.defineProperty(_this.item, property, {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: function get() {
|
|
// eslint-disable-next-line no-console
|
|
console.warn("Browser doesn't allow reading \"".concat(property, "\" until the drop event."));
|
|
return null;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}, {
|
|
key: "loadDataTransfer",
|
|
value: function loadDataTransfer(dataTransfer) {
|
|
var _this2 = this;
|
|
|
|
if (dataTransfer) {
|
|
var newProperties = {};
|
|
Object.keys(this.config.exposeProperties).forEach(function (property) {
|
|
newProperties[property] = {
|
|
value: _this2.config.exposeProperties[property](dataTransfer, _this2.config.matchesTypes),
|
|
configurable: true,
|
|
enumerable: true
|
|
};
|
|
});
|
|
Object.defineProperties(this.item, newProperties);
|
|
}
|
|
}
|
|
}, {
|
|
key: "canDrag",
|
|
value: function canDrag() {
|
|
return true;
|
|
}
|
|
}, {
|
|
key: "beginDrag",
|
|
value: function beginDrag() {
|
|
return this.item;
|
|
}
|
|
}, {
|
|
key: "isDragging",
|
|
value: function isDragging(monitor, handle) {
|
|
return handle === monitor.getSourceId();
|
|
}
|
|
}, {
|
|
key: "endDrag",
|
|
value: function endDrag() {// empty
|
|
}
|
|
}]);
|
|
|
|
return NativeDragSource;
|
|
}();
|
|
|
|
function createNativeDragSource(type, dataTransfer) {
|
|
var result = new NativeDragSource(nativeTypesConfig[type]);
|
|
result.loadDataTransfer(dataTransfer);
|
|
return result;
|
|
}
|
|
function matchNativeItemType(dataTransfer) {
|
|
if (!dataTransfer) {
|
|
return null;
|
|
}
|
|
|
|
var dataTransferTypes = Array.prototype.slice.call(dataTransfer.types || []);
|
|
return Object.keys(nativeTypesConfig).filter(function (nativeItemType) {
|
|
var matchesTypes = nativeTypesConfig[nativeItemType].matchesTypes;
|
|
return matchesTypes.some(function (t) {
|
|
return dataTransferTypes.indexOf(t) > -1;
|
|
});
|
|
})[0] || null;
|
|
}
|
|
|
|
function _classCallCheck$3(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties$3(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass$3(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties$3(Constructor.prototype, protoProps); if (staticProps) _defineProperties$3(Constructor, staticProps); return Constructor; }
|
|
|
|
var OptionsReader =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function OptionsReader(globalContext) {
|
|
_classCallCheck$3(this, OptionsReader);
|
|
|
|
this.globalContext = globalContext;
|
|
}
|
|
|
|
_createClass$3(OptionsReader, [{
|
|
key: "window",
|
|
get: function get() {
|
|
if (this.globalContext) {
|
|
return this.globalContext;
|
|
} else if (typeof window !== 'undefined') {
|
|
return window;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
}, {
|
|
key: "document",
|
|
get: function get() {
|
|
if (this.window) {
|
|
return this.window.document;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
}]);
|
|
|
|
return OptionsReader;
|
|
}();
|
|
|
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
|
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty$1(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
|
|
function _defineProperty$1(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
|
|
function _classCallCheck$4(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties$4(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass$4(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties$4(Constructor.prototype, protoProps); if (staticProps) _defineProperties$4(Constructor, staticProps); return Constructor; }
|
|
|
|
var HTML5Backend =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function HTML5Backend(manager, globalContext) {
|
|
var _this = this;
|
|
|
|
_classCallCheck$4(this, HTML5Backend);
|
|
|
|
this.sourcePreviewNodes = new Map();
|
|
this.sourcePreviewNodeOptions = new Map();
|
|
this.sourceNodes = new Map();
|
|
this.sourceNodeOptions = new Map();
|
|
this.dragStartSourceIds = null;
|
|
this.dropTargetIds = [];
|
|
this.dragEnterTargetIds = [];
|
|
this.currentNativeSource = null;
|
|
this.currentNativeHandle = null;
|
|
this.currentDragSourceNode = null;
|
|
this.altKeyPressed = false;
|
|
this.mouseMoveTimeoutTimer = null;
|
|
this.asyncEndDragFrameId = null;
|
|
this.dragOverTargetIds = null;
|
|
|
|
this.getSourceClientOffset = function (sourceId) {
|
|
return getNodeClientOffset(_this.sourceNodes.get(sourceId));
|
|
};
|
|
|
|
this.endDragNativeItem = function () {
|
|
if (!_this.isDraggingNativeItem()) {
|
|
return;
|
|
}
|
|
|
|
_this.actions.endDrag();
|
|
|
|
_this.registry.removeSource(_this.currentNativeHandle);
|
|
|
|
_this.currentNativeHandle = null;
|
|
_this.currentNativeSource = null;
|
|
};
|
|
|
|
this.isNodeInDocument = function (node) {
|
|
// Check the node either in the main document or in the current context
|
|
return _this.document && _this.document.body && document.body.contains(node);
|
|
};
|
|
|
|
this.endDragIfSourceWasRemovedFromDOM = function () {
|
|
var node = _this.currentDragSourceNode;
|
|
|
|
if (_this.isNodeInDocument(node)) {
|
|
return;
|
|
}
|
|
|
|
if (_this.clearCurrentDragSourceNode()) {
|
|
_this.actions.endDrag();
|
|
}
|
|
};
|
|
|
|
this.handleTopDragStartCapture = function () {
|
|
_this.clearCurrentDragSourceNode();
|
|
|
|
_this.dragStartSourceIds = [];
|
|
};
|
|
|
|
this.handleTopDragStart = function (e) {
|
|
if (e.defaultPrevented) {
|
|
return;
|
|
}
|
|
|
|
var dragStartSourceIds = _this.dragStartSourceIds;
|
|
_this.dragStartSourceIds = null;
|
|
var clientOffset = getEventClientOffset(e); // Avoid crashing if we missed a drop event or our previous drag died
|
|
|
|
if (_this.monitor.isDragging()) {
|
|
_this.actions.endDrag();
|
|
} // Don't publish the source just yet (see why below)
|
|
|
|
|
|
_this.actions.beginDrag(dragStartSourceIds || [], {
|
|
publishSource: false,
|
|
getSourceClientOffset: _this.getSourceClientOffset,
|
|
clientOffset: clientOffset
|
|
});
|
|
|
|
var dataTransfer = e.dataTransfer;
|
|
var nativeType = matchNativeItemType(dataTransfer);
|
|
|
|
if (_this.monitor.isDragging()) {
|
|
if (dataTransfer && typeof dataTransfer.setDragImage === 'function') {
|
|
// Use custom drag image if user specifies it.
|
|
// If child drag source refuses drag but parent agrees,
|
|
// use parent's node as drag image. Neither works in IE though.
|
|
var sourceId = _this.monitor.getSourceId();
|
|
|
|
var sourceNode = _this.sourceNodes.get(sourceId);
|
|
|
|
var dragPreview = _this.sourcePreviewNodes.get(sourceId) || sourceNode;
|
|
|
|
if (dragPreview) {
|
|
var _this$getCurrentSourc = _this.getCurrentSourcePreviewNodeOptions(),
|
|
anchorX = _this$getCurrentSourc.anchorX,
|
|
anchorY = _this$getCurrentSourc.anchorY,
|
|
offsetX = _this$getCurrentSourc.offsetX,
|
|
offsetY = _this$getCurrentSourc.offsetY;
|
|
|
|
var anchorPoint = {
|
|
anchorX: anchorX,
|
|
anchorY: anchorY
|
|
};
|
|
var offsetPoint = {
|
|
offsetX: offsetX,
|
|
offsetY: offsetY
|
|
};
|
|
var dragPreviewOffset = getDragPreviewOffset(sourceNode, dragPreview, clientOffset, anchorPoint, offsetPoint);
|
|
dataTransfer.setDragImage(dragPreview, dragPreviewOffset.x, dragPreviewOffset.y);
|
|
}
|
|
}
|
|
|
|
try {
|
|
// Firefox won't drag without setting data
|
|
dataTransfer.setData('application/json', {});
|
|
} catch (err) {} // IE doesn't support MIME types in setData
|
|
// Store drag source node so we can check whether
|
|
// it is removed from DOM and trigger endDrag manually.
|
|
|
|
|
|
_this.setCurrentDragSourceNode(e.target); // Now we are ready to publish the drag source.. or are we not?
|
|
|
|
|
|
var _this$getCurrentSourc2 = _this.getCurrentSourcePreviewNodeOptions(),
|
|
captureDraggingState = _this$getCurrentSourc2.captureDraggingState;
|
|
|
|
if (!captureDraggingState) {
|
|
// Usually we want to publish it in the next tick so that browser
|
|
// is able to screenshot the current (not yet dragging) state.
|
|
//
|
|
// It also neatly avoids a situation where render() returns null
|
|
// in the same tick for the source element, and browser freaks out.
|
|
setTimeout(function () {
|
|
return _this.actions.publishDragSource();
|
|
}, 0);
|
|
} else {
|
|
// In some cases the user may want to override this behavior, e.g.
|
|
// to work around IE not supporting custom drag previews.
|
|
//
|
|
// When using a custom drag layer, the only way to prevent
|
|
// the default drag preview from drawing in IE is to screenshot
|
|
// the dragging state in which the node itself has zero opacity
|
|
// and height. In this case, though, returning null from render()
|
|
// will abruptly end the dragging, which is not obvious.
|
|
//
|
|
// This is the reason such behavior is strictly opt-in.
|
|
_this.actions.publishDragSource();
|
|
}
|
|
} else if (nativeType) {
|
|
// A native item (such as URL) dragged from inside the document
|
|
_this.beginDragNativeItem(nativeType);
|
|
} else if (dataTransfer && !dataTransfer.types && (e.target && !e.target.hasAttribute || !e.target.hasAttribute('draggable'))) {
|
|
// Looks like a Safari bug: dataTransfer.types is null, but there was no draggable.
|
|
// Just let it drag. It's a native type (URL or text) and will be picked up in
|
|
// dragenter handler.
|
|
return;
|
|
} else {
|
|
// If by this time no drag source reacted, tell browser not to drag.
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
|
|
this.handleTopDragEndCapture = function () {
|
|
if (_this.clearCurrentDragSourceNode()) {
|
|
// Firefox can dispatch this event in an infinite loop
|
|
// if dragend handler does something like showing an alert.
|
|
// Only proceed if we have not handled it already.
|
|
_this.actions.endDrag();
|
|
}
|
|
};
|
|
|
|
this.handleTopDragEnterCapture = function (e) {
|
|
_this.dragEnterTargetIds = [];
|
|
|
|
var isFirstEnter = _this.enterLeaveCounter.enter(e.target);
|
|
|
|
if (!isFirstEnter || _this.monitor.isDragging()) {
|
|
return;
|
|
}
|
|
|
|
var dataTransfer = e.dataTransfer;
|
|
var nativeType = matchNativeItemType(dataTransfer);
|
|
|
|
if (nativeType) {
|
|
// A native item (such as file or URL) dragged from outside the document
|
|
_this.beginDragNativeItem(nativeType, dataTransfer);
|
|
}
|
|
};
|
|
|
|
this.handleTopDragEnter = function (e) {
|
|
var dragEnterTargetIds = _this.dragEnterTargetIds;
|
|
_this.dragEnterTargetIds = [];
|
|
|
|
if (!_this.monitor.isDragging()) {
|
|
// This is probably a native item type we don't understand.
|
|
return;
|
|
}
|
|
|
|
_this.altKeyPressed = e.altKey;
|
|
|
|
if (!isFirefox()) {
|
|
// Don't emit hover in `dragenter` on Firefox due to an edge case.
|
|
// If the target changes position as the result of `dragenter`, Firefox
|
|
// will still happily dispatch `dragover` despite target being no longer
|
|
// there. The easy solution is to only fire `hover` in `dragover` on FF.
|
|
_this.actions.hover(dragEnterTargetIds, {
|
|
clientOffset: getEventClientOffset(e)
|
|
});
|
|
}
|
|
|
|
var canDrop = dragEnterTargetIds.some(function (targetId) {
|
|
return _this.monitor.canDropOnTarget(targetId);
|
|
});
|
|
|
|
if (canDrop) {
|
|
// IE requires this to fire dragover events
|
|
e.preventDefault();
|
|
|
|
if (e.dataTransfer) {
|
|
e.dataTransfer.dropEffect = _this.getCurrentDropEffect();
|
|
}
|
|
}
|
|
};
|
|
|
|
this.handleTopDragOverCapture = function () {
|
|
_this.dragOverTargetIds = [];
|
|
};
|
|
|
|
this.handleTopDragOver = function (e) {
|
|
var dragOverTargetIds = _this.dragOverTargetIds;
|
|
_this.dragOverTargetIds = [];
|
|
|
|
if (!_this.monitor.isDragging()) {
|
|
// This is probably a native item type we don't understand.
|
|
// Prevent default "drop and blow away the whole document" action.
|
|
e.preventDefault();
|
|
|
|
if (e.dataTransfer) {
|
|
e.dataTransfer.dropEffect = 'none';
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
_this.altKeyPressed = e.altKey;
|
|
|
|
_this.actions.hover(dragOverTargetIds || [], {
|
|
clientOffset: getEventClientOffset(e)
|
|
});
|
|
|
|
var canDrop = (dragOverTargetIds || []).some(function (targetId) {
|
|
return _this.monitor.canDropOnTarget(targetId);
|
|
});
|
|
|
|
if (canDrop) {
|
|
// Show user-specified drop effect.
|
|
e.preventDefault();
|
|
|
|
if (e.dataTransfer) {
|
|
e.dataTransfer.dropEffect = _this.getCurrentDropEffect();
|
|
}
|
|
} else if (_this.isDraggingNativeItem()) {
|
|
// Don't show a nice cursor but still prevent default
|
|
// "drop and blow away the whole document" action.
|
|
e.preventDefault();
|
|
} else {
|
|
e.preventDefault();
|
|
|
|
if (e.dataTransfer) {
|
|
e.dataTransfer.dropEffect = 'none';
|
|
}
|
|
}
|
|
};
|
|
|
|
this.handleTopDragLeaveCapture = function (e) {
|
|
if (_this.isDraggingNativeItem()) {
|
|
e.preventDefault();
|
|
}
|
|
|
|
var isLastLeave = _this.enterLeaveCounter.leave(e.target);
|
|
|
|
if (!isLastLeave) {
|
|
return;
|
|
}
|
|
|
|
if (_this.isDraggingNativeItem()) {
|
|
_this.endDragNativeItem();
|
|
}
|
|
};
|
|
|
|
this.handleTopDropCapture = function (e) {
|
|
_this.dropTargetIds = [];
|
|
e.preventDefault();
|
|
|
|
if (_this.isDraggingNativeItem()) {
|
|
_this.currentNativeSource.loadDataTransfer(e.dataTransfer);
|
|
}
|
|
|
|
_this.enterLeaveCounter.reset();
|
|
};
|
|
|
|
this.handleTopDrop = function (e) {
|
|
var dropTargetIds = _this.dropTargetIds;
|
|
_this.dropTargetIds = [];
|
|
|
|
_this.actions.hover(dropTargetIds, {
|
|
clientOffset: getEventClientOffset(e)
|
|
});
|
|
|
|
_this.actions.drop({
|
|
dropEffect: _this.getCurrentDropEffect()
|
|
});
|
|
|
|
if (_this.isDraggingNativeItem()) {
|
|
_this.endDragNativeItem();
|
|
} else {
|
|
_this.endDragIfSourceWasRemovedFromDOM();
|
|
}
|
|
};
|
|
|
|
this.handleSelectStart = function (e) {
|
|
var target = e.target; // Only IE requires us to explicitly say
|
|
// we want drag drop operation to start
|
|
|
|
if (typeof target.dragDrop !== 'function') {
|
|
return;
|
|
} // Inputs and textareas should be selectable
|
|
|
|
|
|
if (target.tagName === 'INPUT' || target.tagName === 'SELECT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
|
|
return;
|
|
} // For other targets, ask IE
|
|
// to enable drag and drop
|
|
|
|
|
|
e.preventDefault();
|
|
target.dragDrop();
|
|
};
|
|
|
|
this.options = new OptionsReader(globalContext);
|
|
this.actions = manager.getActions();
|
|
this.monitor = manager.getMonitor();
|
|
this.registry = manager.getRegistry();
|
|
this.enterLeaveCounter = new EnterLeaveCounter(this.isNodeInDocument);
|
|
} // public for test
|
|
|
|
|
|
_createClass$4(HTML5Backend, [{
|
|
key: "setup",
|
|
value: function setup() {
|
|
if (this.window === undefined) {
|
|
return;
|
|
}
|
|
|
|
if (this.window.__isReactDndBackendSetUp) {
|
|
throw new Error('Cannot have two HTML5 backends at the same time.');
|
|
}
|
|
|
|
this.window.__isReactDndBackendSetUp = true;
|
|
this.addEventListeners(this.window);
|
|
}
|
|
}, {
|
|
key: "teardown",
|
|
value: function teardown() {
|
|
if (this.window === undefined) {
|
|
return;
|
|
}
|
|
|
|
this.window.__isReactDndBackendSetUp = false;
|
|
this.removeEventListeners(this.window);
|
|
this.clearCurrentDragSourceNode();
|
|
|
|
if (this.asyncEndDragFrameId) {
|
|
this.window.cancelAnimationFrame(this.asyncEndDragFrameId);
|
|
}
|
|
}
|
|
}, {
|
|
key: "connectDragPreview",
|
|
value: function connectDragPreview(sourceId, node, options) {
|
|
var _this2 = this;
|
|
|
|
this.sourcePreviewNodeOptions.set(sourceId, options);
|
|
this.sourcePreviewNodes.set(sourceId, node);
|
|
return function () {
|
|
_this2.sourcePreviewNodes.delete(sourceId);
|
|
|
|
_this2.sourcePreviewNodeOptions.delete(sourceId);
|
|
};
|
|
}
|
|
}, {
|
|
key: "connectDragSource",
|
|
value: function connectDragSource(sourceId, node, options) {
|
|
var _this3 = this;
|
|
|
|
this.sourceNodes.set(sourceId, node);
|
|
this.sourceNodeOptions.set(sourceId, options);
|
|
|
|
var handleDragStart = function handleDragStart(e) {
|
|
return _this3.handleDragStart(e, sourceId);
|
|
};
|
|
|
|
var handleSelectStart = function handleSelectStart(e) {
|
|
return _this3.handleSelectStart(e);
|
|
};
|
|
|
|
node.setAttribute('draggable', 'true');
|
|
node.addEventListener('dragstart', handleDragStart);
|
|
node.addEventListener('selectstart', handleSelectStart);
|
|
return function () {
|
|
_this3.sourceNodes.delete(sourceId);
|
|
|
|
_this3.sourceNodeOptions.delete(sourceId);
|
|
|
|
node.removeEventListener('dragstart', handleDragStart);
|
|
node.removeEventListener('selectstart', handleSelectStart);
|
|
node.setAttribute('draggable', 'false');
|
|
};
|
|
}
|
|
}, {
|
|
key: "connectDropTarget",
|
|
value: function connectDropTarget(targetId, node) {
|
|
var _this4 = this;
|
|
|
|
var handleDragEnter = function handleDragEnter(e) {
|
|
return _this4.handleDragEnter(e, targetId);
|
|
};
|
|
|
|
var handleDragOver = function handleDragOver(e) {
|
|
return _this4.handleDragOver(e, targetId);
|
|
};
|
|
|
|
var handleDrop = function handleDrop(e) {
|
|
return _this4.handleDrop(e, targetId);
|
|
};
|
|
|
|
node.addEventListener('dragenter', handleDragEnter);
|
|
node.addEventListener('dragover', handleDragOver);
|
|
node.addEventListener('drop', handleDrop);
|
|
return function () {
|
|
node.removeEventListener('dragenter', handleDragEnter);
|
|
node.removeEventListener('dragover', handleDragOver);
|
|
node.removeEventListener('drop', handleDrop);
|
|
};
|
|
}
|
|
}, {
|
|
key: "addEventListeners",
|
|
value: function addEventListeners(target) {
|
|
// SSR Fix (https://github.com/react-dnd/react-dnd/pull/813
|
|
if (!target.addEventListener) {
|
|
return;
|
|
}
|
|
|
|
target.addEventListener('dragstart', this.handleTopDragStart);
|
|
target.addEventListener('dragstart', this.handleTopDragStartCapture, true);
|
|
target.addEventListener('dragend', this.handleTopDragEndCapture, true);
|
|
target.addEventListener('dragenter', this.handleTopDragEnter);
|
|
target.addEventListener('dragenter', this.handleTopDragEnterCapture, true);
|
|
target.addEventListener('dragleave', this.handleTopDragLeaveCapture, true);
|
|
target.addEventListener('dragover', this.handleTopDragOver);
|
|
target.addEventListener('dragover', this.handleTopDragOverCapture, true);
|
|
target.addEventListener('drop', this.handleTopDrop);
|
|
target.addEventListener('drop', this.handleTopDropCapture, true);
|
|
}
|
|
}, {
|
|
key: "removeEventListeners",
|
|
value: function removeEventListeners(target) {
|
|
// SSR Fix (https://github.com/react-dnd/react-dnd/pull/813
|
|
if (!target.removeEventListener) {
|
|
return;
|
|
}
|
|
|
|
target.removeEventListener('dragstart', this.handleTopDragStart);
|
|
target.removeEventListener('dragstart', this.handleTopDragStartCapture, true);
|
|
target.removeEventListener('dragend', this.handleTopDragEndCapture, true);
|
|
target.removeEventListener('dragenter', this.handleTopDragEnter);
|
|
target.removeEventListener('dragenter', this.handleTopDragEnterCapture, true);
|
|
target.removeEventListener('dragleave', this.handleTopDragLeaveCapture, true);
|
|
target.removeEventListener('dragover', this.handleTopDragOver);
|
|
target.removeEventListener('dragover', this.handleTopDragOverCapture, true);
|
|
target.removeEventListener('drop', this.handleTopDrop);
|
|
target.removeEventListener('drop', this.handleTopDropCapture, true);
|
|
}
|
|
}, {
|
|
key: "getCurrentSourceNodeOptions",
|
|
value: function getCurrentSourceNodeOptions() {
|
|
var sourceId = this.monitor.getSourceId();
|
|
var sourceNodeOptions = this.sourceNodeOptions.get(sourceId);
|
|
return _objectSpread({
|
|
dropEffect: this.altKeyPressed ? 'copy' : 'move'
|
|
}, sourceNodeOptions || {});
|
|
}
|
|
}, {
|
|
key: "getCurrentDropEffect",
|
|
value: function getCurrentDropEffect() {
|
|
if (this.isDraggingNativeItem()) {
|
|
// It makes more sense to default to 'copy' for native resources
|
|
return 'copy';
|
|
}
|
|
|
|
return this.getCurrentSourceNodeOptions().dropEffect;
|
|
}
|
|
}, {
|
|
key: "getCurrentSourcePreviewNodeOptions",
|
|
value: function getCurrentSourcePreviewNodeOptions() {
|
|
var sourceId = this.monitor.getSourceId();
|
|
var sourcePreviewNodeOptions = this.sourcePreviewNodeOptions.get(sourceId);
|
|
return _objectSpread({
|
|
anchorX: 0.5,
|
|
anchorY: 0.5,
|
|
captureDraggingState: false
|
|
}, sourcePreviewNodeOptions || {});
|
|
}
|
|
}, {
|
|
key: "isDraggingNativeItem",
|
|
value: function isDraggingNativeItem() {
|
|
var itemType = this.monitor.getItemType();
|
|
return Object.keys(NativeTypes).some(function (key) {
|
|
return NativeTypes[key] === itemType;
|
|
});
|
|
}
|
|
}, {
|
|
key: "beginDragNativeItem",
|
|
value: function beginDragNativeItem(type, dataTransfer) {
|
|
this.clearCurrentDragSourceNode();
|
|
this.currentNativeSource = createNativeDragSource(type, dataTransfer);
|
|
this.currentNativeHandle = this.registry.addSource(type, this.currentNativeSource);
|
|
this.actions.beginDrag([this.currentNativeHandle]);
|
|
}
|
|
}, {
|
|
key: "setCurrentDragSourceNode",
|
|
value: function setCurrentDragSourceNode(node) {
|
|
var _this5 = this;
|
|
|
|
this.clearCurrentDragSourceNode();
|
|
this.currentDragSourceNode = node; // A timeout of > 0 is necessary to resolve Firefox issue referenced
|
|
// See:
|
|
// * https://github.com/react-dnd/react-dnd/pull/928
|
|
// * https://github.com/react-dnd/react-dnd/issues/869
|
|
|
|
var MOUSE_MOVE_TIMEOUT = 1000; // Receiving a mouse event in the middle of a dragging operation
|
|
// means it has ended and the drag source node disappeared from DOM,
|
|
// so the browser didn't dispatch the dragend event.
|
|
//
|
|
// We need to wait before we start listening for mousemove events.
|
|
// This is needed because the drag preview needs to be drawn or else it fires an 'mousemove' event
|
|
// immediately in some browsers.
|
|
//
|
|
// See:
|
|
// * https://github.com/react-dnd/react-dnd/pull/928
|
|
// * https://github.com/react-dnd/react-dnd/issues/869
|
|
//
|
|
|
|
this.mouseMoveTimeoutTimer = setTimeout(function () {
|
|
return _this5.window && _this5.window.addEventListener('mousemove', _this5.endDragIfSourceWasRemovedFromDOM, true);
|
|
}, MOUSE_MOVE_TIMEOUT);
|
|
}
|
|
}, {
|
|
key: "clearCurrentDragSourceNode",
|
|
value: function clearCurrentDragSourceNode() {
|
|
if (this.currentDragSourceNode) {
|
|
this.currentDragSourceNode = null;
|
|
|
|
if (this.window) {
|
|
this.window.clearTimeout(this.mouseMoveTimeoutTimer || undefined);
|
|
this.window.removeEventListener('mousemove', this.endDragIfSourceWasRemovedFromDOM, true);
|
|
}
|
|
|
|
this.mouseMoveTimeoutTimer = null;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}, {
|
|
key: "handleDragStart",
|
|
value: function handleDragStart(e, sourceId) {
|
|
if (e.defaultPrevented) {
|
|
return;
|
|
}
|
|
|
|
if (!this.dragStartSourceIds) {
|
|
this.dragStartSourceIds = [];
|
|
}
|
|
|
|
this.dragStartSourceIds.unshift(sourceId);
|
|
}
|
|
}, {
|
|
key: "handleDragEnter",
|
|
value: function handleDragEnter(e, targetId) {
|
|
this.dragEnterTargetIds.unshift(targetId);
|
|
}
|
|
}, {
|
|
key: "handleDragOver",
|
|
value: function handleDragOver(e, targetId) {
|
|
if (this.dragOverTargetIds === null) {
|
|
this.dragOverTargetIds = [];
|
|
}
|
|
|
|
this.dragOverTargetIds.unshift(targetId);
|
|
}
|
|
}, {
|
|
key: "handleDrop",
|
|
value: function handleDrop(e, targetId) {
|
|
this.dropTargetIds.unshift(targetId);
|
|
}
|
|
}, {
|
|
key: "window",
|
|
get: function get() {
|
|
return this.options.window;
|
|
}
|
|
}, {
|
|
key: "document",
|
|
get: function get() {
|
|
return this.options.document;
|
|
}
|
|
}]);
|
|
|
|
return HTML5Backend;
|
|
}();
|
|
|
|
var emptyImage;
|
|
function getEmptyImage() {
|
|
if (!emptyImage) {
|
|
emptyImage = new Image();
|
|
emptyImage.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
|
}
|
|
|
|
return emptyImage;
|
|
}
|
|
|
|
var createBackend = function createBackend(manager, context) {
|
|
return new HTML5Backend(manager, context);
|
|
};
|
|
|
|
exports.NativeTypes = NativeTypes;
|
|
exports.default = createBackend;
|
|
exports.getEmptyImage = getEmptyImage;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|