From c04dfe225cc6e2d4b98aaa3c5a167c4a8cfbf146 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Mon, 30 Mar 2026 23:59:00 +0200 Subject: [PATCH] improved spreadsheet editing Signed-off-by: Stephan Richter --- .../src/Components/MarkdownDisplay.svelte | 35 ++++++++++++++----- frontend/src/Components/MarkdownEditor.svelte | 22 ++++++++---- .../resources/web/css/bloodshed-color.css | 4 +++ .../main/resources/web/css/default-color.css | 4 +++ 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/frontend/src/Components/MarkdownDisplay.svelte b/frontend/src/Components/MarkdownDisplay.svelte index a9fc860b..f77d5c41 100644 --- a/frontend/src/Components/MarkdownDisplay.svelte +++ b/frontend/src/Components/MarkdownDisplay.svelte @@ -2,7 +2,15 @@ import { onMount, onDestroy } from 'svelte'; import { t } from '../translations.svelte'; - let { classes='markdown', markdown=$bindable({source:'',rendered:''}), onclick = null, oncontextmenu = null, title='', wrapper = 'div' } = $props(); + 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.-]+$/ @@ -31,16 +39,16 @@ if (!markdown.rendered) return; let sheets = document.getElementsByClassName('spreadsheet'); for (let i = 0; i < sheets.length; i++) { - let sheet = sheets[i]; - let raw = sheet.innerHTML.trim(); + let current_sheet = sheets[i]; + let raw = current_sheet.innerHTML.trim(); if (!jspreadsheet) { - sheet.innerHTML = t('Loading spreadsheet library…'); + 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 - sheet.innerHTML = t('Processing spreadsheet data…'); + current_sheet.innerHTML = t('Processing spreadsheet data…'); // Use parseCSV from the helpers @@ -60,14 +68,25 @@ render: formatCell, width:`${len}0px` }}); + var w = window.innerWidth; + if (classes == 'preview') w = w/2; let config = { worksheets : [{ data:parsed, - columns + columns, + tableOverflow: true, + tableWidth: `${w}px`, }], - onchange : (instance, cell, x, y, value) => update(instance, i) + 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(sheet.id), config); + 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); + } } } diff --git a/frontend/src/Components/MarkdownEditor.svelte b/frontend/src/Components/MarkdownEditor.svelte index a3b1eef3..9fe79866 100644 --- a/frontend/src/Components/MarkdownEditor.svelte +++ b/frontend/src/Components/MarkdownEditor.svelte @@ -20,6 +20,7 @@ let start = 0; let stored_source = $state(store_id ? localStorage.getItem(store_id) : null); let timer = null; + let sheet = null; async function applyEdit(){ let success = await onSet(editValue.source); @@ -80,10 +81,13 @@ function oncontextmenu(evt){ - evt.preventDefault(); - evt.stopPropagation(); - startEdit(); - return false; + if (evt.target) { + evt.preventDefault(); + evt.stopPropagation(); + } + sheet = evt.sheet ? evt : null; // store position of activated cell to focus after editing starts + startEdit(); + return false; } function onmousedown(evt){ @@ -96,6 +100,10 @@ measured(evt, evt.timeStamp - start); } + function onresize(evt){ + console.log('onresize()',evt); + } + function ontouchstart(evt){ evt.preventDefault(); start = evt.timeStamp; @@ -137,8 +145,8 @@ {#if stored_source} {t('unsaved_content')} {/if} - - + + {#if !simple}
@@ -146,6 +154,6 @@
{/if} {:else} - + {/if} diff --git a/web/src/main/resources/web/css/bloodshed-color.css b/web/src/main/resources/web/css/bloodshed-color.css index 231c8362..40523ae1 100644 --- a/web/src/main/resources/web/css/bloodshed-color.css +++ b/web/src/main/resources/web/css/bloodshed-color.css @@ -334,6 +334,10 @@ tr:hover .taglist .tag button { border-left: 1px solid #333 !important; } +.jss_worksheet tr:hover td input{ + color: yellow; +} + @media screen and (max-width: 900px) { #app nav a{ background: black; diff --git a/web/src/main/resources/web/css/default-color.css b/web/src/main/resources/web/css/default-color.css index 9126f295..621b7377 100644 --- a/web/src/main/resources/web/css/default-color.css +++ b/web/src/main/resources/web/css/default-color.css @@ -325,6 +325,10 @@ tr:hover .taglist .tag button { border-left: 1px solid #333 !important; } +.jss_worksheet tr:hover td input{ + color: black; +} + @media screen and (max-width: 900px) { #app nav a{ background: black;