azure-devops-ui
Version:
React components for building web UI in Azure DevOps
202 lines (201 loc) • 9.92 kB
JavaScript
import "../../CommonImports";
import "../../Core/core.css";
import "./Table.css";
import * as React from "react";
import { ListDropIndicatorPosition } from '../../Components/List/ListDropIndicator.Props';
import { cellFromEvent } from '../../List';
import { getPointByEventType } from '../../Util';
import { beginDragOperation, DragDropEffect, DragImage } from '../../Utilities/DragDrop';
import { ListDropIndicator } from "../List/ListDropIndicator";
import { ColumnFillId } from "./Table";
/**
* A behavior for dragging & dropping columns
*/
export class ColumnDragDropBehavior {
constructor(options) {
this.initialize = (props, dragDroppableUI, eventDispatch) => {
this.dragDroppableUI = dragDroppableUI;
this.eventDispatch = eventDispatch;
this.eventDispatch.addEventListener("pointerdown", this.onPointerDown);
this.eventDispatch.addEventListener("dragstart", this.onDragStart);
this.eventDispatch.addEventListener("dragend", this.onDragEnd);
this.eventDispatch.addEventListener("dragenter", this.onDragEnter);
this.eventDispatch.addEventListener("dragexit", this.onDragExit);
this.eventDispatch.addEventListener("dragover", this.onDragOver);
this.eventDispatch.addEventListener("drop", this.onDrop);
this.indicatorName = "drop-indicator";
};
this.onDragEnd = (event) => {
const index = eventIsOnHeader(event);
if (index && index >= 0 && this.options.onDragEnd) {
this.options.onDragEnd(event);
}
this.dragDroppableUI.removeOverlay("drag-source-item");
this.dragImageData = undefined;
};
this.onDragStart = (event) => {
if (event.detail.dataTransfer && !event.defaultPrevented) {
const index = eventIsOnHeader(event);
if (index !== null && index >= 0) {
if (this.options.onDragStart) {
this.options.onDragStart(event);
}
if (event.detail.dataTransfer.effectAllowed !== DragDropEffect.none) {
this.dragDroppableUI.addOverlay("drag-source-item", -1, this.renderDragSourceItemOverlay,
/** z-index */ 0,
/** columnIndex */ index);
if (this.dragImageData === undefined) {
this.dragImageData = {
image: this.options.renderDragImage(event)
};
}
}
}
}
};
this.onPointerDown = (event) => {
if (event.button === 0) {
this.beginDrag(event);
}
};
this.renderDragSourceItemOverlay = (props) => {
return (React.createElement(React.Fragment, null,
React.createElement("div", { className: "bolt-list-drag-source-item flex-grow" }),
this.operation && this.dragImageData && React.createElement(DragImage, { operation: this.operation }, this.dragImageData.image)));
};
this.setDragImage = (image, xOffset, yOffset) => {
this.dragImageData = { image: image, xOffset: xOffset, yOffset: yOffset };
};
this.onDragEnter = (event) => {
if (!this.handlesType(event)) {
return;
}
if (this.options.onDragEnter) {
this.options.onDragEnter(event);
}
else {
event.detail.dataTransfer.dropEffect = DragDropEffect.move;
}
};
this.onDragExit = (event) => {
if (!this.handlesType(event)) {
return;
}
if (this.options.onDragExit) {
this.options.onDragExit(event);
}
this.dragDroppableUI.removeOverlay(this.indicatorName);
};
this.onDragOver = (event) => {
if (!this.handlesType(event)) {
return;
}
const index = this.calculateIndex(event);
const dragIndex = event.detail.dataTransfer.secondaryData.index;
const listId = event.detail.dataTransfer.secondaryData.sourceId;
if (index >= 0 && (index !== dragIndex || listId !== this.options.id) && this.options.columns[index].id !== ColumnFillId) {
if (this.options.onDragOver) {
this.options.onDragOver(event, { index: this.listIndicatorPosition === ListDropIndicatorPosition.right ? index + 1 : index });
}
else {
event.detail.dataTransfer.dropEffect = DragDropEffect.move;
}
}
else {
event.detail.dataTransfer.dropEffect = DragDropEffect.none;
}
if (event.detail.dataTransfer.dropEffect === DragDropEffect.none) {
this.dragDroppableUI.removeOverlay(this.indicatorName);
}
else {
this.dragDroppableUI.addOverlay(this.indicatorName, -1, this.renderDropIndicator, /** z-index */ 0, /** columnIndex */ index);
}
};
this.onDrop = (event) => {
if (!this.handlesType(event)) {
return;
}
const index = this.calculateIndex(event);
const dragIndex = event.detail.dataTransfer.secondaryData.index;
const listId = event.detail.dataTransfer.secondaryData.sourceId;
if (index >= 0 && (index !== dragIndex || listId !== this.options.id) && this.options.onDrop) {
event.persist();
this.options.onDrop(event, { index: this.listIndicatorPosition === ListDropIndicatorPosition.right ? index + 1 : index });
}
this.dragDroppableUI.removeOverlay(this.indicatorName);
};
this.renderDropIndicator = (props) => {
const xOffset = this.listIndicatorPosition === ListDropIndicatorPosition.right ? props.rowElement.offsetWidth : 0;
return React.createElement(ListDropIndicator, { position: this.listIndicatorPosition, xOffset: xOffset - 3, lineOffset: xOffset });
};
this.options = options;
this.contextMenuIndex = options.columns.findIndex(col => col.id === "_more");
}
componentWillUnmount() {
var _a, _b, _c, _d, _e, _f, _g;
(_a = this.eventDispatch) === null || _a === void 0 ? void 0 : _a.removeEventListener("pointerdown", this.onPointerDown);
(_b = this.eventDispatch) === null || _b === void 0 ? void 0 : _b.removeEventListener("dragstart", this.onDragStart);
(_c = this.eventDispatch) === null || _c === void 0 ? void 0 : _c.removeEventListener("dragend", this.onDragEnd);
(_d = this.eventDispatch) === null || _d === void 0 ? void 0 : _d.removeEventListener("dragenter", this.onDragEnter);
(_e = this.eventDispatch) === null || _e === void 0 ? void 0 : _e.removeEventListener("dragexit", this.onDragExit);
(_f = this.eventDispatch) === null || _f === void 0 ? void 0 : _f.removeEventListener("dragover", this.onDragOver);
(_g = this.eventDispatch) === null || _g === void 0 ? void 0 : _g.removeEventListener("drop", this.onDrop);
}
updateBehaviorOptions(options) {
this.options = options;
}
beginDrag(event) {
var _a;
const index = eventIsOnHeader(event);
if (index !== null && ((_a = this.options) === null || _a === void 0 ? void 0 : _a.columns) && index >= 0) {
const item = this.options.columns[index];
this.operation = beginDragOperation(event, {
data: item,
dropEffect: DragDropEffect.none,
secondaryData: { index: index, sourceId: this.options.id },
setDragImage: this.setDragImage,
type: this.options.type
});
}
}
handlesType(event) {
var _a;
const type = ((_a = event.detail.dataTransfer) === null || _a === void 0 ? void 0 : _a.type) || "";
return this.options.allowedTypes.indexOf(type) !== -1;
}
calculateIndex(event) {
const cell = cellFromEvent(event);
let index = cell.cellIndex;
if (cell.cellElement && event.detail.dataTransfer.secondaryData) {
const dragIndex = event.detail.dataTransfer.secondaryData.index;
const nativeEvent = event.detail.nativeEvent;
const columnRect = cell.cellElement.getBoundingClientRect();
const point = getPointByEventType(nativeEvent);
const leftOfColumn = point ? point.x < columnRect.width / 2 + columnRect.left : index < dragIndex;
if (index < dragIndex) {
this.listIndicatorPosition = ListDropIndicatorPosition.left;
if (!leftOfColumn) {
index++;
}
if (index === this.contextMenuIndex) {
index--;
}
}
else if (index > dragIndex) {
this.listIndicatorPosition = ListDropIndicatorPosition.right;
if (leftOfColumn) {
index--;
}
if (index + 1 < this.options.columns.length && index + 1 == this.contextMenuIndex) {
index++;
}
}
// No-op if index === dragIndex
}
return index;
}
}
function eventIsOnHeader(event) {
const cell = cellFromEvent(event);
return cell.rowIndex === -1 ? cell.cellIndex : null;
}