implemented task editing right from the project list

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-07-25 22:03:53 +02:00
parent be0435db1b
commit 5bc84f1321
7 changed files with 284 additions and 26 deletions

View File

@@ -2,10 +2,17 @@
import { activeField } from './field_sync.svelte.js';
import { t } from '../translations.svelte.js';
let { editable = false, value = $bindable(null), onSet = (newVal) => {return true;} } = $props();
let {
editable = false,
onclick = evt => {},
onSet = newVal => {return true;},
type = 'div',
value = $bindable(null)
} = $props();
let editing = $state(false);
let editValue = value;
let start = 0;
async function applyEdit(){
let success = await onSet(editValue);
@@ -28,6 +35,35 @@
if (ev.keyCode == 27) resetEdit();
}
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());
</script>
@@ -48,5 +84,5 @@
{#if editable && editing}
<input bind:value={editValue} onkeyup={typed} autofocus />
{:else}
<div ondblclick={startEdit} class={{editable}} title={t('double_click_to_edit')} >{value}</div>
<svelte:element this={type} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >{value}</svelte:element>
{/if}

View File

@@ -2,16 +2,18 @@
import { t } from '../translations.svelte.js';
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../urls.svelte.js';
import TaskList from './TaskList.svelte';
import LineEditor from './LineEditor.svelte';
const router = useTinyRouter();
let { estimated_time, show_closed, task } = $props();
let children = $state(null);
let error = $state(null);
let start = 0;
async function loadChildren(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/task/list`;
const url = api('task/list');
var data = {
parent_task_id:+task.id,
show_closed: show_closed
@@ -30,11 +32,21 @@
}
}
function openTask(evt){
evt.preventDefault();
console.log('openTask(…)',evt,task);
function openTask(){
router.navigate(`/task/${task.id}/view`);
//location.href = `https://umbrella.srsoftware.de/task/${task.id}/view`;
}
async function patchTask(newName){
console.log('patchTask('+newName+')');
const url = api(`task/${task.id}`);
const resp = await fetch(url,{
credentials:'include',
method: 'PATCH',
body: JSON.stringify({name:newName})
});
let ok = resp.ok;
console.log({ok:ok});
return ok;
}
if (task.estimated_time){
@@ -46,9 +58,7 @@
</script>
<li class="task {task.status.name.toLowerCase()}">
<span class="name" onclick={openTask}>
{task.name}
</span>
<LineEditor bind:value={task.name} onclick={openTask} editable={true} onSet={patchTask} type="span" />
{#if task.estimated_time}
<span class="estimated_time">({+task.estimated_time}&nbsp;h)</span>
{/if}

View File

@@ -4,9 +4,11 @@
let {
editable = true,
onclick = evt => {},
onSet = newVal => {return true;},
simple = false,
value = $bindable({source:null,rendered:null}),
onSet = (newVal) => {}
type = 'div',
value = $bindable({source:null,rendered:null})
} = $props();
let editing = $state(false);
@@ -14,6 +16,7 @@
let editValue = $state({source:value.source,rendered:value.rendered});
let timer = null;
let start = 0;
async function applyEdit(){
let success = await onSet(editValue.source);
@@ -55,6 +58,34 @@
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>
@@ -76,4 +107,4 @@
{#if editing}
<textarea bind:value={editValue.source} onkeyup={typed} autofocus={!simple}></textarea>
{/if}
<div ondblclick={startEdit} class={{editable}} title={t('double_click_to_edit')} >{@html editValue.rendered}</div>
<svelte:element this={type} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >{@html editValue.rendered}</svelte:element>

View File

@@ -2,12 +2,18 @@
import { activeField } from './field_sync.svelte.js';
import { t } from '../translations.svelte.js';
let { editable = false, value = $bindable(null), onSet = (newVal) => {} } = $props();
let {
editable = false,
onclick = evt => {},
onSet = newVal => {return true;},
type = 'div',
value = $bindable(null)
} = $props();
let editing = $state(false);
let editValue = $state(value);
let timer = null;
let start = 0;
async function applyEdit(){
let success = await onSet(editValue);
@@ -29,7 +35,34 @@
if (ev.keyCode == 13 && ev.ctrlKey) applyEdit();
if (ev.keyCode == 27) resetEdit();
}
console.log(value);
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());
</script>
@@ -52,10 +85,10 @@
<textarea bind:value={editValue} onkeyup={typed} autofocus></textarea>
{:else}
{#if value}
<div ondblclick={startEdit} class={{editable}} title={t('double_click_to_edit')} >
<svelte:element this={type} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} class={{editable}} title={t('double_click_to_edit')} >
{#each value.split("\n") as line}
{line}<br/>
{/each}
</div>
</svelte:element>
{/if}
{/if}