handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
341 lines (327 loc) • 13 kB
JavaScript
"use strict";
exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
require("core-js/modules/es.array.push.js");
require("core-js/modules/esnext.iterator.constructor.js");
require("core-js/modules/esnext.iterator.for-each.js");
var _linkedList = _interopRequireDefault(require("../../utils/dataStructures/linkedList"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
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"); }
/**
* Class responsible for providing the correct focus order (vertical and horizontal) within a selection that
* contains merged cells.
*
* @private
*/
var _cellsHorizontalOrder = /*#__PURE__*/new WeakMap();
var _cellsVerticalOrder = /*#__PURE__*/new WeakMap();
var _currentHorizontalLinkedNode = /*#__PURE__*/new WeakMap();
var _currentVerticalLinkedNode = /*#__PURE__*/new WeakMap();
var _mergedCellsGetter = /*#__PURE__*/new WeakMap();
var _rowIndexMapper = /*#__PURE__*/new WeakMap();
var _columnIndexMapper = /*#__PURE__*/new WeakMap();
var _FocusOrder_brand = /*#__PURE__*/new WeakSet();
class FocusOrder {
constructor(_ref) {
let {
mergedCellsGetter,
rowIndexMapper,
columnIndexMapper
} = _ref;
/**
* Pushes a new node to the provided list order.
*
* @param {object} options The options object.
* @param {CellRange} options.selectedRange The selected range to build the focus order for.
* @param {number} options.selectionLayer The selection layer index.
* @param {LinkedList} options.listOrder The list order to push the node to.
* @param {WeakSet} options.mergeCellsVisitor The set of visited cells.
* @param {number} options.row The visual row index.
* @param {number} options.column The visual column index.
* @returns {NodeStructure | null}
*/
_classPrivateMethodInitSpec(this, _FocusOrder_brand);
/**
* The linked list of the all cells within the current selection in horizontal order. The list is
* recreated every time the selection is changed.
*
* @type {LinkedList}
*/
_classPrivateFieldInitSpec(this, _cellsHorizontalOrder, new _linkedList.default());
/**
* The linked list of the all cells within the current selection in horizontal order. The list is
* recreated every time the selection is changed.
*
* @type {LinkedList}
*/
_classPrivateFieldInitSpec(this, _cellsVerticalOrder, new _linkedList.default());
/**
* The currently highlighted cell within the horizontal linked list.
*
* @type {NodeStructure | null}
*/
_classPrivateFieldInitSpec(this, _currentHorizontalLinkedNode, null);
/**
* The currently highlighted cell within the vertical linked list.
*
* @type {NodeStructure | null}
*/
_classPrivateFieldInitSpec(this, _currentVerticalLinkedNode, null);
/**
* The merged cells getter function.
*
* @type {function(): {row: number, col: number, rowspan: number, colspan: number} | null}}
*/
_classPrivateFieldInitSpec(this, _mergedCellsGetter, null);
/**
* The row index mapper.
*
* @type {IndexMapper}
*/
_classPrivateFieldInitSpec(this, _rowIndexMapper, null);
/**
* The column index mapper.
*
* @type {IndexMapper}
*/
_classPrivateFieldInitSpec(this, _columnIndexMapper, null);
_classPrivateFieldSet(_mergedCellsGetter, this, mergedCellsGetter);
_classPrivateFieldSet(_rowIndexMapper, this, rowIndexMapper);
_classPrivateFieldSet(_columnIndexMapper, this, columnIndexMapper);
}
/**
* Gets the currently selected node data from the vertical focus order list.
*
* @returns {NodeStructure}
*/
getCurrentVerticalNode() {
return _classPrivateFieldGet(_currentVerticalLinkedNode, this).data;
}
/**
* Gets the first node data from the vertical focus order list.
*
* @returns {NodeStructure}
*/
getFirstVerticalNode() {
return _classPrivateFieldGet(_cellsVerticalOrder, this).first.data;
}
/**
* Gets the next selected node data from the vertical focus order list.
*
* @returns {NodeStructure}
*/
getNextVerticalNode() {
return _classPrivateFieldGet(_currentVerticalLinkedNode, this).next.data;
}
/**
* Gets the previous selected node data from the vertical focus order list.
*
* @returns {NodeStructure}
*/
getPrevVerticalNode() {
return _classPrivateFieldGet(_currentVerticalLinkedNode, this).prev.data;
}
/**
* Gets the currently selected node data from the horizontal focus order list.
*
* @returns {NodeStructure}
*/
getCurrentHorizontalNode() {
return _classPrivateFieldGet(_currentHorizontalLinkedNode, this).data;
}
/**
* Gets the first node data from the horizontal focus order list.
*
* @returns {NodeStructure}
*/
getFirstHorizontalNode() {
return _classPrivateFieldGet(_cellsHorizontalOrder, this).first.data;
}
/**
* Gets the next selected node data from the horizontal focus order list.
*
* @returns {NodeStructure}
*/
getNextHorizontalNode() {
return _classPrivateFieldGet(_currentHorizontalLinkedNode, this).next.data;
}
/**
* Gets the previous selected node data from the horizontal focus order list.
*
* @returns {NodeStructure}
*/
getPrevHorizontalNode() {
return _classPrivateFieldGet(_currentHorizontalLinkedNode, this).prev.data;
}
/**
* Sets the previous node from the vertical focus order list as active.
*/
setPrevNodeAsActive() {
_classPrivateFieldSet(_currentVerticalLinkedNode, this, _classPrivateFieldGet(_currentVerticalLinkedNode, this).prev);
_classPrivateFieldSet(_currentHorizontalLinkedNode, this, _classPrivateFieldGet(_currentHorizontalLinkedNode, this).prev);
}
/**
* Sets the previous node from the horizontal focus order list as active.
*/
setNextNodeAsActive() {
_classPrivateFieldSet(_currentVerticalLinkedNode, this, _classPrivateFieldGet(_currentVerticalLinkedNode, this).next);
_classPrivateFieldSet(_currentHorizontalLinkedNode, this, _classPrivateFieldGet(_currentHorizontalLinkedNode, this).next);
}
/**
* Rebuilds the focus order list based on the provided selection.
*
* @param {CellRange[]} selectedRanges The selected ranges to build the focus order for.
*/
buildFocusOrder(selectedRanges) {
_classPrivateFieldSet(_cellsHorizontalOrder, this, new _linkedList.default());
selectedRanges.forEach((range, selectionLayer) => {
const visitedHorizontalCells = new WeakSet();
const topStart = range.getTopStartCorner();
const bottomEnd = range.getBottomEndCorner();
for (let r = topStart.row; r <= bottomEnd.row; r++) {
if (_classPrivateFieldGet(_rowIndexMapper, this).isHidden(r)) {
// eslint-disable-next-line no-continue
continue;
}
for (let c = topStart.col; c <= bottomEnd.col; c++) {
if (_classPrivateFieldGet(_columnIndexMapper, this).isHidden(c)) {
// eslint-disable-next-line no-continue
continue;
}
const node = _assertClassBrand(_FocusOrder_brand, this, _pushOrderNode).call(this, {
selectedRange: range,
selectionLayer,
listOrder: _classPrivateFieldGet(_cellsHorizontalOrder, this),
mergeCellsVisitor: visitedHorizontalCells,
row: r,
column: c
});
if (node) {
_classPrivateFieldSet(_currentHorizontalLinkedNode, this, node);
}
}
}
});
// create circular linked list
if (_classPrivateFieldGet(_cellsHorizontalOrder, this).first) {
_classPrivateFieldGet(_cellsHorizontalOrder, this).first.prev = _classPrivateFieldGet(_cellsHorizontalOrder, this).last;
_classPrivateFieldGet(_cellsHorizontalOrder, this).last.next = _classPrivateFieldGet(_cellsHorizontalOrder, this).first;
}
_classPrivateFieldSet(_cellsVerticalOrder, this, new _linkedList.default());
selectedRanges.forEach((range, selectionLayer) => {
const visitedVerticalCells = new WeakSet();
const topStart = range.getTopStartCorner();
const bottomEnd = range.getBottomEndCorner();
for (let c = topStart.col; c <= bottomEnd.col; c++) {
if (_classPrivateFieldGet(_columnIndexMapper, this).isHidden(c)) {
// eslint-disable-next-line no-continue
continue;
}
for (let r = topStart.row; r <= bottomEnd.row; r++) {
if (_classPrivateFieldGet(_rowIndexMapper, this).isHidden(r)) {
// eslint-disable-next-line no-continue
continue;
}
const node = _assertClassBrand(_FocusOrder_brand, this, _pushOrderNode).call(this, {
selectedRange: range,
selectionLayer,
listOrder: _classPrivateFieldGet(_cellsVerticalOrder, this),
mergeCellsVisitor: visitedVerticalCells,
row: r,
column: c
});
if (node) {
_classPrivateFieldSet(_currentVerticalLinkedNode, this, node);
}
}
}
});
// create circular linked list
if (_classPrivateFieldGet(_cellsVerticalOrder, this).first) {
_classPrivateFieldGet(_cellsVerticalOrder, this).first.prev = _classPrivateFieldGet(_cellsVerticalOrder, this).last;
_classPrivateFieldGet(_cellsVerticalOrder, this).last.next = _classPrivateFieldGet(_cellsVerticalOrder, this).first;
}
}
/**
* Sets the active node based on the provided row and column.
*
* @param {number} row The visual row index.
* @param {number} column The visual column index.
* @param {number} selectionLayerIndex The index of the selection layer to which the focus should be marked as active.
* @returns {FocusOrder}
*/
setActiveNode(row, column, selectionLayerIndex) {
_classPrivateFieldGet(_cellsHorizontalOrder, this).inorder(node => {
const {
selectionLayer,
rowStart,
rowEnd,
colStart,
colEnd
} = node.data;
if (selectionLayer === selectionLayerIndex && row >= rowStart && row <= rowEnd && column >= colStart && column <= colEnd) {
_classPrivateFieldSet(_currentHorizontalLinkedNode, this, node);
return true;
}
});
_classPrivateFieldGet(_cellsVerticalOrder, this).inorder(node => {
const {
selectionLayer,
rowStart,
rowEnd,
colStart,
colEnd
} = node.data;
if (selectionLayer === selectionLayerIndex && row >= rowStart && row <= rowEnd && column >= colStart && column <= colEnd) {
_classPrivateFieldSet(_currentVerticalLinkedNode, this, node);
return true;
}
});
return this;
}
}
exports.FocusOrder = FocusOrder;
function _pushOrderNode(_ref2) {
let {
selectedRange,
selectionLayer,
listOrder,
mergeCellsVisitor,
row,
column
} = _ref2;
const topStart = selectedRange.getTopStartCorner();
const bottomEnd = selectedRange.getBottomEndCorner();
const highlight = selectedRange.highlight.clone().normalize();
const mergeParent = _classPrivateFieldGet(_mergedCellsGetter, this).call(this, row, column);
if (mergeParent && mergeCellsVisitor.has(mergeParent)) {
return null;
}
const node = {
selectionLayer,
colStart: column,
colEnd: column,
rowStart: row,
rowEnd: row
};
if (mergeParent) {
mergeCellsVisitor.add(mergeParent);
if (mergeParent.row < topStart.row || mergeParent.row + mergeParent.rowspan - 1 > bottomEnd.row || mergeParent.col < topStart.col || mergeParent.col + mergeParent.colspan - 1 > bottomEnd.col) {
return null;
}
node.colStart = mergeParent.col;
node.colEnd = mergeParent.col + mergeParent.colspan - 1;
node.rowStart = mergeParent.row;
node.rowEnd = mergeParent.row + mergeParent.rowspan - 1;
}
const linkedNode = listOrder.push(node);
if (row === highlight.row && column === highlight.col || mergeParent && highlight.row >= mergeParent.row && highlight.row <= mergeParent.row + mergeParent.rowspan - 1 && highlight.col >= mergeParent.col && highlight.col <= mergeParent.col + mergeParent.colspan - 1) {
return linkedNode;
}
return null;
}