handsontable
Version:
Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.
257 lines (222 loc) • 8.4 kB
JavaScript
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); }
import "core-js/modules/es.object.get-prototype-of.js";
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/web.dom-collections.for-each.js";
import "core-js/modules/es.object.keys.js";
import "core-js/modules/es.symbol.js";
import "core-js/modules/es.symbol.description.js";
import "core-js/modules/es.symbol.iterator.js";
import "core-js/modules/es.array.iterator.js";
import "core-js/modules/es.string.iterator.js";
import "core-js/modules/web.dom-collections.iterator.js";
import { getCellType } from "./../cellTypes/registry.mjs";
import { deepObjectSize, hasOwnProperty, isObject } from "./object.mjs";
var COLUMN_LABEL_BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var COLUMN_LABEL_BASE_LENGTH = COLUMN_LABEL_BASE.length;
/**
* Generates spreadsheet-like column names: A, B, C, ..., Z, AA, AB, etc.
*
* @param {number} index Column index.
* @returns {string}
*/
export function spreadsheetColumnLabel(index) {
var dividend = index + 1;
var columnLabel = '';
var modulo;
while (dividend > 0) {
modulo = (dividend - 1) % COLUMN_LABEL_BASE_LENGTH;
columnLabel = String.fromCharCode(65 + modulo) + columnLabel;
dividend = parseInt((dividend - modulo) / COLUMN_LABEL_BASE_LENGTH, 10);
}
return columnLabel;
}
/**
* Generates spreadsheet-like column index from theirs labels: A, B, C ...., Z, AA, AB, etc.
*
* @param {string} label Column label.
* @returns {number}
*/
export function spreadsheetColumnIndex(label) {
var result = 0;
if (label) {
for (var i = 0, j = label.length - 1; i < label.length; i += 1, j -= 1) {
result += Math.pow(COLUMN_LABEL_BASE_LENGTH, j) * (COLUMN_LABEL_BASE.indexOf(label[i]) + 1);
}
}
result -= 1;
return result;
}
/**
* Creates 2D array of Excel-like values "A1", "A2", ...
*
* @param {number} rows Number of rows to generate.
* @param {number} columns Number of columns to generate.
* @returns {Array}
*/
export function createSpreadsheetData() {
var rows = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
var columns = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4;
var _rows = [];
var i;
var j;
for (i = 0; i < rows; i++) {
var row = [];
for (j = 0; j < columns; j++) {
row.push(spreadsheetColumnLabel(j) + (i + 1));
}
_rows.push(row);
}
return _rows;
}
/**
* Creates 2D array of Excel-like values "A1", "A2", as an array of objects.
*
* @param {number} rows Number of rows to generate.
* @param {number} colCount Number of columns to generate.
* @returns {Array}
*/
export function createSpreadsheetObjectData() {
var rows = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 100;
var colCount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4;
var _rows = [];
var i;
var j;
for (i = 0; i < rows; i++) {
var row = {};
for (j = 0; j < colCount; j++) {
row["prop".concat(j)] = spreadsheetColumnLabel(j) + (i + 1);
}
_rows.push(row);
}
return _rows;
}
/**
* Generates an empty data object.
*
* @param {number} rows Number of rows to generate.
* @param {number} columns Number of columns to generate.
* @returns {Array}
*/
export function createEmptySpreadsheetData(rows, columns) {
var data = [];
var row;
for (var i = 0; i < rows; i++) {
row = [];
for (var j = 0; j < columns; j++) {
row.push('');
}
data.push(row);
}
return data;
}
/**
* Factory that produces a function for searching methods (or any properties) which could be defined directly in
* table configuration or implicitly, within cell type definition.
*
* For example: renderer can be defined explicitly using "renderer" property in column configuration or it can be
* defined implicitly using "type" property.
*
* Methods/properties defined explicitly always takes precedence over those defined through "type".
*
* If the method/property is not found in an object, searching is continued recursively through prototype chain, until
* it reaches the Object.prototype.
*
* @param {string} methodName Name of the method/property to search (i.e. 'renderer', 'validator', 'copyable').
* @param {boolean} [allowUndefined] If `false`, the search is continued if methodName has not been found in cell
* "type".
* @returns {Function}
*/
export function cellMethodLookupFactory(methodName, allowUndefined) {
var isUndefinedAllowed = typeof allowUndefined === 'undefined' ? true : allowUndefined;
return function cellMethodLookup(row, col) {
return function getMethodFromProperties(properties) {
if (!properties) {
return; // method or property not found
}
if (hasOwnProperty(properties, methodName) && properties[methodName] !== void 0) {
// check if it is own and is not empty
return properties[methodName]; // method defined directly
} else if (hasOwnProperty(properties, 'type') && properties.type) {
// check if it is own and is not empty
if (typeof properties.type !== 'string') {
throw new Error('Cell "type" must be a string');
}
var type = getCellType(properties.type);
if (hasOwnProperty(type, methodName)) {
return type[methodName]; // method defined in type.
} else if (isUndefinedAllowed) {
return; // method does not defined in type (eg. validator), returns undefined
}
}
return getMethodFromProperties(Object.getPrototypeOf(properties));
}(typeof row === 'number' ? this.getCellMeta(row, col) : row);
};
}
/**
* Transform a data row (either an array or an object) or an array of data rows to array of changes in a form of `[row,
* prop/col, value]`. Convenient to use with `setDataAtRowProp` and `setSourceDataAtCell` methods.
*
* @param {Array|object} dataRow Object of row data, array of row data or an array of either.
* @param {number} rowOffset Row offset to be passed to the resulting change list. Defaults to `0`.
* @returns {Array} Array of changes (in a form of an array).
*/
export function dataRowToChangesArray(dataRow) {
var rowOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var dataRows = dataRow;
var changesArray = [];
if (!Array.isArray(dataRow) || !Array.isArray(dataRow[0])) {
dataRows = [dataRow];
}
dataRows.forEach(function (row, rowIndex) {
if (Array.isArray(row)) {
row.forEach(function (value, column) {
changesArray.push([rowIndex + rowOffset, column, value]);
});
} else {
Object.keys(row).forEach(function (propName) {
changesArray.push([rowIndex + rowOffset, propName, row[propName]]);
});
}
});
return changesArray;
}
/**
* Count the number of keys (or, basically, columns when the data is an array or arrays) in the first row of the
* provided dataset.
*
* @param {Array} data The dataset.
* @returns {number} Number of keys in the first row of the dataset.
*/
export function countFirstRowKeys(data) {
var result = 0;
if (Array.isArray(data)) {
if (data[0] && Array.isArray(data[0])) {
result = data[0].length;
} else if (data[0] && isObject(data[0])) {
result = deepObjectSize(data[0]);
}
}
return result;
}
/**
* Check whether the provided dataset is a *non-empty* array of arrays.
*
* @param {Array} data Dataset to be checked.
* @returns {boolean} `true` if data is an array of arrays, `false` otherwise.
*/
export function isArrayOfArrays(data) {
return !!(Array.isArray(data) && data.length && data.every(function (el) {
return Array.isArray(el);
}));
}
/**
* Check whether the provided dataset is a *non-empty* array of objects.
*
* @param {Array} data Dataset to be checked.
* @returns {boolean} `true` if data is an array of objects, `false` otherwise.
*/
export function isArrayOfObjects(data) {
return !!(Array.isArray(data) && data.length && data.every(function (el) {
return _typeof(el) === 'object' && !Array.isArray(el) && el !== null;
}));
}