Files
Umbrella/frontend/src/Components/MarkdownEditor.svelte
Stephan Richter 9a27a501a8
All checks were successful
Build Docker Image / Docker-Build (push) Successful in 2m33s
Build Docker Image / Clean-Registry (push) Successful in -4s
implemented storing of data entered into a task form in localstore
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
2026-02-03 14:05:48 +01:00

124 lines
3.3 KiB
Svelte

<script>
import { activeField } from './field_sync.svelte.js';
import { api, target } from '../urls.svelte.js';
import { t } from '../translations.svelte.js';
let {
editable = true,
onclick = evt => {},
onRender = src => {},
onSet = newVal => {return true;},
simple = false,
type = 'div',
value = $bindable({source:null,rendered:null})
} = $props();
let editing = $state(false);
let editValue = $state({source:value.source,rendered:value.rendered});
let start = 0;
let timer = null;
async function applyEdit(){
let success = await onSet(editValue.source);
if (success) {
value.source = editValue.source;
value.rendered = editValue.rendered;
editing = false;
} else resetEdit();
}
function doSave(){
if (simple){
onSet(editValue.source);
} else applyEdit();
}
function resetEdit(){
editing = false;
editValue = {source:value.source,rendered:value.rendered};
}
function startEdit(){
activeField.update((n) => n+1);
editing = editable;
}
async function render(){
const url = api('markdown/render');
const resp = await fetch(url,{
credentials: 'include',
method : 'POST',
body : editValue.source
});
editValue.rendered = await resp.text();
onRender(editValue.source);
}
function typed(ev){
if (simple) {
value.source = editValue.source;
value.rendered = editValue.rendered;
}
if (ev.keyCode == 13 && ev.ctrlKey) doSave();
if (ev.keyCode == 27) resetEdit();
if (timer) clearTimeout(timer);
timer = setTimeout(render,500);
}
function measured(evt,duration){
if (duration < 500){
onclick(evt);
} else {
startEdit();
}
}
function oncontextmenu(evt){
evt.preventDefault();
evt.stopPropagation();
startEdit();
return false;
}
function onmousedown(evt){
evt.preventDefault();
start = evt.timeStamp;
}
function onmouseup(evt){
evt.preventDefault();
measured(evt, evt.timeStamp - start);
}
function ontouchstart(evt){
evt.preventDefault();
start = evt.timeStamp;
}
function ontouchend(evt){
evt.preventDefault();
measured(evt, evt.timeStamp - start);
}
activeField.subscribe((val) => resetEdit());
if (simple) startEdit();
</script>
<div class="markdown {editing?'editing':''}">
{#if editing}
<span class="hint">{@html t('markdown_supported')}</span>
<textarea bind:value={editValue.source} onkeyup={typed} autofocus={!simple}></textarea>
<div class="preview">{@html target(editValue.rendered)}</div>
{#if !simple}
<div class="buttons">
<button class="cancel" onclick={e => editing = false}>{t('cancel')}</button>
<button class="save" onclick={doSave}>{t('save')}</button>
</div>
{/if}
{:else}
<svelte:element this={type} {onclick} {oncontextmenu} class={{editable}} title={t('right_click_to_edit')} >{@html target(value.rendered)}</svelte:element>
{/if}
</div>