handsontable
Version:
Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.
433 lines (340 loc) • 16.5 kB
JavaScript
"use strict";
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.iterator.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.array.slice.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.array.from.js");
require("core-js/modules/es.regexp.exec.js");
exports.__esModule = true;
exports.default = void 0;
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.array.concat.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/es.object.values.js");
var _element = require("./../../../helpers/dom/element");
var _border = _interopRequireDefault(require("./border"));
var _coords = _interopRequireDefault(require("./cell/coords"));
var _range = _interopRequireDefault(require("./cell/range"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
/**
* @class Selection
*/
var Selection = /*#__PURE__*/function () {
/**
* @param {object} settings The selection settings object.
* @param {CellRange} cellRange The cell range instance.
*/
function Selection(settings, cellRange) {
_classCallCheck(this, Selection);
this.settings = settings;
this.cellRange = cellRange || null;
this.instanceBorders = {};
this.classNames = [this.settings.className];
this.classNameGenerator = this.linearClassNameGenerator(this.settings.className, this.settings.layerLevel);
}
/**
* Each Walkontable clone requires it's own border for every selection. This method creates and returns selection
* borders per instance.
*
* @param {Walkontable} wotInstance The Walkontable instance.
* @returns {Border}
*/
_createClass(Selection, [{
key: "getBorder",
value: function getBorder(wotInstance) {
if (!this.instanceBorders[wotInstance.guid]) {
this.instanceBorders[wotInstance.guid] = new _border.default(wotInstance, this.settings);
}
return this.instanceBorders[wotInstance.guid];
}
/**
* Checks if selection is empty.
*
* @returns {boolean}
*/
}, {
key: "isEmpty",
value: function isEmpty() {
return this.cellRange === null;
}
/**
* Adds a cell coords to the selection.
*
* @param {CellCoords} coords The cell coordinates to add.
* @returns {Selection}
*/
}, {
key: "add",
value: function add(coords) {
if (this.isEmpty()) {
this.cellRange = new _range.default(coords);
} else {
this.cellRange.expand(coords);
}
return this;
}
/**
* If selection range from or to property equals oldCoords, replace it with newCoords. Return boolean
* information about success.
*
* @param {CellCoords} oldCoords An old cell coordinates to replace.
* @param {CellCoords} newCoords The new cell coordinates.
* @returns {boolean}
*/
}, {
key: "replace",
value: function replace(oldCoords, newCoords) {
if (!this.isEmpty()) {
if (this.cellRange.from.isEqual(oldCoords)) {
this.cellRange.from = newCoords;
return true;
}
if (this.cellRange.to.isEqual(oldCoords)) {
this.cellRange.to = newCoords;
return true;
}
}
return false;
}
/**
* Clears selection.
*
* @returns {Selection}
*/
}, {
key: "clear",
value: function clear() {
this.cellRange = null;
return this;
}
/**
* Returns the top left (TL) and bottom right (BR) selection coordinates.
*
* @returns {Array} Returns array of coordinates for example `[1, 1, 5, 5]`.
*/
}, {
key: "getCorners",
value: function getCorners() {
var topLeft = this.cellRange.getOuterTopLeftCorner();
var bottomRight = this.cellRange.getOuterBottomRightCorner();
return [topLeft.row, topLeft.col, bottomRight.row, bottomRight.col];
}
/**
* Adds class name to cell element at given coords.
*
* @param {Walkontable} wotInstance Walkontable instance.
* @param {number} sourceRow Cell row coord.
* @param {number} sourceColumn Cell column coord.
* @param {string} className Class name.
* @param {boolean} [markIntersections=false] If `true`, linear className generator will be used to add CSS classes
* in a continuous way.
* @returns {Selection}
*/
}, {
key: "addClassAtCoords",
value: function addClassAtCoords(wotInstance, sourceRow, sourceColumn, className) {
var markIntersections = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
var TD = wotInstance.wtTable.getCell(new _coords.default(sourceRow, sourceColumn));
if (_typeof(TD) === 'object') {
var cellClassName = className;
if (markIntersections) {
cellClassName = this.classNameGenerator(TD);
if (!this.classNames.includes(cellClassName)) {
this.classNames.push(cellClassName);
}
}
(0, _element.addClass)(TD, cellClassName);
}
return this;
}
/**
* Generate helper for calculating classNames based on previously added base className.
* The generated className is always generated as a continuation of the previous className. For example, when
* the currently checked element has 'area-2' className the generated new className will be 'area-3'. When
* the element doesn't have any classNames than the base className will be returned ('area');.
*
* @param {string} baseClassName Base className to be used.
* @param {number} layerLevelOwner Layer level which the instance of the Selection belongs to.
* @returns {Function}
*/
}, {
key: "linearClassNameGenerator",
value: function linearClassNameGenerator(baseClassName, layerLevelOwner) {
// TODO: Make this recursive function Proper Tail Calls (TCO/PTC) friendly.
return function calcClassName(element) {
var previousIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
if (layerLevelOwner === 0 || previousIndex === 0) {
return baseClassName;
}
var index = previousIndex >= 0 ? previousIndex : layerLevelOwner;
var className = baseClassName;
index -= 1;
var previousClassName = index === 0 ? baseClassName : "".concat(baseClassName, "-").concat(index);
if ((0, _element.hasClass)(element, previousClassName)) {
var currentLayer = index + 1;
className = "".concat(baseClassName, "-").concat(currentLayer);
} else {
className = calcClassName(element, index);
}
return className;
};
}
/**
* @param {Walkontable} wotInstance The Walkontable instance.
*/
}, {
key: "draw",
value: function draw(wotInstance) {
if (this.isEmpty()) {
if (this.settings.border) {
this.getBorder(wotInstance).disappear();
}
return;
}
var renderedRows = wotInstance.wtTable.getRenderedRowsCount();
var renderedColumns = wotInstance.wtTable.getRenderedColumnsCount();
var corners = this.getCorners();
var _corners = _slicedToArray(corners, 4),
topRow = _corners[0],
topColumn = _corners[1],
bottomRow = _corners[2],
bottomColumn = _corners[3];
var _this$settings = this.settings,
highlightHeaderClassName = _this$settings.highlightHeaderClassName,
highlightColumnClassName = _this$settings.highlightColumnClassName,
highlightRowClassName = _this$settings.highlightRowClassName,
highlightOnlyClosestHeader = _this$settings.highlightOnlyClosestHeader,
selectionType = _this$settings.selectionType;
var isHeaderSelectionType = selectionType === void 0 || ['active-header', 'header'].includes(selectionType);
if (isHeaderSelectionType && topColumn !== null && bottomColumn !== null) {
var selectionColumnCursor = 0;
for (var column = 0; column < renderedColumns; column += 1) {
var sourceCol = wotInstance.wtTable.columnFilter.renderedToSource(column);
if (sourceCol >= topColumn && sourceCol <= bottomColumn) {
var THs = wotInstance.wtTable.getColumnHeaders(sourceCol);
var closestHeaderLevel = THs.length - 1;
if (highlightOnlyClosestHeader && THs.length > 1) {
THs = [THs[closestHeaderLevel]];
}
for (var headerLevel = 0; headerLevel < THs.length; headerLevel += 1) {
var newClasses = [];
var TH = THs[headerLevel];
if (highlightHeaderClassName) {
newClasses.push(highlightHeaderClassName);
}
if (highlightColumnClassName) {
newClasses.push(highlightColumnClassName);
}
headerLevel = highlightOnlyClosestHeader ? closestHeaderLevel : headerLevel;
var newSourceCol = wotInstance.getSetting('onBeforeHighlightingColumnHeader', sourceCol, headerLevel, {
selectionType: selectionType,
columnCursor: selectionColumnCursor,
selectionWidth: bottomColumn - topColumn + 1,
classNames: newClasses
});
if (newSourceCol !== sourceCol) {
TH = wotInstance.wtTable.getColumnHeader(newSourceCol, headerLevel);
}
(0, _element.addClass)(TH, newClasses);
}
selectionColumnCursor += 1;
}
}
}
if (topRow !== null && bottomRow !== null) {
var selectionRowCursor = 0;
for (var row = 0; row < renderedRows; row += 1) {
var sourceRow = wotInstance.wtTable.rowFilter.renderedToSource(row);
if (isHeaderSelectionType && sourceRow >= topRow && sourceRow <= bottomRow) {
var _THs = wotInstance.wtTable.getRowHeaders(sourceRow);
var _closestHeaderLevel = _THs.length - 1;
if (highlightOnlyClosestHeader && _THs.length > 1) {
_THs = [_THs[_closestHeaderLevel]];
}
for (var _headerLevel = 0; _headerLevel < _THs.length; _headerLevel += 1) {
var _newClasses = [];
var _TH = _THs[_headerLevel];
if (highlightHeaderClassName) {
_newClasses.push(highlightHeaderClassName);
}
if (highlightRowClassName) {
_newClasses.push(highlightRowClassName);
}
_headerLevel = highlightOnlyClosestHeader ? _closestHeaderLevel : _headerLevel;
var newSourceRow = wotInstance.getSetting('onBeforeHighlightingRowHeader', sourceRow, _headerLevel, {
selectionType: selectionType,
rowCursor: selectionRowCursor,
selectionHeight: bottomRow - topRow + 1,
classNames: _newClasses
});
if (newSourceRow !== sourceRow) {
_TH = wotInstance.wtTable.getRowHeader(newSourceRow, _headerLevel);
}
(0, _element.addClass)(_TH, _newClasses);
}
selectionRowCursor += 1;
}
if (topColumn !== null && bottomColumn !== null) {
for (var _column = 0; _column < renderedColumns; _column += 1) {
var _sourceCol = wotInstance.wtTable.columnFilter.renderedToSource(_column);
if (sourceRow >= topRow && sourceRow <= bottomRow && _sourceCol >= topColumn && _sourceCol <= bottomColumn) {
// selected cell
if (this.settings.className) {
this.addClassAtCoords(wotInstance, sourceRow, _sourceCol, this.settings.className, this.settings.markIntersections);
}
} else if (sourceRow >= topRow && sourceRow <= bottomRow) {
// selection is in this row
if (highlightRowClassName) {
this.addClassAtCoords(wotInstance, sourceRow, _sourceCol, highlightRowClassName);
}
} else if (_sourceCol >= topColumn && _sourceCol <= bottomColumn) {
// selection is in this column
if (highlightColumnClassName) {
this.addClassAtCoords(wotInstance, sourceRow, _sourceCol, highlightColumnClassName);
}
}
var additionalSelectionClass = wotInstance.getSetting('onAfterDrawSelection', sourceRow, _sourceCol, this.settings.layerLevel);
if (typeof additionalSelectionClass === 'string') {
this.addClassAtCoords(wotInstance, sourceRow, _sourceCol, additionalSelectionClass);
}
}
}
}
}
wotInstance.getSetting('onBeforeDrawBorders', corners, this.settings.className);
if (this.settings.border) {
// warning! border.appear modifies corners!
this.getBorder(wotInstance).appear(corners);
}
}
/**
* Cleans up all the DOM state related to a Selection instance. Call this prior to deleting a Selection instance.
*/
}, {
key: "destroy",
value: function destroy() {
Object.values(this.instanceBorders).forEach(function (border) {
return border.destroy();
});
}
}]);
return Selection;
}();
var _default = Selection;
exports.default = _default;