major improvement to easylist for usability on mobile devices

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-11-29 00:43:58 +01:00
parent 600b0f2cf4
commit 8f82ca87b4
11 changed files with 119 additions and 91 deletions

View File

@@ -20,11 +20,23 @@
let x = 0;
let y = 0;
function byName(a,b){
return a.name.localeCompare(b.name);
}
function extend(e,task){
e.preventDefault();
e.stopPropagation();
highlight = task;
return false;
}
function getTask(evt){
var link = evt.target;
var id = link.getAttribute('task_id');
return tasks[id];
}
function goTag(e,newTag){
e.preventDefault();
e.stopPropagation();
@@ -33,6 +45,12 @@
load();
}
function ignore(evt){
evt.preventDefault();
evt.stopPropagation();
return false;
}
async function load(){
const url = api(`task/tagged/${tag}`);
const res = await get(url);
@@ -43,57 +61,17 @@
} else error(res);
}
function noNoIndex(task){
return !task.no_index;
}
function ignore(evt){
evt.preventDefault();
evt.stopPropagation();
function match(task){
if (!search) return true;
if (task.name.toLowerCase().includes(search)) return true;
if (task.tags){
for (let tag of task.tags){
if (tag.toLowerCase().includes(search)) return true;
}
}
return false;
}
function extend(e,task){
e.preventDefault();
e.stopPropagation();
highlight = task;
return false;
}
function getTask(evt){
var link = evt.target;
var id = link.getAttribute('task_id');
return tasks[id];
}
function onclick(evt) {
let task = getTask(evt);
if (task.status <= 20) { // open
update(task,60);
} else update(task,20);
return ignore(evt);
}
function oncontextmenu(evt) {
highlight = getTask(evt);
return ignore(evt);
}
function ontouchstart(evt){
start = evt.timeStamp;
x = evt.touches[0].clientX;
y = evt.touches[0].clientY;
return ignore(evt);
}
function ontouchend(evt){
let d = Math.abs(x - evt.changedTouches[0].clientX) + Math.abs(y - evt.changedTouches[0].clientY);
measured(evt, evt.timeStamp - start, d);
return ignore(evt);
}
function measured(evt,duration,d){
if (d > 100) return;
if (duration < 500){
@@ -103,6 +81,41 @@
}
}
function noNoIndex(task){
return !task.no_index;
}
function onclick(evt) {
ignore(evt);
let task = getTask(evt);
if (task.status <= 20) { // open
update(task,60);
} else update(task,20);
return false;
}
function oncontextmenu(evt) {
ignore(evt);
highlight = getTask(evt);
return false;
}
function ontouchstart(evt){
ignore(evt);
start = evt.timeStamp;
x = evt.touches[0].clientX;
y = evt.touches[0].clientY;
return false;
}
function ontouchend(evt){
ignore(evt);
let d = Math.abs(x - evt.changedTouches[0].clientX) + Math.abs(y - evt.changedTouches[0].clientY);
measured(evt, evt.timeStamp - start, d);
return false;
}
async function update(task,newState){
highlight = null;
const url = api(`task/${task.id}`);
@@ -111,25 +124,23 @@
task.status = newState;
yikes();
// filter = null; // not sure what is better, resetting or keeping
input.focus();
} else error(res);
}
onMount(load);
</script>
<h2>{tag}</h2>
<h2>{t('tasks_for_tag',{tag:decodeURI(tag)})}</h2>
<div class="easylist">
<fieldset class="open">
<legend>{t('state_open')}</legend>
{#if sorted}
{#each sorted as task}
{#if task.status == 20 && (!filter || task.name.toLowerCase().includes(search))}
<a href={`/task/${task.id}/view`} title={task.description.source} task_id={task.id} {onclick} {oncontextmenu} {ontouchstart} {ontouchend} >
{#if task.status == 20 && match(task)}
<div href={`/task/${task.id}/view`} title={task.description.source} task_id={task.id} {onclick} {oncontextmenu} {ontouchstart} {ontouchend} onmousedown={ontouchstart} onmouseup={ontouchend} >
{task.name}
</a>
</div>
{#if highlight == task}
<Detail task={task} goTag={goTag} />
{/if}
@@ -142,10 +153,10 @@
<legend>{t('state_complete')}</legend>
{#if sorted}
{#each sorted as task}
{#if task.status > 20 && (!filter || task.name.toLowerCase().includes(search))}
<a href={`/task/${task.id}/view`} title={task.description.source} task_id={task.id} {onclick} {oncontextmenu} {ontouchstart} {ontouchend} >
{#if task.status > 20 && match(task)}
<div href={`/task/${task.id}/view`} title={task.description.source} task_id={task.id} {onclick} {oncontextmenu} {ontouchstart} {ontouchend} onmousedown={ontouchstart} onmouseup={ontouchend} >
{task.name}
</a>
</div>
{#if highlight == task}
<Detail task={task} goTag={goTag} />
{/if}

View File

@@ -1,26 +1,20 @@
<script>
import { onMount } from 'svelte';
import { api, get, patch } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte';
let { goTag, task } = $props();
let router = useTinyRouter();
async function load(){
const url = api(`tags/task/${task.id}`);
const res = await get(url);
if (res.ok){
yikes();
task.tags = await res.json();
} else error(res);
function onclick(){
router.navigate(`/task/${task.id}/edit`);
}
onMount(load);
</script>
<button class="edit" {onclick}>{t('edit')}</button>
{@html task.description.rendered}
{#if task.tags}
{t('other_tags')}:
{t('other_tags')}:<br/>
{#each task.tags as tag}
<button onclick={e => goTag(e,tag)}>{tag}</button>
{/each}