reactronic-dom
Version:
Reactronic DOM - Transactional Reactive Front-End Development Framework
387 lines (386 loc) • 14.8 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { options, reaction, transaction, isnonreactive, Transaction, LoggingLevel } from 'reactronic';
import { findTargetElementData, SymDataForSensor } from './DataForSensor';
import { HtmlElementSensor } from './HtmlElementSensor';
import { extractModifierKeys, KeyboardModifiers } from './KeyboardSensor';
export class HtmlDragSensor extends HtmlElementSensor {
constructor(focusSensor, windowSensor) {
super(focusSensor, windowSensor);
this.draggable = undefined;
this.dragSource = undefined;
this.dragTarget = undefined;
this.dragTargetWindow = undefined;
this.previousDragTarget = undefined;
this.dragStarted = false;
this.dragFinished = false;
this.startX = Infinity;
this.startY = Infinity;
this.dataByFormat = new Map();
this.draggingImage = undefined;
this.draggingImageX = Infinity;
this.draggingImageY = Infinity;
this.dropEffect = 'none';
this.dataTypesAllowed = [];
this.effectAllowed = 'uninitialized';
this.dropAllowed = false;
this.draggingOver = false;
this.draggingDataTypes = [];
this.positionX = Infinity;
this.positionY = Infinity;
this.modifiers = KeyboardModifiers.None;
this.dropX = Infinity;
this.dropY = Infinity;
this.dropped = false;
this.immediatePositionX = Infinity;
this.immediatePositionY = Infinity;
this.immediateModifiers = KeyboardModifiers.None;
}
getData(format) {
return this.dataByFormat.get(format);
}
setData(format, value) {
this.dataByFormat.set(format, value);
}
clearData(format) {
if (format)
this.dataByFormat.delete(format);
else
this.dataByFormat.clear();
}
setDragImage(value, x, y) {
this.draggingImage = value;
this.draggingImageX = x;
this.draggingImageY = y;
}
listen(element, enabled = true) {
const existing = this.sourceElement;
if (element !== existing) {
if (existing) {
existing.removeEventListener('dragstart', this.onDragStart.bind(this), { capture: true });
existing.removeEventListener('drag', this.onDrag.bind(this), { capture: true });
existing.removeEventListener('dragenter', this.onDragEnter.bind(this), { capture: false });
existing.removeEventListener('dragleave', this.onDragLeave.bind(this), { capture: false });
existing.removeEventListener('dragover', this.onDragOver.bind(this), { capture: true });
existing.removeEventListener('drop', this.onDrop.bind(this), { capture: true });
existing.removeEventListener('dragend', this.onDragEnd.bind(this), { capture: true });
}
this.sourceElement = element;
if (element && enabled) {
element.addEventListener('dragstart', this.onDragStart.bind(this), { capture: true });
element.addEventListener('drag', this.onDrag.bind(this), { capture: true });
element.addEventListener('dragenter', this.onDragEnter.bind(this), { capture: false });
element.addEventListener('dragleave', this.onDragLeave.bind(this), { capture: false });
element.addEventListener('dragover', this.onDragOver.bind(this), { capture: true });
element.addEventListener('drop', this.onDrop.bind(this), { capture: true });
element.addEventListener('dragend', this.onDragEnd.bind(this), { capture: true });
}
}
}
onDragStart(e) {
this.startDragging(e);
this.updateEventOnDragStart(e);
}
onDrag(e) {
this.dragging(e);
}
onDragEnter(e) {
this.enterTarget(e);
this.updateEventOnDropAllowed(e);
}
onDragLeave(e) {
this.leaveTarget(e);
}
onDragOver(e) {
this.dragOver(e);
this.updateEventOnDropAllowed(e);
}
onDrop(e) {
this.drop(e);
}
onDragEnd(e) {
this.finishDragging(e);
this.reset();
}
startDragging(e) {
var _a;
this.preventDefault = false;
this.stopPropagation = false;
const targetPath = e.composedPath();
const underPointer = document.elementsFromPoint(e.clientX, e.clientY);
const { data, window } = findTargetElementData(targetPath, underPointer, SymDataForSensor, ['htmlDraggable']);
this.draggable = data === null || data === void 0 ? void 0 : data.htmlDraggable;
this.dragSource = (_a = findTargetElementData(targetPath, underPointer, SymDataForSensor, ['htmlDrag'], true).data) === null || _a === void 0 ? void 0 : _a.htmlDrag;
this.dragStarted = true;
this.dragFinished = false;
this.startX = e.clientX;
this.startY = e.clientY;
this.modifiers = extractModifierKeys(e);
this.positionX = e.clientX;
this.positionY = e.clientY;
this.dropped = false;
this.dragTarget = undefined;
this.dragTargetWindow = undefined;
this.previousDragTarget = undefined;
this.revision++;
Transaction.standalone(() => {
var _a;
(_a = this.windowSensor) === null || _a === void 0 ? void 0 : _a.setActiveWindow(window, 'htmlDrag');
});
}
dragging(e) {
this.dragStarted = true;
this.dragFinished = false;
this.revision++;
}
finishDragging(e) {
this.dragFinished = true;
this.revision++;
}
enterTarget(e) {
this.updateDragTarget(e);
this.dropped = false;
this.revision++;
}
leaveTarget(e) {
}
dragOver(e) {
this.updateDragTarget(e);
this.dropped = false;
this.revision++;
}
drop(e) {
this.updateDragTarget(e);
this.modifiers = this.immediateModifiers;
this.dropX = e.clientX;
this.dropY = e.clientY;
this.dropped = true;
const dt = e.dataTransfer;
if (dt) {
let dataByFormat = this.dataByFormat;
dt.types.forEach(type => {
if (!dataByFormat.has(type)) {
const data = dt.getData(type);
if (data !== '') {
this.dataByFormat = dataByFormat = dataByFormat.toMutable();
dataByFormat.set(type, data);
}
}
});
}
this.revision++;
}
updateEventOnDragStart(e) {
const dt = e.dataTransfer;
if (dt) {
dt.dropEffect = this.dropEffect;
dt.effectAllowed = this.effectAllowed;
this.dataByFormat.forEach((data, format) => {
if (typeof data === 'string')
dt.setData(format, data);
});
if (this.draggingImage) {
dt.setDragImage(this.draggingImage, this.draggingImageX, this.draggingImageY);
}
}
}
updateEventOnDropAllowed(e) {
if (this.dropAllowed)
e.preventDefault();
}
reset() {
this.draggable = undefined;
this.dragSource = undefined;
this.dragTarget = undefined;
this.dragTargetWindow = undefined;
this.previousDragTarget = undefined;
this.dragStarted = false;
this.dragFinished = false;
this.startX = Infinity;
this.startY = Infinity;
this.dataByFormat.clear();
this.draggingImage = undefined;
this.draggingImageX = Infinity;
this.draggingImageY = Infinity;
this.dropEffect = 'none';
this.dataTypesAllowed = [];
this.effectAllowed = 'uninitialized';
this.dropAllowed = false;
this.draggingOver = false;
this.draggingDataTypes = [];
this.positionX = Infinity;
this.positionY = Infinity;
this.modifiers = KeyboardModifiers.None;
this.dropX = Infinity;
this.dropY = Infinity;
this.dropped = false;
this.immediatePositionX = Infinity;
this.immediatePositionY = Infinity;
this.immediateModifiers = KeyboardModifiers.None;
this.revision++;
}
updateDragTarget(e) {
var _a;
const targetPath = e.composedPath();
const underPointer = document.elementsFromPoint(e.clientX, e.clientY);
const { data, window } = findTargetElementData(targetPath, underPointer, SymDataForSensor, ['htmlDrag']);
const dragTarget = data === null || data === void 0 ? void 0 : data.htmlDrag;
if (dragTarget !== this.dragTarget) {
this.previousDragTarget = this.dragTarget;
this.dragTarget = dragTarget;
this.dragTargetWindow = window;
}
const types = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.types;
if (types) {
if (!areEqualArrays(types, this.draggingDataTypes)) {
const draggingDataTypes = new Array();
for (let i = 0; i < types.length; i++)
draggingDataTypes.push(types[i]);
this.draggingDataTypes = draggingDataTypes;
}
}
this.immediateModifiers = extractModifierKeys(e);
this.immediatePositionX = e.clientX;
this.immediatePositionY = e.clientY;
this.draggingOver = true;
}
whenDragging() {
if (this.draggingOver) {
this.positionX = this.immediatePositionX;
this.positionY = this.immediatePositionY;
this.modifiers = this.immediateModifiers;
}
}
}
__decorate([
isnonreactive,
__metadata("design:type", Map)
], HtmlDragSensor.prototype, "dataByFormat", void 0);
__decorate([
isnonreactive,
__metadata("design:type", Object)
], HtmlDragSensor.prototype, "draggingImage", void 0);
__decorate([
isnonreactive,
__metadata("design:type", Number)
], HtmlDragSensor.prototype, "draggingImageX", void 0);
__decorate([
isnonreactive,
__metadata("design:type", Number)
], HtmlDragSensor.prototype, "draggingImageY", void 0);
__decorate([
isnonreactive,
__metadata("design:type", String)
], HtmlDragSensor.prototype, "dropEffect", void 0);
__decorate([
isnonreactive,
__metadata("design:type", Array)
], HtmlDragSensor.prototype, "dataTypesAllowed", void 0);
__decorate([
isnonreactive,
__metadata("design:type", String)
], HtmlDragSensor.prototype, "effectAllowed", void 0);
__decorate([
isnonreactive,
__metadata("design:type", Boolean)
], HtmlDragSensor.prototype, "dropAllowed", void 0);
__decorate([
transaction,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Boolean]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "listen", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "startDragging", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "dragging", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "finishDragging", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "enterTarget", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "leaveTarget", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "dragOver", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "drop", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "updateEventOnDragStart", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", [DragEvent]),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "updateEventOnDropAllowed", null);
__decorate([
transaction,
options({ logging: LoggingLevel.Off }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "reset", null);
__decorate([
reaction,
options({ throttling: 0 }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], HtmlDragSensor.prototype, "whenDragging", null);
function areEqualArrays(array1, array2) {
let result = true;
for (let i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) {
result = false;
break;
}
}
return result;
}