src/Draggable/Sensors/ForceTouchSensor/ForceTouchSensor.js
import Sensor from '../Sensor';
import {DragStartSensorEvent, DragMoveSensorEvent, DragStopSensorEvent, DragPressureSensorEvent} from '../SensorEvent';
const onMouseForceWillBegin = Symbol('onMouseForceWillBegin');
const onMouseForceDown = Symbol('onMouseForceDown');
const onMouseDown = Symbol('onMouseDown');
const onMouseForceChange = Symbol('onMouseForceChange');
const onMouseMove = Symbol('onMouseMove');
const onMouseUp = Symbol('onMouseUp');
const onMouseForceGlobalChange = Symbol('onMouseForceGlobalChange');
/**
* This sensor picks up native force touch events and dictates drag operations
* @class ForceTouchSensor
* @module ForceTouchSensor
* @extends Sensor
*/
export default class ForceTouchSensor extends Sensor {
/**
* ForceTouchSensor constructor.
* @constructs ForceTouchSensor
* @param {HTMLElement[]|NodeList|HTMLElement} containers - Containers
* @param {Object} options - Options
*/
constructor(containers = [], options = {}) {
super(containers, options);
/**
* Draggable element needs to be remembered to unset the draggable attribute after drag operation has completed
* @property mightDrag
* @type {Boolean}
*/
this.mightDrag = false;
this[onMouseForceWillBegin] = this[onMouseForceWillBegin].bind(this);
this[onMouseForceDown] = this[onMouseForceDown].bind(this);
this[onMouseDown] = this[onMouseDown].bind(this);
this[onMouseForceChange] = this[onMouseForceChange].bind(this);
this[onMouseMove] = this[onMouseMove].bind(this);
this[onMouseUp] = this[onMouseUp].bind(this);
}
/**
* Attaches sensors event listeners to the DOM
*/
attach() {
for (const container of this.containers) {
container.addEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false);
container.addEventListener('webkitmouseforcedown', this[onMouseForceDown], false);
container.addEventListener('mousedown', this[onMouseDown], true);
container.addEventListener('webkitmouseforcechanged', this[onMouseForceChange], false);
}
document.addEventListener('mousemove', this[onMouseMove]);
document.addEventListener('mouseup', this[onMouseUp]);
}
/**
* Detaches sensors event listeners to the DOM
*/
detach() {
for (const container of this.containers) {
container.removeEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false);
container.removeEventListener('webkitmouseforcedown', this[onMouseForceDown], false);
container.removeEventListener('mousedown', this[onMouseDown], true);
container.removeEventListener('webkitmouseforcechanged', this[onMouseForceChange], false);
}
document.removeEventListener('mousemove', this[onMouseMove]);
document.removeEventListener('mouseup', this[onMouseUp]);
}
/**
* Mouse force will begin handler
* @private
* @param {Event} event - Mouse force will begin event
*/
[onMouseForceWillBegin](event) {
event.preventDefault();
this.mightDrag = true;
}
/**
* Mouse force down handler
* @private
* @param {Event} event - Mouse force down event
*/
[onMouseForceDown](event) {
if (this.dragging) {
return;
}
const target = document.elementFromPoint(event.clientX, event.clientY);
const container = event.currentTarget;
const dragStartEvent = new DragStartSensorEvent({
clientX: event.clientX,
clientY: event.clientY,
target,
container,
originalEvent: event,
});
this.trigger(container, dragStartEvent);
this.currentContainer = container;
this.dragging = !dragStartEvent.canceled();
this.mightDrag = false;
}
/**
* Mouse up handler
* @private
* @param {Event} event - Mouse up event
*/
[onMouseUp](event) {
if (!this.dragging) {
return;
}
const dragStopEvent = new DragStopSensorEvent({
clientX: event.clientX,
clientY: event.clientY,
target: null,
container: this.currentContainer,
originalEvent: event,
});
this.trigger(this.currentContainer, dragStopEvent);
this.currentContainer = null;
this.dragging = false;
this.mightDrag = false;
}
/**
* Mouse down handler
* @private
* @param {Event} event - Mouse down event
*/
[onMouseDown](event) {
if (!this.mightDrag) {
return;
}
// Need workaround for real click
// Cancel potential drag events
event.stopPropagation();
event.stopImmediatePropagation();
event.preventDefault();
}
/**
* Mouse move handler
* @private
* @param {Event} event - Mouse force will begin event
*/
[onMouseMove](event) {
if (!this.dragging) {
return;
}
const target = document.elementFromPoint(event.clientX, event.clientY);
const dragMoveEvent = new DragMoveSensorEvent({
clientX: event.clientX,
clientY: event.clientY,
target,
container: this.currentContainer,
originalEvent: event,
});
this.trigger(this.currentContainer, dragMoveEvent);
}
/**
* Mouse force change handler
* @private
* @param {Event} event - Mouse force change event
*/
[onMouseForceChange](event) {
if (this.dragging) {
return;
}
const target = event.target;
const container = event.currentTarget;
const dragPressureEvent = new DragPressureSensorEvent({
pressure: event.webkitForce,
clientX: event.clientX,
clientY: event.clientY,
target,
container,
originalEvent: event,
});
this.trigger(container, dragPressureEvent);
}
/**
* Mouse force global change handler
* @private
* @param {Event} event - Mouse force global change event
*/
[onMouseForceGlobalChange](event) {
if (!this.dragging) {
return;
}
const target = event.target;
const dragPressureEvent = new DragPressureSensorEvent({
pressure: event.webkitForce,
clientX: event.clientX,
clientY: event.clientY,
target,
container: this.currentContainer,
originalEvent: event,
});
this.trigger(this.currentContainer, dragPressureEvent);
}
}