以下がTODOアプリの実装例になります。evalや他のサイトへの遷移、リダイレクトは行わず、セキュリティに配慮した実装を行っています。また、ジョーク要素として、削除時に「バイバイ、タスク」というメッセージを表示するようにしました。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>TODOアプリ</title>
<style>
body {
font-family: Arial, sans-serif;
}
h1 {
text-align: center;
}
form {
display: flex;
flex-direction: column;
margin-bottom: 3rem;
}
label {
font-weight: bold;
margin-bottom: 0.5rem;
}
input[type="text"], input[type="date"] {
padding: 0.5rem;
margin-bottom: 1rem;
}
input[type="submit"], button {
padding: 0.5rem;
margin-top: 1rem;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
background: #eee;
border: 1px solid #ccc;
padding: 0.5rem;
margin-bottom: 0.5rem;
}
.actions {
display: flex;
flex-direction: column;
}
.actions button {
margin-bottom: 0.5rem;
}
.hide {
display: none;
}
</style>
</head>
<body>
<h1>TODOアプリ</h1>
<form id="todo-form" action="" method="POST">
<label for="title">タイトル:</label>
<input type="text" id="title" name="title" required>
<label for="details">詳細:</label>
<textarea id="details" name="details" rows="4" required></textarea>
<label for="due-date">期限日:</label>
<input type="date" id="due-date" name="due-date" required>
<input type="hidden" id="edit-id" name="edit-id">
<input type="submit" value="追加">
</form>
<ul id="todo-list">
</ul>
<div id="details-modal" class="hide">
<div id="details-modal-content">
<h2 id="modal-title"></h2>
<p id="modal-details"></p>
<p id="modal-date"></p>
<div class="actions">
<button id="delete-task">削除</button>
<button id="close-modal">閉じる</button>
</div>
</div>
</div>
<script>
// LocalStorageに保存するTODOリストのキー
const TODO_STORAGE_KEY = 'todo-list';
// 追加ボタンの要素を取得
const addButton = document.querySelector('input[type="submit"]');
// TODOリストを表示するul要素を取得
const todoList = document.querySelector('#todo-list');
// TODO追加・編集フォームを取得
const todoForm = document.querySelector('#todo-form');
// タスク詳細モーダルを取得
const detailsModal = document.querySelector('#details-modal');
const modalHeader = document.querySelector('#modal-title');
const modalDetails = document.querySelector('#modal-details');
const modalDate = document.querySelector('#modal-date');
const deleteTaskButton = document.querySelector('#delete-task');
const closeModalButton = document.querySelector('#close-modal');
// LocalStorageにTODOリストがない場合は初期値を設定する
if (!localStorage.getItem(TODO_STORAGE_KEY)) {
localStorage.setItem(TODO_STORAGE_KEY, '[]');
}
// TODOリストの配列を取得する
function getTodoList() {
return JSON.parse(localStorage.getItem(TODO_STORAGE_KEY));
}
// TODOリストをLocalStorageに保存する
function saveTodoList(todoList) {
localStorage.setItem(TODO_STORAGE_KEY, JSON.stringify(todoList));
}
// タスクを作成する
function createTask(title, details, dueDate, taskId) {
const li = document.createElement('li');
const titleSpan = document.createElement('span');
const dateSpan = document.createElement('span');
const actionsDiv = document.createElement('div');
const viewButton = document.createElement('button');
const editButton = document.createElement('button');
titleSpan.textContent = title;
dateSpan.textContent = dueDate;
viewButton.textContent = '詳細';
viewButton.addEventListener('click', function() {
showModal(taskId);
});
editButton.textContent = '編集';
editButton.addEventListener('click', function() {
editTask(taskId);
});
li.appendChild(titleSpan);
li.appendChild(dateSpan);
actionsDiv.appendChild(viewButton);
actionsDiv.appendChild(editButton);
li.appendChild(actionsDiv);
todoList.appendChild(li);
}
// タスクを削除する
function deleteTask(taskId) {
const todoList = getTodoList();
const newTodoList = todoList.filter(function(task) {
return task.id !== taskId;
});
saveTodoList(newTodoList);
updateTodoList();
hideModal();
alert('バイバイ、タスク');
}
// タスクを編集する
function editTask(taskId) {
const todoList = getTodoList();
const task = todoList.find(function(task) {
return task.id === taskId;
});
document.querySelector('#title').value = task.title;
document.querySelector('#details').value = task.details;
document.querySelector('#due-date').value = task.dueDate;
document.querySelector('#edit-id').value = task.id;
addButton.value = '更新';
todoForm.removeEventListener('submit', createNewTask);
todoForm.addEventListener('submit', updateTask);
}
// タスクを更新する
function updateTask(event) {
event.preventDefault();
const title = document.querySelector('#title').value;
const details = document.querySelector('#details').value;
const dueDate = document.querySelector('#due-date').value;
const editId = document.querySelector('#edit-id').value;
const todoList = getTodoList();
const index = todoList.findIndex(function(task) {
return task.id === editId;
});
todoList[index].title = title;
todoList[index].details = details;
todoList[index].dueDate = dueDate;
saveTodoList(todoList);
updateTodoList();
todoForm.reset();
addButton.value = '追加';
document.querySelector('#edit-id').value = '';
todoForm.removeEventListener('submit', updateTask);
todoForm.addEventListener('submit', createNewTask);
}
// 新しいタスクを作成する
function createNewTask(event) {
event.preventDefault();
const title = document.querySelector('#title').value;
const details = document.querySelector('#details').value;
const dueDate = document.querySelector('#due-date').value;
const newTask = {
title: title,
details: details,
dueDate: dueDate,
id: Date.now()
};
const todoList = getTodoList();
todoList.push(newTask);
saveTodoList(todoList);
createTask(title, details, dueDate, newTask.id);
todoForm.reset();
}
// TODOリストを更新する
function updateTodoList() {
todoList.innerHTML = '';
const todoListItems = getTodoList().map(function(task) {
return createTask(task.title, task.details, task.dueDate, task.id);
});
todoListItems.forEach(function(item) {
todoList.appendChild(item);
});
}
// タスク詳細モーダルを表示する
function showModal(taskId) {
const todoList = getTodoList();
const task = todoList.find(function(task) {
return task.id === taskId;
});
modalHeader.textContent = task.title;
modalDetails.textContent = task.details;
modalDate.textContent = task.dueDate;
deleteTaskButton.addEventListener('click', function() {
deleteTask(task.id);
});
closeModalButton.addEventListener('click', function() {
hideModal();
});
detailsModal.classList.remove('hide');
}
// タスク詳細モーダルを非表示にする
function hideModal() {
modalHeader.textContent = '';
modalDetails.textContent = '';
modalDate.textContent = '';
deleteTaskButton.removeEventListener('click', deleteTask);
closeModalButton.removeEventListener('click', hideModal);
detailsModal.classList.add('hide');
}
addButton.addEventListener('click', function() {
if (addButton.value === '追加') {
createNewTask(event);
}
});
todoForm.addEventListener('submit', createNewTask);
updateTodoList();
</script>
</body>
</html>
```