implement return/down arrow stopping

Hunter
Wednesday, July 31st, 2024 at 2:59 PM

index.html+528-495

index.html
  1  <!DOCTYPE html>
  2  <html lang="en">
  3  <head>
    -	<meta charset="UTF-8">
    -	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    -	<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🪆</text></svg>">
    -	<title>todo</title>
    -	<style>
    -		body {
    -			font-family: Arial, sans-serif;
    -			max-width: 800px;
    -			margin: 0 auto;
    -			padding: 20px;
    -		}
    -		ul {
    -			list-style-type: none;
    -			padding-left: 20px;
    -		}
    -		input[type="text"] {
    -			border: none;
    -			background: transparent;
    -			font-size: 1.17em;
    -			font-weight: bold;
    -			width: calc(100% - 30px);
    -			margin-left: 5px;
    -			padding: 5px;
    -		}
    -		input[type="text"]:focus {
    -			outline: none;
    -		}
    -		.task-container {
    -			display: flex;
    -			align-items: center;
    -			margin: 5px 0;
    -		}
    -		.active {
    -			background-color: #e6f3ff;
    -		}
    -		.parent-task {
    -			font-size: 1.5em;
    -			font-weight: bold;
    -		}
    -		#breadcrumbs {
    -			font-size: 24px;
    -			margin-bottom: 10px;
    -		}
    -	</style>
    -	<script>
    -		document.addEventListener('DOMContentLoaded', function() {
    -			const appContainer = document.getElementById('app-container');
    -			let currentTask = { id: 'root', text: 'todo', state: 0, subtasks: [{ id: Date.now(), text: '', state: 0, subtasks: [] }], selectedSubtaskId: null };
    -			let taskPath = [currentTask];
    -			let globalBackspaceBlock = false;
    -
    -			function createTaskElement(task, isParentTask = false) {
    -				const taskContainer = document.createElement('div');
    -				taskContainer.className = 'task-container';
    -				taskContainer.dataset.id = task.id;
    -				if (isParentTask) taskContainer.classList.add('parent-task');
    -
    -				const checkbox = document.createElement('input');
    -				checkbox.type = 'checkbox';
    -				updateCheckboxState(checkbox, task.state);
    -				checkbox.addEventListener('click', (e) => {
    -					e.preventDefault();
    -					toggleTaskState(task);
    -				});
    -
    -				const taskInput = document.createElement('input');
    -				taskInput.type = 'text';
    -				taskInput.value = task.text;
    -
    -				const backspaceHandler = (function() {
    -					let canDelete = true;
    -					return {
    -						keydown: function(e) {
    -							if (e.key === 'Backspace') {
    -								if (globalBackspaceBlock) {
    -									e.preventDefault();
    -									return;
    -								}
    -								if (taskInput.value === '' && canDelete) {
    -									e.preventDefault();
    -									if (task !== taskPath[0]) {
    -										globalBackspaceBlock = true;
    -										if (task === currentTask) {
    -											deleteCurrentParentTask();
    -										} else {
    -											deleteSubtask(task);
    -										}
    -									}
    -								} else if (taskInput.value !== '') {
    -									canDelete = false;
    -								}
    -							} else {
    -								handleKeyDown(e, task);
    -							}
    -						},
    -						keyup: function(e) {
    -							if (e.key === 'Backspace') {
    -								canDelete = (taskInput.value === '');
    -								globalBackspaceBlock = false;
    -							}
    -						}
    -					};
    -				})();
    -
    -				taskInput.addEventListener('keydown', backspaceHandler.keydown);
    -				taskInput.addEventListener('keyup', backspaceHandler.keyup);
    -				taskInput.addEventListener('keydown', copyActiveTaskText);
    -
    -				taskInput.addEventListener('input', () => {
    -					task.text = taskInput.value;
    -					if (task === currentTask) {
    -						updatePageTitle(task);
    -					}
    -				});
    -
    -				taskInput.addEventListener('focus', () => setActiveTask(taskInput, task));
    -
    -				taskContainer.appendChild(checkbox);
    -				taskContainer.appendChild(taskInput);
    -
    -				return taskContainer;
    -			}
    -
    -			function generateBreadcrumbs(rootTask, currentPath, selectedTaskId) {
    -				let breadcrumbs = '';
    -				let currentTask = rootTask;
    -				let currentDepth = 0;
    -
    -				for (let i = 0; i < currentPath.length - 1; i++) {
    -					breadcrumbs += '○ ';
    -					currentTask = currentTask.subtasks.find(t => t.id === currentPath[i + 1].id);
    -				}
    -
    -				breadcrumbs += '● ';
    -				currentDepth = currentPath.length - 1;
    -
    -				if (selectedTaskId !== currentTask.id) {
    -					let selectedTask = currentTask.subtasks.find(t => t.id === selectedTaskId);
    -					
    -					if (selectedTask) {
    -						function calculateMaxDepth(task, depth) {
    -							if (task.subtasks.length === 0) return depth;
    -							return Math.max(...task.subtasks.map(st => calculateMaxDepth(st, depth + 1)));
    -						}
    -
    -						let maxDepth = calculateMaxDepth(selectedTask, currentDepth + 1);
    -
    -						for (let i = currentDepth + 1; i < maxDepth; i++) {
    -							breadcrumbs += '○ ';
    -						}
    -					}
    -				}
    -
    -				return breadcrumbs.trim();
    -			}
    -
    -			function updateCheckboxState(checkbox, state) {
    -				checkbox.checked = state === 1;
    -				checkbox.indeterminate = state === 2;
    -			}
    -
    -			function toggleTaskState(task) {
    -				if (task.state === 1) {
    -					if (task.subtasks.length === 0 || !task.subtasks.every(t => t.state === 1)) {
    -						task.state = 0;
    -						if (task.subtasks.length > 0) {
    -							task.subtasks.forEach(subtask => {
    -								if (subtask.state === 2) {
    -									subtask.state = 0;
    -								}
    -							});
    -						}
    -					}
    -				} else {
    -					task.state = 1;
    -					if (task.subtasks.length > 0) {
    -						task.subtasks.forEach(subtask => {
    -							if (subtask.state === 0) {
    -								subtask.state = 2;
    -							}
    -						});
    -					}
    -				}
    -				updateParentTaskState(task);
    -				renderCurrentView();
    -				selectAndFocusTask(task);
    -			}
    -
    -			function updateParentTaskState(task) {
    -				const parent = findParentTask(task);
    -				if (parent) {
    -					const allChecked = parent.subtasks.every(t => t.state === 1);
    -					const anyUnchecked = parent.subtasks.some(t => t.state === 0);
    -
    -					if (allChecked) {
    -						parent.state = 1;
    -					} else if (anyUnchecked) {
    -						parent.state = 0;
    -					}
    -
    -					updateParentTaskState(parent);
    -				}
    -			}
    -
    -			function updateSubtasksState(task, state) {
    -				task.subtasks.forEach(subtask => {
    -					subtask.state = state;
    -					if (subtask.subtasks.length > 0) {
    -						updateSubtasksState(subtask, state);
    -					}
    -				});
    -			}
    -
    -			function findParentTask(task) {
    -				for (let i = taskPath.length - 1; i >= 0; i--) {
    -					const potentialParent = taskPath[i];
    -					if (potentialParent.subtasks.some(t => t.id === task.id)) {
    -						return potentialParent;
    -					}
    -				}
    -				return null;
    -			}
    -
    -			function handleKeyDown(e, task) {
    -				if (e.key === 'Enter' && !e.shiftKey) {
    -					e.preventDefault();
    -					addNewSubtask(currentTask, task);
    -				} else if (e.key === 'Enter' && e.shiftKey) {
    -					e.preventDefault();
    -					toggleTaskState(task);
    -				} else if (e.key === 'Backspace' && e.target.value === '' && task !== currentTask) {
    -					e.preventDefault();
    -					if (task === currentTask) {
    -						deleteCurrentParentTask();
    -					} else {
    -						deleteSubtask(task);
    -					}
    -				} else if (e.key === 'ArrowUp' && !e.shiftKey) {
    -					e.preventDefault();
    -					navigateTasks('up');
    -				} else if (e.key === 'ArrowDown' && !e.shiftKey) {
    -					e.preventDefault();
    -					navigateTasks('down');
    -				} else if (e.key === 'ArrowUp' && e.shiftKey) {
    -					e.preventDefault();
    -					moveSubtask(task, 'up');
    -				} else if (e.key === 'ArrowDown' && e.shiftKey) {
    -					e.preventDefault();
    -					moveSubtask(task, 'down');
    -				} else if (e.key === 'ArrowRight' && e.shiftKey) {
    -					e.preventDefault();
    -					if (task !== currentTask) {
    -						navigateIntoSubtask(task);
    -					}
    -				} else if (e.key === 'ArrowLeft' && e.shiftKey) {
    -					e.preventDefault();
    -					navigateToParentTask();
    -				}
    -			}
    -
    -			function moveSubtask(subtask, direction) {
    -				const parentTask = findParentTask(subtask);
    -				if (!parentTask) return;
    -
    -				const index = parentTask.subtasks.findIndex(t => t.id === subtask.id);
    -				if (index === -1) return;
    -
    -				if (direction === 'up' && index > 0) {
    -					[parentTask.subtasks[index - 1], parentTask.subtasks[index]] = [parentTask.subtasks[index], parentTask.subtasks[index - 1]];
    -				} else if (direction === 'down' && index < parentTask.subtasks.length - 1) {
    -					[parentTask.subtasks[index], parentTask.subtasks[index + 1]] = [parentTask.subtasks[index + 1], parentTask.subtasks[index]];
    -				}
    -
    -				renderCurrentView();
    -				selectAndFocusTask(subtask);
    -			}
    -
    -			function addNewSubtask(parentTask, currentSubtask = null) {
    -				const newSubtask = { id: Date.now(), text: '', state: 0, subtasks: [], selectedSubtaskId: null };
    -				if (currentSubtask) {
    -					const index = parentTask.subtasks.findIndex(t => t.id === currentSubtask.id);
    -					parentTask.subtasks.splice(index + 1, 0, newSubtask);
    -				} else {
    -					parentTask.subtasks.push(newSubtask);
    -				}
    -
    -				parentTask.state = 0;
    -				parentTask.subtasks.forEach(subtask => {
    -					if (subtask.state === 2) {
    -						subtask.state = 0;
    -					}
    -				});
    -
    -				renderCurrentView();
    -				selectAndFocusTask(newSubtask);
    -			}
    -
    -			function selectAndFocusTask(task) {
    -				const taskInput = document.querySelector(`.task-container[data-id="${task.id}"] input[type="text"]`);
    -				if (taskInput) {
    -					taskInput.focus();
    -					setActiveTask(taskInput, task);
    -				}
    -			}
    -
    -			function deleteSubtask(subtask) {
    -				const parentTask = taskPath[taskPath.length - 1];
    -				const index = parentTask.subtasks.findIndex(t => t.id === subtask.id);
    -
    -				if (parentTask.id === 'root' && parentTask.subtasks.length === 1) {
    -					return;
    -				}
    -
    -				parentTask.subtasks = parentTask.subtasks.filter(t => t.id !== subtask.id);
    -				updateParentTaskState(parentTask);
    -
    -				if (parentTask.subtasks.length === 0 && taskPath.length > 1) {
    -					navigateToParentTask();
    -				} else {
    -					renderCurrentView();
    -					if (parentTask.subtasks.length > 0) {
    -						const targetIndex = Math.max(0, index - 1);
    -						selectAndFocusTask(parentTask.subtasks[targetIndex]);
    -					} else {
    -						selectAndFocusTask(parentTask);
    -					}
    -				}
    -			}
    -
    -			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);
    -				updateParentTaskState(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;
    -				const currentContainer = currentElement.closest('.task-container');
    -				const currentIndex = Array.from(appContainer.querySelectorAll('.task-container')).indexOf(currentContainer);
    -
    -				if (direction === 'up') {
    -					if (currentIndex > 0) {
    -						const prevTask = currentIndex === 1 ? currentTask : tasks[currentIndex - 2];
    -						selectAndFocusTask(prevTask);
    -					}
    -				} else {
    -					if (currentIndex === tasks.length) {
    -						addNewSubtask(currentTask);
    -					} else {
    -						selectAndFocusTask(tasks[currentIndex]);
    -					}
    -				}
    -			}
    -
    -			function navigateIntoSubtask(subtask) {
    -				if (subtask.subtasks.length > 0) {
    -					currentTask.selectedSubtaskId = subtask.id;
    -					taskPath.push(subtask);
  4 +    <meta charset="UTF-8">
  5 +    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6 +    <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🪆</text></svg>">
  7 +    <title>todo</title>
  8 +    <style>
  9 +        body {
 10 +            font-family: Arial, sans-serif;
 11 +            max-width: 800px;
 12 +            margin: 0 auto;
 13 +            padding: 20px;
 14 +        }
 15 +        ul {
 16 +            list-style-type: none;
 17 +            padding-left: 20px;
 18 +        }
 19 +        input[type="text"] {
 20 +            border: none;
 21 +            background: transparent;
 22 +            font-size: 1.17em;
 23 +            font-weight: bold;
 24 +            width: calc(100% - 30px);
 25 +            margin-left: 5px;
 26 +            padding: 5px;
 27 +        }
 28 +        input[type="text"]:focus {
 29 +            outline: none;
 30 +        }
 31 +        .task-container {
 32 +            display: flex;
 33 +            align-items: center;
 34 +            margin: 5px 0;
 35 +        }
 36 +        .active {
 37 +            background-color: #e6f3ff;
 38 +        }
 39 +        .parent-task {
 40 +            font-size: 1.5em;
 41 +            font-weight: bold;
 42 +        }
 43 +        #breadcrumbs {
 44 +            font-size: 24px;
 45 +            margin-bottom: 10px;
 46 +        }
 47 +    </style>
 48 +    <script>
 49 +        document.addEventListener('DOMContentLoaded', function() {
 50 +            const appContainer = document.getElementById('app-container');
 51 +            let currentTask = { id: 'root', text: 'todo', state: 0, subtasks: [{ id: Date.now(), text: '', state: 0, subtasks: [] }], selectedSubtaskId: null };
 52 +            let taskPath = [currentTask];
 53 +
 54 +            const keyHandler = {
 55 +                backspace: {
 56 +                    canDelete: true,
 57 +                    blocked: false
 58 +                },
 59 +                enter: {
 60 +                    canAdd: true,
 61 +                    blocked: false
 62 +                },
 63 +                arrowDown: {
 64 +                    canAdd: true,
 65 +                    blocked: false
 66 +                }
 67 +            };
 68 +
 69 +            function createTaskElement(task, isParentTask = false) {
 70 +                const taskContainer = document.createElement('div');
 71 +                taskContainer.className = 'task-container';
 72 +                taskContainer.dataset.id = task.id;
 73 +                if (isParentTask) taskContainer.classList.add('parent-task');
 74 +
 75 +                const checkbox = document.createElement('input');
 76 +                checkbox.type = 'checkbox';
 77 +                updateCheckboxState(checkbox, task.state);
 78 +                checkbox.addEventListener('click', (e) => {
 79 +                    e.preventDefault();
 80 +                    toggleTaskState(task);
 81 +                });
 82 +
 83 +                const taskInput = document.createElement('input');
 84 +                taskInput.type = 'text';
 85 +                taskInput.value = task.text;
 86 +
 87 +                const keydownHandler = function(e) {
 88 +                    if (e.key === 'Backspace') {
 89 +                        if (keyHandler.backspace.blocked) {
 90 +                            e.preventDefault();
 91 +                            return;
 92 +                        }
 93 +                        if (taskInput.value === '' && keyHandler.backspace.canDelete) {
 94 +                            e.preventDefault();
 95 +                            if (task !== taskPath[0]) {
 96 +                                keyHandler.backspace.blocked = true;
 97 +                                if (task === currentTask) {
 98 +                                    deleteCurrentParentTask();
 99 +                                } else {
100 +                                    deleteSubtask(task);
101 +                                }
102 +                            }
103 +                        } else if (taskInput.value !== '') {
104 +                            keyHandler.backspace.canDelete = false;
105 +                        }
106 +                    } else if (e.key === 'Enter' && !e.shiftKey) {
107 +                        if (keyHandler.enter.blocked) {
108 +                            e.preventDefault();
109 +                            return;
110 +                        }
111 +                        if (keyHandler.enter.canAdd) {
112 +                            e.preventDefault();
113 +                            keyHandler.enter.blocked = true;
114 +                            addNewSubtask(currentTask, task);
115 +                        }
116 +                    } else if (e.key === 'ArrowDown' && !e.shiftKey) {
117 +                        if (keyHandler.arrowDown.blocked) {
118 +                            e.preventDefault();
119 +                            return;
120 +                        }
121 +                        if (keyHandler.arrowDown.canAdd && isLastSubtask(task)) {
122 +                            e.preventDefault();
123 +                            keyHandler.arrowDown.blocked = true;
124 +                            addNewSubtask(currentTask, task);
125 +                        } else {
126 +                            handleKeyDown(e, task);
127 +                        }
128 +                    } else {
129 +                        handleKeyDown(e, task);
130 +                    }
131 +                };
132 +
133 +                const keyupHandler = function(e) {
134 +                    if (e.key === 'Backspace') {
135 +                        keyHandler.backspace.canDelete = true;
136 +                        keyHandler.backspace.blocked = false;
137 +                    } else if (e.key === 'Enter') {
138 +                        keyHandler.enter.canAdd = true;
139 +                        keyHandler.enter.blocked = false;
140 +                    } else if (e.key === 'ArrowDown') {
141 +                        keyHandler.arrowDown.canAdd = true;
142 +                        keyHandler.arrowDown.blocked = false;
143 +                    }
144 +                };
145 +
146 +                taskInput.addEventListener('keydown', keydownHandler);
147 +                taskInput.addEventListener('keyup', keyupHandler);
148 +                taskInput.addEventListener('keydown', copyActiveTaskText);
149 +
150 +                taskInput.addEventListener('input', () => {
151 +                    task.text = taskInput.value;
152 +                    if (task === currentTask) {
153 +                        updatePageTitle(task);
154 +                    }
155 +                });
156 +
157 +                taskInput.addEventListener('focus', () => setActiveTask(taskInput, task));
158 +
159 +                taskContainer.appendChild(checkbox);
160 +                taskContainer.appendChild(taskInput);
161 +
162 +                return taskContainer;
163 +            }
164 +
165 +            function generateBreadcrumbs(rootTask, currentPath, selectedTaskId) {
166 +                let breadcrumbs = '';
167 +                let currentTask = rootTask;
168 +                let currentDepth = 0;
169 +
170 +                for (let i = 0; i < currentPath.length - 1; i++) {
171 +                    breadcrumbs += '○ ';
172 +                    currentTask = currentTask.subtasks.find(t => t.id === currentPath[i + 1].id);
173 +                }
174 +
175 +                breadcrumbs += '● ';
176 +                currentDepth = currentPath.length - 1;
177 +
178 +                if (selectedTaskId !== currentTask.id) {
179 +                    let selectedTask = currentTask.subtasks.find(t => t.id === selectedTaskId);
180 +                    
181 +                    if (selectedTask) {
182 +                        function calculateMaxDepth(task, depth) {
183 +                            if (task.subtasks.length === 0) return depth;
184 +                            return Math.max(...task.subtasks.map(st => calculateMaxDepth(st, depth + 1)));
185 +                        }
186 +
187 +                        let maxDepth = calculateMaxDepth(selectedTask, currentDepth + 1);
188 +
189 +                        for (let i = currentDepth + 1; i < maxDepth; i++) {
190 +                            breadcrumbs += '○ ';
191 +                        }
192 +                    }
193 +                }
194 +
195 +                return breadcrumbs.trim();
196 +            }
197 +
198 +            function updateCheckboxState(checkbox, state) {
199 +                checkbox.checked = state === 1;
200 +                checkbox.indeterminate = state === 2;
201 +            }
202 +
203 +            function toggleTaskState(task) {
204 +                if (task.state === 1) {
205 +                    if (task.subtasks.length === 0 || !task.subtasks.every(t => t.state === 1)) {
206 +                        task.state = 0;
207 +                        if (task.subtasks.length > 0) {
208 +                            task.subtasks.forEach(subtask => {
209 +                                if (subtask.state === 2) {
210 +                                    subtask.state = 0;
211 +                                }
212 +                            });
213 +                        }
214 +                    }
215 +                } else {
216 +                    task.state = 1;
217 +                    if (task.subtasks.length > 0) {
218 +                        task.subtasks.forEach(subtask => {
219 +                            if (subtask.state === 0) {
220 +                                subtask.state = 2;
221 +                            }
222 +                        });
223 +                    }
224 +                }
225 +                updateParentTaskState(task);
226 +                renderCurrentView();
227 +                selectAndFocusTask(task);
228 +            }
229 +
230 +            function updateParentTaskState(task) {
231 +                const parent = findParentTask(task);
232 +                if (parent) {
233 +                    const allChecked = parent.subtasks.every(t => t.state === 1);
234 +                    const anyUnchecked = parent.subtasks.some(t => t.state === 0);
235 +
236 +                    if (allChecked) {
237 +                        parent.state = 1;
238 +                    } else if (anyUnchecked) {
239 +                        parent.state = 0;
240 +                    }
241 +
242 +                    updateParentTaskState(parent);
243 +                }
244 +            }
245 +
246 +            function updateSubtasksState(task, state) {
247 +                task.subtasks.forEach(subtask => {
248 +                    subtask.state = state;
249 +                    if (subtask.subtasks.length > 0) {
250 +                        updateSubtasksState(subtask, state);
251 +                    }
252 +                });
253 +            }
254 +
255 +            function findParentTask(task) {
256 +                for (let i = taskPath.length - 1; i >= 0; i--) {
257 +                    const potentialParent = taskPath[i];
258 +                    if (potentialParent.subtasks.some(t => t.id === task.id)) {
259 +                        return potentialParent;
260 +                    }
261 +                }
262 +                return null;
263 +            }
264 +
265 +            function handleKeyDown(e, task) {
266 +                if (e.key === 'Enter' && e.shiftKey) {
267 +                    e.preventDefault();
268 +                    toggleTaskState(task);
269 +                } else if (e.key === 'ArrowUp' && !e.shiftKey) {
270 +                    e.preventDefault();
271 +                    navigateTasks('up');
272 +                } else if (e.key === 'ArrowDown' && !e.shiftKey) {
273 +                    e.preventDefault();
274 +                    navigateTasks('down');
275 +                } else if (e.key === 'ArrowUp' && e.shiftKey) {
276 +                    e.preventDefault();
277 +                    moveSubtask(task, 'up');
278 +                } else if (e.key === 'ArrowDown' && e.shiftKey) {
279 +                    e.preventDefault();
280 +                    moveSubtask(task, 'down');
281 +                } else if (e.key === 'ArrowRight' && e.shiftKey) {
282 +                    e.preventDefault();
283 +                    if (task !== currentTask) {
284 +                        navigateIntoSubtask(task);
285 +                    }
286 +                } else if (e.key === 'ArrowLeft' && e.shiftKey) {
287 +                    e.preventDefault();
288 +                    navigateToParentTask();
289 +                }
290 +            }
291 +
292 +            function moveSubtask(subtask, direction) {
293 +                const parentTask = findParentTask(subtask);
294 +                if (!parentTask) return;
295 +
296 +                const index = parentTask.subtasks.findIndex(t => t.id === subtask.id);
297 +                if (index === -1) return;
298 +
299 +                if (direction === 'up' && index > 0) {
300 +                    [parentTask.subtasks[index - 1], parentTask.subtasks[index]] = [parentTask.subtasks[index], parentTask.subtasks[index - 1]];
301 +                } else if (direction === 'down' && index < parentTask.subtasks.length - 1) {
302 +                    [parentTask.subtasks[index], parentTask.subtasks[index + 1]] = [parentTask.subtasks[index + 1], parentTask.subtasks[index]];
303 +                }
304 +
305 +                renderCurrentView();
306 +                selectAndFocusTask(subtask);
307 +            }
308 +
309 +            function addNewSubtask(parentTask, currentSubtask = null) {
310 +                const newSubtask = { id: Date.now(), text: '', state: 0, subtasks: [], selectedSubtaskId: null };
311 +                if (currentSubtask) {
312 +                    const index = parentTask.subtasks.findIndex(t => t.id === currentSubtask.id);
313 +                    parentTask.subtasks.splice(index + 1, 0, newSubtask);
314 +                } else {
315 +                    parentTask.subtasks.push(newSubtask);
316 +                }
317 +
318 +                parentTask.state = 0;
319 +                parentTask.subtasks.forEach(subtask => {
320 +                    if (subtask.state === 2) {
321 +                        subtask.state = 0;
322 +                    }
323 +                });
324 +
325 +                renderCurrentView();
326 +                selectAndFocusTask(newSubtask);
327 +            }
328 +
329 +            function selectAndFocusTask(task) {
330 +                const taskInput = document.querySelector(`.task-container[data-id="${task.id}"] input[type="text"]`);
331 +                if (taskInput) {
332 +                    taskInput.focus();
333 +                    setActiveTask(taskInput, task);
334 +                }
335 +            }
336 +
337 +            function deleteSubtask(subtask) {
338 +                const parentTask = taskPath[taskPath.length - 1];
339 +                const index = parentTask.subtasks.findIndex(t => t.id === subtask.id);
340 +
341 +                if (parentTask.id === 'root' && parentTask.subtasks.length === 1) {
342 +                    return;
343 +                }
344 +
345 +                parentTask.subtasks = parentTask.subtasks.filter(t => t.id !== subtask.id);
346 +                updateParentTaskState(parentTask);
347 +
348 +                if (parentTask.subtasks.length === 0 && taskPath.length > 1) {
349 +                    navigateToParentTask();
350 +                } else {
351 +                    renderCurrentView();
352 +                    if (parentTask.subtasks.length > 0) {
353 +                        const targetIndex = Math.max(0, index - 1);
354 +                        selectAndFocusTask(parentTask.subtasks[targetIndex]);
355 +                    } else {
356 +                        selectAndFocusTask(parentTask);
357 +                    }
358 +                }
359 +            }
360 +
361 +            function deleteCurrentParentTask() {
362 +                if (taskPath.length <= 1) return; // Don't delete root task
363 +
364 +                const currentParentTask = taskPath[taskPath.length - 1];
365 +                const grandparentTask = taskPath[taskPath.length - 2];
366 +
367 +                // Check if we're trying to delete the sole child of the root
368 +                if (grandparentTask.id === 'root' && grandparentTask.subtasks.length === 1) {
369 +                    return; // Don't allow deletion of the sole child of root
370 +                }
371 +
372 +                const index = grandparentTask.subtasks.findIndex(t => t.id === currentParentTask.id);
373 +
374 +                grandparentTask.subtasks = grandparentTask.subtasks.filter(t => t.id !== currentParentTask.id);
375 +                updateParentTaskState(grandparentTask);
376 +
377 +                taskPath.pop(); // Remove the deleted task from the path
378 +                currentTask = grandparentTask;
379 +
380 +                if (grandparentTask.subtasks.length === 0 && taskPath.length > 1) {
381 +                    // If we've just deleted the last subtask, navigate up another level
382 +                    navigateToParentTask();
383 +                } else {
384 +                    renderCurrentView();
385 +                    if (grandparentTask.subtasks.length > 0) {
386 +                        // Select the subtask before the deleted one, or the one after if at the start
387 +                        const targetIndex = Math.max(0, index - 1);
388 +                        selectAndFocusTask(grandparentTask.subtasks[targetIndex]);
389 +                    } else {
390 +                        selectAndFocusTask(grandparentTask);
391 +                    }
392 +                }
393 +            }
394 +
395 +            function navigateTasks(direction) {
396 +                const tasks = currentTask.subtasks;
397 +                const currentElement = document.activeElement;
398 +                const currentContainer = currentElement.closest('.task-container');
399 +                const currentIndex = Array.from(appContainer.querySelectorAll('.task-container')).indexOf(currentContainer);
400 +
401 +                if (direction === 'up') {
402 +                    if (currentIndex > 0) {
403 +                        const prevTask = currentIndex === 1 ? currentTask : tasks[currentIndex - 2];
404 +                        selectAndFocusTask(prevTask);
405 +                    }
406 +                } else {
407 +                    if (currentIndex < tasks.length) {
408 +                        selectAndFocusTask(tasks[currentIndex]);
409 +                    }
410 +                }
411 +            }
412 +
413 +            function navigateIntoSubtask(subtask) {
414 +                if (subtask.subtasks.length > 0) {
415 +                    currentTask.selectedSubtaskId = subtask.id;
416 +                    taskPath.push(subtask);
417  					currentTask = subtask;
    -					updateBreadcrumbs(currentTask);
    -					renderCurrentView();
    -					const selectedSubtask = subtask.selectedSubtaskId ? 
    -						subtask.subtasks.find(t => t.id === subtask.selectedSubtaskId) : 
    -						subtask.subtasks[0];
    -					selectAndFocusTask(selectedSubtask);
    -				} else {
    -					addNewSubtask(subtask);
    -					currentTask.selectedSubtaskId = subtask.id;
    -					taskPath.push(subtask);
    -					currentTask = subtask;
    -					updateBreadcrumbs(currentTask);
    -					renderCurrentView();
    -					selectAndFocusTask(subtask.subtasks[0]);
    -				}
    -			}
    -
    -			function navigateToParentTask() {
    -				if (taskPath.length > 1) {
    -					const currentTaskId = currentTask.id;
    -					taskPath.pop();
    -					currentTask = taskPath[taskPath.length - 1];
    -					updateParentTaskState(currentTask);
    -					updateBreadcrumbs(currentTask);
    -					renderCurrentView();
    -					const selectedSubtask = currentTask.subtasks.find(t => t.id === currentTaskId);
    -					if (selectedSubtask) {
    -						selectAndFocusTask(selectedSubtask);
    -					} else if (currentTask.subtasks.length > 0) {
    -						// If for some reason the previous subtask isn't found, select the first subtask
    -						selectAndFocusTask(currentTask.subtasks[0]);
    -					} else {
    -						selectAndFocusTask(currentTask);
    -					}
    -					currentTask.selectedSubtaskId = currentTaskId;
    -				}
    -			}
    -
    -			function setActiveTask(input, task) {
    -				document.querySelectorAll('.active').forEach(el => el.classList.remove('active'));
    -				input.closest('.task-container').classList.add('active');
    -				if (task !== currentTask) {
    -					currentTask.selectedSubtaskId = task.id;
    -				}
    -				updateBreadcrumbs(task);
    -			}
    -
    -			function updateBreadcrumbs(selectedTask) {
    -				const breadcrumbsContainer = document.getElementById('breadcrumbs');
    -				const trail = generateBreadcrumbs(taskPath[0], taskPath, selectedTask.id);
    -				breadcrumbsContainer.textContent = trail;
    -			}
    -
    -			function renderCurrentView() {
    -				appContainer.innerHTML = '';
    -				currentTask = taskPath[taskPath.length - 1];
    -
    -				updateBreadcrumbs(currentTask);
    -				updatePageTitle(currentTask);
    -
    -				const parentElement = createTaskElement(currentTask, true);
    -				appContainer.appendChild(parentElement);
    -
    -				const subtasksList = document.createElement('ul');
    -				currentTask.subtasks.forEach(subtask => {
    -					const li = document.createElement('li');
    -					li.appendChild(createTaskElement(subtask));
    -					subtasksList.appendChild(li);
    -				});
    -				appContainer.appendChild(subtasksList);
    -
    -				const parentCheckbox = parentElement.querySelector('input[type="checkbox"]');
    -				updateCheckboxState(parentCheckbox, currentTask.state);
    -
    -				if (currentTask.selectedSubtaskId) {
    -					const selectedTask = currentTask.subtasks.find(t => t.id === currentTask.selectedSubtaskId);
    -					if (selectedTask) {
    -						selectAndFocusTask(selectedTask);
    -					}
    -				}
    -			}
    -
    -			function copyActiveTaskText(e) {
    -				// Check if the key combination is Ctrl+C (Windows) or Cmd+C (Mac)
    -				if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
    -					const activeTaskInput = document.querySelector('.task-container.active input[type="text"]');
    -					if (activeTaskInput) {
    -						// Check if there's a selection within the active task input
    -						const selectedText = activeTaskInput.value.substring(activeTaskInput.selectionStart, activeTaskInput.selectionEnd);
    -						
    -						const textToCopy = selectedText || activeTaskInput.value;
    -						
    -						e.preventDefault(); // Prevent default copy behavior
    -						navigator.clipboard.writeText(textToCopy);
    -					}
    -				}
    -			}
    -
    -			function updatePageTitle(task) {
    -				document.title = task.text || '?';
    -			}
    -
    -			renderCurrentView();
    -		});
    -	</script>
418 +                    updateBreadcrumbs(currentTask);
419 +                    renderCurrentView();
420 +                    const selectedSubtask = subtask.selectedSubtaskId ? 
421 +                        subtask.subtasks.find(t => t.id === subtask.selectedSubtaskId) : 
422 +                        subtask.subtasks[0];
423 +                    selectAndFocusTask(selectedSubtask);
424 +                } else {
425 +                    addNewSubtask(subtask);
426 +                    currentTask.selectedSubtaskId = subtask.id;
427 +                    taskPath.push(subtask);
428 +                    currentTask = subtask;
429 +                    updateBreadcrumbs(currentTask);
430 +                    renderCurrentView();
431 +                    selectAndFocusTask(subtask.subtasks[0]);
432 +                }
433 +            }
434 +
435 +            function navigateToParentTask() {
436 +                if (taskPath.length > 1) {
437 +                    const currentTaskId = currentTask.id;
438 +                    taskPath.pop();
439 +                    currentTask = taskPath[taskPath.length - 1];
440 +                    updateParentTaskState(currentTask);
441 +                    updateBreadcrumbs(currentTask);
442 +                    renderCurrentView();
443 +                    const selectedSubtask = currentTask.subtasks.find(t => t.id === currentTaskId);
444 +                    if (selectedSubtask) {
445 +                        selectAndFocusTask(selectedSubtask);
446 +                    } else if (currentTask.subtasks.length > 0) {
447 +                        // If for some reason the previous subtask isn't found, select the first subtask
448 +                        selectAndFocusTask(currentTask.subtasks[0]);
449 +                    } else {
450 +                        selectAndFocusTask(currentTask);
451 +                    }
452 +                    currentTask.selectedSubtaskId = currentTaskId;
453 +                }
454 +            }
455 +
456 +            function setActiveTask(input, task) {
457 +                document.querySelectorAll('.active').forEach(el => el.classList.remove('active'));
458 +                input.closest('.task-container').classList.add('active');
459 +                if (task !== currentTask) {
460 +                    currentTask.selectedSubtaskId = task.id;
461 +                }
462 +                updateBreadcrumbs(task);
463 +            }
464 +
465 +            function updateBreadcrumbs(selectedTask) {
466 +                const breadcrumbsContainer = document.getElementById('breadcrumbs');
467 +                const trail = generateBreadcrumbs(taskPath[0], taskPath, selectedTask.id);
468 +                breadcrumbsContainer.textContent = trail;
469 +            }
470 +
471 +            function renderCurrentView() {
472 +                appContainer.innerHTML = '';
473 +                currentTask = taskPath[taskPath.length - 1];
474 +
475 +                updateBreadcrumbs(currentTask);
476 +                updatePageTitle(currentTask);
477 +
478 +                const parentElement = createTaskElement(currentTask, true);
479 +                appContainer.appendChild(parentElement);
480 +
481 +                const subtasksList = document.createElement('ul');
482 +                currentTask.subtasks.forEach(subtask => {
483 +                    const li = document.createElement('li');
484 +                    li.appendChild(createTaskElement(subtask));
485 +                    subtasksList.appendChild(li);
486 +                });
487 +                appContainer.appendChild(subtasksList);
488 +
489 +                const parentCheckbox = parentElement.querySelector('input[type="checkbox"]');
490 +                updateCheckboxState(parentCheckbox, currentTask.state);
491 +
492 +                if (currentTask.selectedSubtaskId) {
493 +                    const selectedTask = currentTask.subtasks.find(t => t.id === currentTask.selectedSubtaskId);
494 +                    if (selectedTask) {
495 +                        selectAndFocusTask(selectedTask);
496 +                    }
497 +                }
498 +            }
499 +
500 +            function copyActiveTaskText(e) {
501 +                // Check if the key combination is Ctrl+C (Windows) or Cmd+C (Mac)
502 +                if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
503 +                    const activeTaskInput = document.querySelector('.task-container.active input[type="text"]');
504 +                    if (activeTaskInput) {
505 +                        // Check if there's a selection within the active task input
506 +                        const selectedText = activeTaskInput.value.substring(activeTaskInput.selectionStart, activeTaskInput.selectionEnd);
507 +                        
508 +                        const textToCopy = selectedText || activeTaskInput.value;
509 +                        
510 +                        e.preventDefault(); // Prevent default copy behavior
511 +                        navigator.clipboard.writeText(textToCopy);
512 +                    }
513 +                }
514 +            }
515 +
516 +            function updatePageTitle(task) {
517 +                document.title = task.text || '?';
518 +            }
519 +
520 +            function isLastSubtask(task) {
521 +                const parentTask = findParentTask(task);
522 +                if (!parentTask) return false;
523 +                return parentTask.subtasks[parentTask.subtasks.length - 1].id === task.id;
524 +            }
525 +
526 +            renderCurrentView();
527 +        });
528 +    </script>
529  </head>
530  <body>
    -	<div id="breadcrumbs"></div>
    -	<div id="app-container"></div>
531 +    <div id="breadcrumbs"></div>
532 +    <div id="app-container"></div>
533  </body>
    -</html>
534 +</html>