dockview-core
Version:
Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript
196 lines (195 loc) • 8.86 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PointerDragSource = void 0;
var events_1 = require("../../events");
var lifecycle_1 = require("../../lifecycle");
var pointerDragController_1 = require("./pointerDragController");
var DEFAULT_THRESHOLD = 5;
var DEFAULT_TOUCH_INITIATION_DELAY = 250;
var DEFAULT_PRESS_TOLERANCE = 8;
/**
* Pointer-event drag source. Waits for movement past `threshold` (and
* touch-only `touchInitiationDelay`) before promoting to a drag so taps
* pass through unaffected.
*/
var PointerDragSource = /** @class */ (function (_super) {
__extends(PointerDragSource, _super);
function PointerDragSource(element, options) {
var _a;
var _this = _super.call(this) || this;
_this.element = element;
_this.options = options;
_this._disabled = false;
_this._armed = false;
_this._startX = 0;
_this._startY = 0;
_this._touchOnly = (_a = options.touchOnly) !== null && _a !== void 0 ? _a : true;
_this.addDisposables((0, events_1.addDisposableListener)(_this.element, 'pointerdown', function (e) {
_this._onPointerDown(e);
}));
return _this;
}
PointerDragSource.prototype.setDisabled = function (value) {
this._disabled = value;
if (value) {
this._cancelPending();
}
};
/**
* `false` lets the pointer source also handle mouse pointers; used when
* `dndStrategy: 'pointer'` to drive every input type through this path.
*/
PointerDragSource.prototype.setTouchOnly = function (value) {
if (this._touchOnly === value) {
return;
}
this._touchOnly = value;
// A pending mouse-tracked drag should be abandoned if we re-enable
// the touch-only filter mid-flight.
if (value) {
this._cancelPending();
}
};
PointerDragSource.prototype._shouldHandle = function (event) {
var _a, _b;
if (this._disabled) {
return false;
}
// Pointer-type filter runs before isCancelled — consumer state read
// by isCancelled may not be populated for events we'll never handle.
if (this._touchOnly &&
event.pointerType !== 'touch' &&
event.pointerType !== 'pen') {
return false;
}
if ((_b = (_a = this.options).isCancelled) === null || _b === void 0 ? void 0 : _b.call(_a, event)) {
return false;
}
return true;
};
PointerDragSource.prototype._onPointerDown = function (event) {
var _this = this;
var _a, _b, _c, _d, _e;
if (!this._shouldHandle(event)) {
return;
}
// Defensive: a fresh pointerdown supersedes any in-flight tracking.
this._cancelPending();
this._pendingPointerId = event.pointerId;
this._startX = event.clientX;
this._startY = event.clientY;
this._startEvent = event;
var isTouch = event.pointerType === 'touch' || event.pointerType === 'pen';
// Touch waits a short window so a still finger can press-and-hold
// before drifting; once the timer fires, any motion past `threshold`
// begins the drag.
var initiationDelayOpt = this.options.touchInitiationDelay;
var initiationDelay = (_a = (typeof initiationDelayOpt === 'function'
? initiationDelayOpt()
: initiationDelayOpt)) !== null && _a !== void 0 ? _a : DEFAULT_TOUCH_INITIATION_DELAY;
this._armed = !isTouch || initiationDelay <= 0;
if (isTouch && initiationDelay > 0 && isFinite(initiationDelay)) {
this._armTimer = setTimeout(function () {
_this._armTimer = undefined;
_this._armed = true;
}, initiationDelay);
}
var threshold = (_b = this.options.threshold) !== null && _b !== void 0 ? _b : DEFAULT_THRESHOLD;
var pressToleranceOpt = this.options.pressTolerance;
var pressTolerance = (_c = (typeof pressToleranceOpt === 'function'
? pressToleranceOpt()
: pressToleranceOpt)) !== null && _c !== void 0 ? _c : DEFAULT_PRESS_TOLERANCE;
// Source's owning window — popout drags fire on their own window.
var targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
this._pendingMoveListener = (0, events_1.addDisposableListener)(targetWindow, 'pointermove', function (moveEvent) {
if (moveEvent.pointerId !== _this._pendingPointerId) {
return;
}
var dx = moveEvent.clientX - _this._startX;
var dy = moveEvent.clientY - _this._startY;
var distance = Math.hypot(dx, dy);
if (_this._armed) {
if (distance >= threshold) {
_this._beginDrag(moveEvent);
}
return;
}
// Pre-arm phase: a flick past `pressTolerance` in any
// direction is treated as drag intent. The element opts out
// of native scroll via `touch-action: none`; container-level
// scrolling lives on the surrounding strip's empty space.
if (distance > pressTolerance) {
_this._beginDrag(moveEvent);
}
});
this._pendingUpListener = (0, events_1.addDisposableListener)(targetWindow, 'pointerup', function (upEvent) {
if (upEvent.pointerId !== _this._pendingPointerId) {
return;
}
_this._cancelPending();
});
this._pendingCancelListener = (0, events_1.addDisposableListener)(targetWindow, 'pointercancel', function (cancelEvent) {
if (cancelEvent.pointerId !== _this._pendingPointerId) {
return;
}
_this._cancelPending();
});
};
/** For sibling gesture detectors (e.g. LongPressDetector) to dismiss a pending drag. */
PointerDragSource.prototype.cancelPending = function () {
this._cancelPending();
};
PointerDragSource.prototype._cancelPending = function () {
var _a, _b, _c;
this._pendingPointerId = undefined;
if (this._armTimer !== undefined) {
clearTimeout(this._armTimer);
this._armTimer = undefined;
}
this._armed = false;
(_a = this._pendingMoveListener) === null || _a === void 0 ? void 0 : _a.dispose();
(_b = this._pendingUpListener) === null || _b === void 0 ? void 0 : _b.dispose();
(_c = this._pendingCancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
this._pendingMoveListener = undefined;
this._pendingUpListener = undefined;
this._pendingCancelListener = undefined;
this._startEvent = undefined;
};
PointerDragSource.prototype._beginDrag = function (triggerEvent) {
var _this = this;
var _a, _b, _c, _d, _e;
var startEvent = (_a = this._startEvent) !== null && _a !== void 0 ? _a : triggerEvent;
this._cancelPending();
(_c = (_b = this.options).onDragStart) === null || _c === void 0 ? void 0 : _c.call(_b, startEvent);
var ghost = (_e = (_d = this.options).createGhost) === null || _e === void 0 ? void 0 : _e.call(_d, startEvent);
pointerDragController_1.PointerDragController.getInstance().beginDrag({
pointerEvent: triggerEvent,
source: this.element,
getData: function () { return _this.options.getData(startEvent); },
ghost: ghost,
onDragMove: this.options.onDragMove,
onDragEnd: this.options.onDragEnd,
});
};
PointerDragSource.prototype.dispose = function () {
this._cancelPending();
_super.prototype.dispose.call(this);
};
return PointerDragSource;
}(lifecycle_1.CompositeDisposable));
exports.PointerDragSource = PointerDragSource;