shake when trying to delete root or last child
Hunter
Thursday, August 8th, 2024 at 8:33 PM
241 function loadTasksFromLocalStorage() {
242 const savedTasks = localStorage.getItem('taskTree');
243 if (savedTasks) {
244 + console.log('%cloaded tasks from local storage:', "color: green;");
245 + console.log(savedTasks);
246 return deserializeTaskTree(savedTasks);
247 } else {
248 return { id: 'root', text: 'todo', state: 0, subtasks: [{ id: Date.now(), text: '', state: 0, subtasks: [] }], selectedSubtaskId: null };
350 } else {
351 deleteSubtask(task);
352 }
353 + } else {
354 + // Attempting to delete root task
355 + applyShakeAnimation(task.id);
356 }
357 } else if (taskInput.value !== '') {
358 keyHandler.backspace.canDelete = false;
469
470 function toggleTaskState(task) {
471 if (task.state === 1) {
- // if all direct children are checked, disallow unchecking
472 if (task.subtasks.length === 0 || !task.subtasks.every(t => t.state === 1)) {
473 task.state = 0;
474 updateSubtasksState(task, 0);
483 scheduleSave();
484 } else {
485 // 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
- }
486 + applyShakeAnimation(task.id);
487 }
488 } else {
489 task.state = 1;
500 }
501 }
502
503 + function applyShakeAnimation(taskId) {
504 + const checkbox = document.querySelector(`.task-container[data-id="${taskId}"] .checkbox-label`);
505 + if (checkbox) {
506 + checkbox.classList.add('shake');
507 + setTimeout(() => {
508 + checkbox.classList.remove('shake');
509 + }, 250); // Remove class after animation completes
510 + }
511 + }
512 +
513 function recalculateTaskState(task) {
514 if (task.subtasks.length === 0) {
515 return task.state; // If no subtasks, keep current state
562 const index = parentTask.subtasks.findIndex(t => t.id === subtask.id);
563
564 if (parentTask.id === 'root' && parentTask.subtasks.length === 1) {
565 + // Disallow deletion of the root task's sole remaining child
566 + applyShakeAnimation(subtask.id);
567 return;
568 }
569
587 scheduleSave();
588 }
589
590 + function deleteCurrentParentTask() {
591 + if (taskPath.length <= 1) return; // Don't delete root task
592 +
593 + const currentParentTask = taskPath[taskPath.length - 1];
594 + const grandparentTask = taskPath[taskPath.length - 2];
595 +
596 + // Check if we're trying to delete the sole child of the root
597 + if (grandparentTask.id === 'root' && grandparentTask.subtasks.length === 1) {
598 + // Don't allow deletion of the sole child of root
599 + applyShakeAnimation(currentParentTask.id);
600 + return;
601 + }
602 +
603 + const index = grandparentTask.subtasks.findIndex(t => t.id === currentParentTask.id);
604 +
605 + grandparentTask.subtasks = grandparentTask.subtasks.filter(t => t.id !== currentParentTask.id);
606 + updateTaskAndAncestors(grandparentTask);
607 +
608 + taskPath.pop(); // Remove the deleted task from the path
609 + currentTask = grandparentTask;
610 +
611 + if (grandparentTask.subtasks.length === 0 && taskPath.length > 1) {
612 + // If we've just deleted the last subtask, navigate up another level
613 + navigateToParentTask();
614 + } else {
615 + renderCurrentView();
616 + if (grandparentTask.subtasks.length > 0) {
617 + // Select the subtask before the deleted one, or the one after if at the start
618 + const targetIndex = Math.max(0, index - 1);
619 + selectAndFocusTask(grandparentTask.subtasks[targetIndex]);
620 + } else {
621 + selectAndFocusTask(grandparentTask);
622 + }
623 + }
624 + }
625 +
626 function findParentTask(task) {
627 for (let i = taskPath.length - 1; i >= 0; i--) {
628 const potentialParent = taskPath[i];
717 taskInput.setSelectionRange(0, 0);
718 }
719
- 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);
- }
- }
- }
-
720 function navigateTasks(direction) {
721 const tasks = currentTask.subtasks;
722 const currentElement = document.activeElement;