handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
231 lines (216 loc) • 10.4 kB
JavaScript
import "core-js/modules/es.error.cause.js";
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); }
import { Selection } from "./../../3rdparty/walkontable/src/index.mjs";
class VisualSelection extends Selection {
constructor(settings, visualCellRange) {
super(settings, null);
/**
* Range of selection visually. Visual representation may have representation in a rendered selection.
*
* @type {null|CellRange}
*/
_defineProperty(this, "visualCellRange", null);
this.visualCellRange = visualCellRange || null;
this.commit();
}
/**
* Adds a cell coords to the selection.
*
* @param {CellCoords} coords Visual coordinates of a cell.
* @returns {VisualSelection}
*/
add(coords) {
if (this.visualCellRange === null) {
this.visualCellRange = this.settings.createCellRange(coords);
} else {
this.visualCellRange.expand(coords);
}
return this;
}
/**
* Clears visual and renderable selection.
*
* @returns {VisualSelection}
*/
clear() {
this.visualCellRange = null;
return super.clear();
}
/**
* Trims the passed cell range object by removing all coordinates that points to the hidden rows
* or columns. The result is a new cell range object that points only to the visible indexes or `null`.
*
* @private
* @param {CellRange} cellRange Cells range object to be trimmed.
* @returns {CellRange} Visual non-hidden cells range coordinates.
*/
trimToVisibleCellsRangeOnly(_ref) {
let {
from,
to
} = _ref;
let visibleFromCoords = this.getNearestNotHiddenCoords(from, 1);
let visibleToCoords = this.getNearestNotHiddenCoords(to, -1);
if (visibleFromCoords === null || visibleToCoords === null) {
return null;
}
if (visibleFromCoords.row > visibleToCoords.row || visibleFromCoords.col > visibleToCoords.col) {
visibleFromCoords = from;
visibleToCoords = to;
}
return this.settings.createCellRange(visibleFromCoords, visibleFromCoords, visibleToCoords);
}
/**
* Gets nearest coordinates that points to the visible row and column indexes. If there are no visible
* rows and/or columns the `null` value is returned.
*
* @private
* @param {CellCoords} coords The coords object as starting point for finding the nearest visible coordinates.
* @param {1|-1} rowSearchDirection The search direction. For value 1, it means searching from top to bottom for
* rows and from left to right for columns. For -1, it is the other way around.
* @param {1|-1} columnSearchDirection The same as above but for rows.
* @returns {CellCoords|null} Visual cell coordinates.
*/
getNearestNotHiddenCoords(coords, rowSearchDirection) {
let columnSearchDirection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : rowSearchDirection;
const nextVisibleRow = this.getNearestNotHiddenIndex(this.settings.rowIndexMapper, coords.row, rowSearchDirection);
// There are no more visual rows in the range.
if (nextVisibleRow === null) {
return null;
}
const nextVisibleColumn = this.getNearestNotHiddenIndex(this.settings.columnIndexMapper, coords.col, columnSearchDirection);
// There are no more visual columns in the range.
if (nextVisibleColumn === null) {
return null;
}
return this.settings.createCellCoords(nextVisibleRow, nextVisibleColumn);
}
/**
* Gets nearest visual index. If there are no visible rows or columns the `null` value is returned.
*
* @private
* @param {IndexMapper} indexMapper The IndexMapper instance for specific axis.
* @param {number} visualIndex The index as starting point for finding the nearest visible index.
* @param {1|-1} searchDirection The search direction. For value 1, it means searching from top to bottom for
* rows and from left to right for columns. For -1, it is the other way around.
* @returns {number|null} Visual row/column index.
*/
getNearestNotHiddenIndex(indexMapper, visualIndex, searchDirection) {
if (visualIndex < 0) {
return visualIndex;
}
return indexMapper.getNearestNotHiddenIndex(visualIndex, searchDirection);
}
/**
* Override internally stored visual indexes added by the Selection's `add` function. It should be executed
* at the end of process of adding visual selection coordinates.
*
* @returns {VisualSelection}
*/
commit() {
// There is no information about visual ranges, thus no selection may be displayed.
if (this.visualCellRange === null) {
return this;
}
const trimmedCellRange = this.trimToVisibleCellsRangeOnly(this.visualCellRange);
// There is no visual start point (and also visual end point) in the range.
if (trimmedCellRange === null) {
this.cellRange = null;
} else {
this.cellRange = this.createRenderableCellRange(trimmedCellRange.from, trimmedCellRange.to);
}
return this;
}
/**
* Some selection may be a part of broader cell range. This function sync coordinates of current selection
* and the broader cell range when needed (current selection can't be presented visually).
*
* @param {CellRange} broaderCellRange Visual range. Actual cell range may be contained in the broader cell range.
* When there is no way to represent some cell range visually we try to find range containing just the first visible cell.
*
* Warn: Please keep in mind that this function may change coordinates of the handled broader range.
*
* @returns {VisualSelection}
*/
syncWith(broaderCellRange) {
const coordsFrom = broaderCellRange.from.clone().normalize();
const rowDirection = broaderCellRange.getVerticalDirection() === 'N-S' ? 1 : -1;
const columnDirection = broaderCellRange.getHorizontalDirection() === 'W-E' ? 1 : -1;
const renderableHighlight = this.settings.visualToRenderableCoords(this.visualCellRange.highlight);
let cellCoordsVisual = null;
if (renderableHighlight === null || renderableHighlight.col === null || renderableHighlight.row === null) {
cellCoordsVisual = this.getNearestNotHiddenCoords(coordsFrom, rowDirection, columnDirection);
}
if (cellCoordsVisual !== null && broaderCellRange.overlaps(cellCoordsVisual)) {
const currentHighlight = broaderCellRange.highlight.clone();
if (currentHighlight.row >= 0) {
currentHighlight.row = cellCoordsVisual.row;
}
if (currentHighlight.col >= 0) {
currentHighlight.col = cellCoordsVisual.col;
}
// We can't show selection visually now, but we found first visible range in the broader cell range.
if (this.cellRange === null) {
const cellCoordsRenderable = this.settings.visualToRenderableCoords(currentHighlight);
this.cellRange = this.settings.createCellRange(cellCoordsRenderable);
}
// TODO
// We set new highlight as it might change (for example, when showing/hiding some cells from the broader selection range)
// TODO: It is also handled by the `MergeCells` plugin while adjusting already modified coordinates. Should it?
broaderCellRange.setHighlight(currentHighlight);
}
// TODO
// Sync the highlight coords from the visual selection layer with logical coords.
if (this.settings.selectionType === 'focus' && renderableHighlight !== null && cellCoordsVisual === null) {
broaderCellRange.setHighlight(this.visualCellRange.highlight);
}
return this;
}
/**
* Returns the top left (TL) and bottom right (BR) selection coordinates (renderable indexes).
* The method overwrites the original method to support header selection for hidden cells.
* To make the header selection working, the CellCoords and CellRange have to support not
* complete coordinates (`null` values for example, `row: null`, `col: 2`).
*
* @returns {Array} Returns array of coordinates for example `[1, 1, 5, 5]`.
*/
getCorners() {
const {
from,
to
} = this.cellRange;
return [Math.min(from.row, to.row), Math.min(from.col, to.col), Math.max(from.row, to.row), Math.max(from.col, to.col)];
}
/**
* Returns the top left (or top right in RTL) and bottom right (or bottom left in RTL) selection
* coordinates (visual indexes).
*
* @returns {Array} Returns array of coordinates for example `[1, 1, 5, 5]`.
*/
getVisualCorners() {
const topStart = this.settings.renderableToVisualCoords(this.cellRange.getTopStartCorner());
const bottomEnd = this.settings.renderableToVisualCoords(this.cellRange.getBottomEndCorner());
return [topStart.row, topStart.col, bottomEnd.row, bottomEnd.col];
}
/**
* Creates a new CellRange object based on visual coordinates which before object creation are
* translated to renderable indexes.
*
* @param {CellCoords} visualFromCoords The CellCoords object which contains coordinates that
* points to the beginning of the selection.
* @param {CellCoords} visualToCoords The CellCoords object which contains coordinates that
* points to the end of the selection.
* @returns {CellRange|null}
*/
createRenderableCellRange(visualFromCoords, visualToCoords) {
const renderableFromCoords = this.settings.visualToRenderableCoords(visualFromCoords);
const renderableToCoords = this.settings.visualToRenderableCoords(visualToCoords);
if (renderableFromCoords.row === null || renderableFromCoords.col === null || renderableToCoords.row === null || renderableToCoords.col === null) {
return null;
}
return this.settings.createCellRange(renderableFromCoords, renderableFromCoords, renderableToCoords);
}
}
export default VisualSelection;