You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.9 KiB
114 lines
2.9 KiB
<script> |
|
import { activeField } from './field_sync.svelte.js'; |
|
import { api } from '../urls.svelte.js'; |
|
import { t } from '../translations.svelte.js'; |
|
|
|
let { |
|
editable = true, |
|
onclick = evt => {}, |
|
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 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(); |
|
} |
|
|
|
function typed(ev){ |
|
if (simple) { |
|
value.source = editValue.source; |
|
value.rendered = editValue.rendered; |
|
} |
|
if (ev.keyCode == 13 && ev.ctrlKey){ |
|
if (simple){ |
|
onSet(editValue.source); |
|
} else applyEdit(); |
|
} |
|
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 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> |
|
|
|
<style> |
|
textarea{ |
|
width: 100%; |
|
min-height: 100px; |
|
} |
|
div{ |
|
min-width: 40px; |
|
min-height: 20px; |
|
} |
|
div.editable:hover{ |
|
border: 1px dotted; |
|
} |
|
</style> |
|
|
|
{#if editing} |
|
<textarea bind:value={editValue.source} onkeyup={typed} autofocus={!simple}></textarea> |
|
{/if} |
|
<svelte:element this={type} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >{@html editValue.rendered}</svelte:element>
|
|
|