handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
244 lines (230 loc) • 7.71 kB
JavaScript
import "core-js/modules/es.error.cause.js";
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
import { BasePlugin } from "../base/index.mjs";
import { isRightClick } from "../../helpers/dom/event.mjs";
import { getParentWindow } from "../../helpers/dom/element.mjs";
export const PLUGIN_KEY = 'dragToScroll';
export const PLUGIN_PRIORITY = 100;
/* eslint-disable jsdoc/require-description-complete-sentence */
/**
* @description
* Plugin used to scroll Handsontable by selecting a cell and dragging outside of the visible viewport.
*
*
* @class DragToScroll
* @plugin DragToScroll
*/
var _DragToScroll_brand = /*#__PURE__*/new WeakSet();
export class DragToScroll extends BasePlugin {
constructor() {
super(...arguments);
/**
* On after on cell/cellCorner mouse down listener.
*
* @param {MouseEvent} event The mouse event object.
*/
_classPrivateMethodInitSpec(this, _DragToScroll_brand);
/**
* Size of an element and its position relative to the viewport,
* e.g. {bottom: 449, height: 441, left: 8, right: 814, top: 8, width: 806, x: 8, y:8}.
*
* @type {DOMRect}
*/
_defineProperty(this, "boundaries", null);
/**
* Callback function.
*
* @private
* @type {Function}
*/
_defineProperty(this, "callback", null);
/**
* Flag indicates mouseDown/mouseUp.
*
* @private
* @type {boolean}
*/
_defineProperty(this, "listening", false);
}
static get PLUGIN_KEY() {
return PLUGIN_KEY;
}
static get PLUGIN_PRIORITY() {
return PLUGIN_PRIORITY;
}
/**
* Checks if the plugin is enabled in the handsontable settings. This method is executed in {@link Hooks#beforeInit}
* hook and if it returns `true` then the {@link DragToScroll#enablePlugin} method is called.
*
* @returns {boolean}
*/
isEnabled() {
return !!this.hot.getSettings()[PLUGIN_KEY];
}
/**
* Enables the plugin functionality for this Handsontable instance.
*/
enablePlugin() {
if (this.enabled) {
return;
}
this.addHook('afterOnCellMouseDown', event => _assertClassBrand(_DragToScroll_brand, this, _setupListening).call(this, event));
this.addHook('afterOnCellCornerMouseDown', event => _assertClassBrand(_DragToScroll_brand, this, _setupListening).call(this, event));
this.registerEvents();
super.enablePlugin();
}
/**
* Updates the plugin's state.
*
* This method is executed when [`updateSettings()`](@/api/core.md#updatesettings) is invoked with any of the following configuration options:
* - [`dragToScroll`](@/api/options.md#dragtoscroll)
*/
updatePlugin() {
this.disablePlugin();
this.enablePlugin();
super.updatePlugin();
}
/**
* Disables the plugin functionality for this Handsontable instance.
*/
disablePlugin() {
this.unregisterEvents();
super.disablePlugin();
}
/**
* Sets the boundaries/dimensions of the scrollable viewport.
*
* @param {DOMRect|{left: number, right: number, top: number, bottom: number}} [boundaries] An object with
* coordinates. Contains the window boundaries by default. The object is compatible with DOMRect.
*/
setBoundaries() {
let boundaries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
left: 0,
right: this.hot.rootWindow.innerWidth,
top: 0,
bottom: this.hot.rootWindow.innerHeight
};
this.boundaries = boundaries;
}
/**
* Changes callback function.
*
* @param {Function} callback The callback function.
*/
setCallback(callback) {
this.callback = callback;
}
/**
* Checks if the mouse position (X, Y) is outside the viewport and fires a callback with calculated X an Y diffs
* between passed boundaries.
*
* @param {number} x Mouse X coordinate to check.
* @param {number} y Mouse Y coordinate to check.
*/
check(x, y) {
let diffX = 0;
let diffY = 0;
if (y < this.boundaries.top) {
// y is less than top
diffY = y - this.boundaries.top;
} else if (y > this.boundaries.bottom) {
// y is more than bottom
diffY = y - this.boundaries.bottom;
}
if (x < this.boundaries.left) {
// x is less than left
diffX = x - this.boundaries.left;
} else if (x > this.boundaries.right) {
// x is more than right
diffX = x - this.boundaries.right;
}
this.callback(diffX, diffY);
}
/**
* Enables listening on `mousemove` event.
*
* @private
*/
listen() {
this.listening = true;
}
/**
* Disables listening on `mousemove` event.
*
* @private
*/
unlisten() {
this.listening = false;
}
/**
* Returns current state of listening.
*
* @private
* @returns {boolean}
*/
isListening() {
return this.listening;
}
/**
* Registers dom listeners.
*
* @private
*/
registerEvents() {
const {
rootWindow
} = this.hot;
let frame = rootWindow;
while (frame) {
this.eventManager.addEventListener(frame.document, 'contextmenu', () => this.unlisten());
this.eventManager.addEventListener(frame.document, 'mouseup', () => this.unlisten());
this.eventManager.addEventListener(frame.document, 'mousemove', event => this.onMouseMove(event));
frame = getParentWindow(frame);
}
}
/**
* Unbinds the events used by the plugin.
*
* @private
*/
unregisterEvents() {
this.eventManager.clear();
}
/**
* 'mouseMove' event callback.
*
* @private
* @param {MouseEvent} event `mousemove` event properties.
*/
onMouseMove(event) {
if (!this.isListening()) {
return;
}
this.check(event.clientX, event.clientY);
}
/**
* Destroys the plugin instance.
*/
destroy() {
super.destroy();
}
}
function _setupListening(event) {
if (isRightClick(event)) {
return;
}
const scrollHandler = this.hot.view._wt.wtOverlays.topOverlay.mainTableScrollableElement;
this.setBoundaries(scrollHandler !== this.hot.rootWindow ? scrollHandler.getBoundingClientRect() : undefined);
this.setCallback((scrollX, scrollY) => {
var _scrollHandler$scroll, _scrollHandler$scroll2;
const horizontalScrollValue = (_scrollHandler$scroll = scrollHandler.scrollLeft) !== null && _scrollHandler$scroll !== void 0 ? _scrollHandler$scroll : scrollHandler.scrollX;
const verticalScrollValue = (_scrollHandler$scroll2 = scrollHandler.scrollTop) !== null && _scrollHandler$scroll2 !== void 0 ? _scrollHandler$scroll2 : scrollHandler.scrollY;
scrollHandler.scroll(horizontalScrollValue + Math.sign(scrollX) * 50, verticalScrollValue + Math.sign(scrollY) * 20);
});
this.listen();
}