handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
117 lines (115 loc) • 3.56 kB
JavaScript
import { logAggregatedItems, warn } from "../helpers/console.mjs";
import { isFunction } from "../helpers/function.mjs";
import { stringify } from "../helpers/mixed.mjs";
/**
* Runs source-data validator for a single cell.
*
* @param {*} value The value of the cell.
* @param {CellProperties} cellMeta The cell meta object.
* @param {string} [source] The call source identifier.
* @returns {boolean} True if valid, false otherwise.
*/
export function runSourceDataValidator(value, cellMeta, source) {
const validator = cellMeta.sourceDataValidator;
if (!isFunction(validator)) {
return true;
}
const isValid = validator(value, cellMeta, source);
if (isValid === true) {
return true;
}
const {
row,
col,
sourceDataWarningMessage,
allowInvalid
} = cellMeta;
if (sourceDataWarningMessage) {
logSourceDataWarning(sourceDataWarningMessage, [{
row,
col,
value
}]);
}
return allowInvalid === true;
}
/**
* Runs source-data validators for all cells and emits one aggregated warning per cell type
* message when invalid values are found, to avoid spamming the console.
*
* @param {Core} hotInstance The Handsontable instance.
* @param {string} [source] The call source identifier.
*/
export function runSourceDataValidators(hotInstance, source) {
const rowSourceCount = hotInstance.countSourceRows();
const colSourceCount = hotInstance.countSourceCols();
if (rowSourceCount === 0 || colSourceCount === 0) {
return;
}
const invalidByMessageType = new Map();
for (let row = 0; row < rowSourceCount; row += 1) {
for (let col = 0; col < colSourceCount; col += 1) {
const visualRow = hotInstance.toVisualRow(row);
const visualColumn = hotInstance.toVisualColumn(col);
if (visualRow === null || visualColumn === null) {
continue;
}
const cellMeta = hotInstance.getCellMeta(visualRow, visualColumn);
const {
sourceDataWarningMessage,
sourceDataValidator,
allowInvalid
} = cellMeta;
if (!isFunction(sourceDataValidator)) {
continue;
}
const dataSource = hotInstance._getDataSource();
const value = dataSource.getAtCell(row, col, null);
const isValid = sourceDataValidator(value, cellMeta, source);
if (isValid === true) {
continue;
}
if (allowInvalid === false) {
dataSource.setAtCell(row, col, null);
}
if (sourceDataWarningMessage) {
var _invalidByMessageType;
const message = sourceDataWarningMessage;
const list = (_invalidByMessageType = invalidByMessageType.get(message)) !== null && _invalidByMessageType !== void 0 ? _invalidByMessageType : [];
list.push({
row,
col,
value,
message
});
invalidByMessageType.set(message, list);
}
}
}
invalidByMessageType.forEach((items, message) => {
logSourceDataWarning(message, items);
});
}
/**
* Logs a source data warning.
*
* @param {string} message The message to log.
* @param {Array} items The list of affected cells.
*/
function logSourceDataWarning(message, items) {
logAggregatedItems({
logFunction: warn,
message,
items,
itemFormatter: _ref => {
let {
row,
col,
value
} = _ref;
const rawValue = stringify(value);
const shortValue = rawValue.length > 64 ? `${rawValue.slice(0, 64)}...` : rawValue;
return `row ${row}, col ${col}, value: "${shortValue}"`;
}
});
}