add new table tool
All checks were successful
Deploy Sokko G / deploy (push) Successful in 6s

This commit is contained in:
Shinuwa 2026-07-30 11:32:33 +02:00
parent 896ae23ff2
commit 025cd4bf22
19 changed files with 1336 additions and 1 deletions

View file

@ -48,6 +48,7 @@ const DEFAULT_MODULE_TITLES = {
links: "Liens",
counters: "Compteurs",
calculator: "Calculateur",
table: "Tableau",
timer: "Timer",
taskPlanner: "Planificateur de tâches",
imageAnnotation: "Annotation d'images"
@ -360,6 +361,36 @@ function normalizeCalculatorValue(value) {
return Number.isFinite(parsed) ? parsed : 0;
}
function clampTableSize(value, fallback, max) {
const parsed = Number.parseInt(value, 10);
return Number.isInteger(parsed) ? Math.min(max, Math.max(1, parsed)) : fallback;
}
function columnIndexToName(index) {
let value = Math.max(0, Number(index) || 0) + 1;
let name = "";
while (value > 0) {
const remainder = (value - 1) % 26;
name = String.fromCharCode(65 + remainder) + name;
value = Math.floor((value - 1) / 26);
}
return name;
}
function tableCellAddress(rowIndex, columnIndex) {
return `${columnIndexToName(columnIndex)}${rowIndex + 1}`;
}
function normalizeTableLabels(labels, length, getFallback) {
const sourceLabels = labels && typeof labels === "object" ? labels : {};
const normalized = {};
for (let index = 0; index < length; index += 1) {
const value = String(sourceLabels[index] || "").slice(0, 80);
if (value.trim() && value !== String(getFallback(index))) normalized[index] = value;
}
return normalized;
}
function isTimeString(value, allowWildcard = false) {
const pattern = allowWildcard ? /^(?:\d{2}|X):(?:\d{2}|X):(?:\d{2}|X)$/ : /^\d{2}:\d{2}:\d{2}$/;
if (!pattern.test(String(value || ""))) return false;
@ -406,6 +437,29 @@ export function normalizeCalculatorData(data) {
};
}
export function normalizeTableData(data) {
const rows = clampTableSize(data?.rows, 10, 50);
const columns = clampTableSize(data?.columns, 6, 20);
const sourceCells = data?.cells && typeof data.cells === "object" ? data.cells : {};
const cells = {};
for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
for (let columnIndex = 0; columnIndex < columns; columnIndex += 1) {
const address = tableCellAddress(rowIndex, columnIndex);
const value = String(sourceCells[address] || "").trim();
if (value) cells[address] = value.slice(0, 500);
}
}
return {
rows,
columns,
cells,
rowLabels: normalizeTableLabels(data?.rowLabels, rows, (rowIndex) => rowIndex + 1),
columnLabels: normalizeTableLabels(data?.columnLabels, columns, columnIndexToName)
};
}
export function normalizeTimerData(data) {
const stopwatch = data?.stopwatch || {};
const laps = (Array.isArray(stopwatch.laps) ? stopwatch.laps : [])
@ -657,6 +711,15 @@ export function compactModuleDataForStorage(type, value) {
if (!entries.length && !normalized.scrollResults) return null;
return normalized.scrollResults ? { entries, scrollResults: true } : { entries };
}
if (type === "table") {
const normalized = normalizeTableData(value);
const compact = { cells: normalized.cells };
if (normalized.rows !== 10) compact.rows = normalized.rows;
if (normalized.columns !== 6) compact.columns = normalized.columns;
if (Object.keys(normalized.rowLabels).length) compact.rowLabels = normalized.rowLabels;
if (Object.keys(normalized.columnLabels).length) compact.columnLabels = normalized.columnLabels;
return Object.keys(compact.cells).length || compact.rows || compact.columns || compact.rowLabels || compact.columnLabels ? compact : null;
}
if (type === "timer") {
const normalized = normalizeTimerData(value);
const compact = {};