102 lines
3.4 KiB
Svelte
102 lines
3.4 KiB
Svelte
<script>
|
|
import { onMount, onDestroy } from 'svelte';
|
|
import { t } from '../translations.svelte';
|
|
|
|
let {
|
|
classes='markdown',
|
|
markdown=$bindable({source:'',rendered:''}),
|
|
onclick = null,
|
|
oncontextmenu = e => {},
|
|
sheet = null,
|
|
title='',
|
|
wrapper = 'div'
|
|
} = $props();
|
|
let jspreadsheet = null;
|
|
const regex = /@startsheet[\s\S]*?@endsheet/g;
|
|
const number = /^[0-9.-]+$/
|
|
|
|
function update(sheet, index){
|
|
const data = sheet.getData(false,false,'|',false);
|
|
markdown.source = replaceNthSpreadsheet(markdown.source,index,data);
|
|
}
|
|
|
|
function replaceNthSpreadsheet(text, n, newContent) {
|
|
const blocks = text.match(regex) || [];
|
|
if (blocks.length < n+1){
|
|
console.warn(`cannot replace block ${n}: only ${blocks.length} blocks found!`);
|
|
return text;
|
|
}
|
|
let count = 0;
|
|
return text.replace(regex, (match) => count++ === n ? `@startsheet\n${newContent}\n@endsheet` : match);
|
|
}
|
|
|
|
function formatCell(cell, value, x, y, instance, options){
|
|
value = value.trim();
|
|
if (value.startsWith('=') || number.test(value)) cell.style.textAlign = 'right';
|
|
}
|
|
|
|
async function transform(){
|
|
if (!markdown.rendered) return;
|
|
let sheets = document.getElementsByClassName('spreadsheet');
|
|
for (let i = 0; i < sheets.length; i++) {
|
|
let current_sheet = sheets[i];
|
|
let raw = current_sheet.innerHTML.trim();
|
|
if (!jspreadsheet) {
|
|
current_sheet.innerHTML = t('Loading spreadsheet library…');
|
|
let module = await import('jspreadsheet-ce'); // path or package name
|
|
await import('jspreadsheet-ce/dist/jspreadsheet.css');
|
|
jspreadsheet = module.default ?? module;
|
|
}
|
|
if (!jspreadsheet) break; // break loop if library fails to load
|
|
current_sheet.innerHTML = t('Processing spreadsheet data…');
|
|
|
|
|
|
// Use parseCSV from the helpers
|
|
const parsed = jspreadsheet.helpers.parseCSV(raw, '|');
|
|
let columns = {};
|
|
|
|
for (let row of parsed){
|
|
for (let col in row){
|
|
let data = ""+row[col];
|
|
if (data.startsWith('=')) continue;
|
|
let len = data.length;
|
|
columns[col] = Math.max(columns[col]??0,len);
|
|
}
|
|
}
|
|
columns = Object.values(columns).map((len) => {return {
|
|
align: 'left',
|
|
render: formatCell,
|
|
width:`${len}0px`
|
|
}});
|
|
var w = window.innerWidth;
|
|
if (classes == 'preview') w = w/2;
|
|
let config = {
|
|
worksheets : [{
|
|
data:parsed,
|
|
columns,
|
|
tableOverflow: true,
|
|
tableWidth: `${w}px`,
|
|
}],
|
|
onchange : (instance, cell, x, y, value) => update(instance, i),
|
|
oneditionstart : (instance, cell, x, y) => oncontextmenu({sheet:current_sheet.id, x,y})
|
|
};
|
|
let wb = jspreadsheet(document.getElementById(current_sheet.id), config);
|
|
if (sheet && sheet.sheet == current_sheet.id) {
|
|
let cell = wb[0].getCellFromCoords(sheet.x, sheet.y);
|
|
cell.scrollIntoView({block:'center'});
|
|
wb[0].updateSelectionFromCoords(sheet.x, sheet.y);
|
|
wb[0].openEditor(cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
onMount(() => { setTimeout(transform,200)});
|
|
|
|
</script>
|
|
|
|
{#if markdown.rendered}
|
|
<svelte:element this={wrapper} class={classes} {onclick} {oncontextmenu} {title}>
|
|
{@html markdown.rendered}
|
|
</svelte:element>
|
|
{/if}
|