commit 2be1af9398d2829739ebea6ec6dcfacbe37ef894
parent 66aea629d04984c408eb71a1b36ea60db901b254
Author: Hunter
Date:   Thu,  8 Aug 2024 20:33:41 -0400

shake when trying to delete root or last child

Diffstat:
Mindex.html | 96++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 54 insertions(+), 42 deletions(-)

diff --git a/index.html b/index.html @@ -241,6 +241,8 @@ function loadTasksFromLocalStorage() { const savedTasks = localStorage.getItem('taskTree'); if (savedTasks) { + console.log('%cloaded tasks from local storage:', "color: green;"); + console.log(savedTasks); return deserializeTaskTree(savedTasks); } else { return { id: 'root', text: 'todo', state: 0, subtasks: [{ id: Date.now(), text: '', state: 0, subtasks: [] }], selectedSubtaskId: null }; @@ -348,6 +350,9 @@ } else { deleteSubtask(task); } + } else { + // Attempting to delete root task + applyShakeAnimation(task.id); } } else if (taskInput.value !== '') { keyHandler.backspace.canDelete = false; @@ -464,7 +469,6 @@ function toggleTaskState(task) { if (task.state === 1) { - // if all direct children are checked, disallow unchecking if (task.subtasks.length === 0 || !task.subtasks.every(t => t.state === 1)) { task.state = 0; updateSubtasksState(task, 0); @@ -479,13 +483,7 @@ scheduleSave(); } else { // disallow unchecking and play a 'shake' animation - const checkbox = document.querySelector(`.task-container[data-id="${task.id}"] .checkbox-label`); - if (checkbox) { - checkbox.classList.add('shake'); - setTimeout(() => { - checkbox.classList.remove('shake'); - }, 250); // Remove class after animation completes - } + applyShakeAnimation(task.id); } } else { task.state = 1; @@ -502,6 +500,16 @@ } } + function applyShakeAnimation(taskId) { + const checkbox = document.querySelector(`.task-container[data-id="${taskId}"] .checkbox-label`); + if (checkbox) { + checkbox.classList.add('shake'); + setTimeout(() => { + checkbox.classList.remove('shake'); + }, 250); // Remove class after animation completes + } + } + function recalculateTaskState(task) { if (task.subtasks.length === 0) { return task.state; // If no subtasks, keep current state @@ -554,6 +562,8 @@ const index = parentTask.subtasks.findIndex(t => t.id === subtask.id); if (parentTask.id === 'root' && parentTask.subtasks.length === 1) { + // Disallow deletion of the root task's sole remaining child + applyShakeAnimation(subtask.id); return; } @@ -577,6 +587,42 @@ scheduleSave(); } + function deleteCurrentParentTask() { + if (taskPath.length <= 1) return; // Don't delete root task + + const currentParentTask = taskPath[taskPath.length - 1]; + const grandparentTask = taskPath[taskPath.length - 2]; + + // Check if we're trying to delete the sole child of the root + if (grandparentTask.id === 'root' && grandparentTask.subtasks.length === 1) { + // Don't allow deletion of the sole child of root + applyShakeAnimation(currentParentTask.id); + return; + } + + const index = grandparentTask.subtasks.findIndex(t => t.id === currentParentTask.id); + + grandparentTask.subtasks = grandparentTask.subtasks.filter(t => t.id !== currentParentTask.id); + updateTaskAndAncestors(grandparentTask); + + taskPath.pop(); // Remove the deleted task from the path + currentTask = grandparentTask; + + if (grandparentTask.subtasks.length === 0 && taskPath.length > 1) { + // If we've just deleted the last subtask, navigate up another level + navigateToParentTask(); + } else { + renderCurrentView(); + if (grandparentTask.subtasks.length > 0) { + // Select the subtask before the deleted one, or the one after if at the start + const targetIndex = Math.max(0, index - 1); + selectAndFocusTask(grandparentTask.subtasks[targetIndex]); + } else { + selectAndFocusTask(grandparentTask); + } + } + } + function findParentTask(task) { for (let i = taskPath.length - 1; i >= 0; i--) { const potentialParent = taskPath[i]; @@ -671,40 +717,6 @@ taskInput.setSelectionRange(0, 0); } - function deleteCurrentParentTask() { - if (taskPath.length <= 1) return; // Don't delete root task - - const currentParentTask = taskPath[taskPath.length - 1]; - const grandparentTask = taskPath[taskPath.length - 2]; - - // Check if we're trying to delete the sole child of the root - if (grandparentTask.id === 'root' && grandparentTask.subtasks.length === 1) { - return; // Don't allow deletion of the sole child of root - } - - const index = grandparentTask.subtasks.findIndex(t => t.id === currentParentTask.id); - - grandparentTask.subtasks = grandparentTask.subtasks.filter(t => t.id !== currentParentTask.id); - updateTaskAndAncestors(grandparentTask); - - taskPath.pop(); // Remove the deleted task from the path - currentTask = grandparentTask; - - if (grandparentTask.subtasks.length === 0 && taskPath.length > 1) { - // If we've just deleted the last subtask, navigate up another level - navigateToParentTask(); - } else { - renderCurrentView(); - if (grandparentTask.subtasks.length > 0) { - // Select the subtask before the deleted one, or the one after if at the start - const targetIndex = Math.max(0, index - 1); - selectAndFocusTask(grandparentTask.subtasks[targetIndex]); - } else { - selectAndFocusTask(grandparentTask); - } - } - } - function navigateTasks(direction) { const tasks = currentTask.subtasks; const currentElement = document.activeElement;