Skip to content

Commit ad11b39

Browse files
authored
Merge pull request #9 from lukeecart/sanitise-html-input
Sanitise HTML input & use id instead of title to identify task
2 parents 2e38c94 + fef369d commit ad11b39

File tree

1 file changed

+62
-25
lines changed

1 file changed

+62
-25
lines changed

main.js

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,31 @@ completeAllBtn.addEventListener('click', () => {
2121
let savedTasks = JSON.parse(localStorage.getItem('tasks'));
2222
let taskTitles = document.querySelectorAll('.todo');
2323

24-
for (let i = 0, len = savedTasks.length; i < len; i++) {
25-
var check = document.getElementsByName("completed")[i];
24+
for (let i = 0; i < savedTasks.length; i++) {
25+
var check = document.getElementsByName('completed')[i];
2626
check.checked = "checked";
27-
updateTaskInStorage(taskTitles[i].innerHTML, true);
27+
const taskTitleId = Number(taskTitles[i].id);
28+
updateTaskInStorage(taskTitleId, true);
2829
}
2930
});
3031

3132
// Create TODO
3233
addBtn.addEventListener('click', () => {
33-
newTodo = document.querySelector('textarea').value;
34-
saveTaskToStorage(newTodo);
35-
createTodo(newTodo);
34+
const newTodoTitle = sanitiseInput(document.querySelector('textarea').value);
35+
36+
const newTodoTask = generateTask(newTodoTitle);
37+
38+
saveTaskToStorage(newTodoTask);
39+
createTodo(newTodoTask);
3640
hidePage();
3741
});
3842

3943
document.querySelector('textarea').addEventListener('keypress', (key) => {
40-
newTodo = document.querySelector('textarea').value;
44+
const newTodoTitle = sanitiseInput(document.querySelector('textarea').value);
45+
const newTodoTask = generateTask(newTodoTitle);
4146
if (key.which === 13) {
42-
saveTaskToStorage(newTodo);
43-
createTodo(newTodo);
47+
saveTaskToStorage(newTodoTask);
48+
createTodo(newTodoTask);
4449
hidePage();
4550
}
4651
});
@@ -51,55 +56,87 @@ todoContainer.addEventListener('click', (e) => {
5156

5257
if (item.classList[2] == 'delete') {
5358
item.parentElement.remove();
54-
const taskTitle = item.parentElement.children[1].innerHTML;
55-
deleteTaskFromStorage(taskTitle);
59+
const taskId = Number(item.parentElement.children[1].id);
60+
deleteTaskFromStorage(taskId);
5661
}
5762
});
5863

5964
cancelBtn.addEventListener('click', hidePage);
6065

6166
function hidePage() {
6267
document.querySelector('.add-task').classList.toggle('hidden');
68+
6369
if (document.querySelector('.add-task').classList[0] != 'hidden') {
6470
document.querySelector('textarea').focus();
6571
}
72+
6673
document.querySelector('textarea').value = '';
6774
};
6875

6976
function createTodo(newTodo) {
7077
const isChecked = newTodo.isChecked ? 'checked' : '';
71-
const taskTitle = newTodo.title || newTodo;
78+
7279
const demoTodo = document.createElement('LI');
73-
const createdElement = `<input type='checkbox' ${isChecked} name='completed' onchange='updateTaskInStorage("${taskTitle}")'> <p class='todo'>${taskTitle}</p><i class='far fa-trash-alt delete'></i>`;
80+
const createdElement = `<input type='checkbox' ${isChecked} name='completed' onchange="updateTaskInStorage(${newTodo.id})"> <p class='todo' id=${newTodo.id}>${newTodo.title}</p><i class='far fa-trash-alt delete'></i>`;
81+
7482
demoTodo.innerHTML = createdElement;
7583
todoContainer.appendChild(demoTodo);
7684
};
7785

7886
function saveTaskToStorage(addedTask) {
7987
let savedTasks = JSON.parse(localStorage.getItem('tasks')) || [];
80-
const newTask = {
81-
id: Date.now(),
82-
title: addedTask,
83-
isChecked: false
84-
};
85-
savedTasks.push(newTask);
88+
89+
savedTasks.push(addedTask);
90+
8691
localStorage.setItem('tasks', JSON.stringify(savedTasks));
8792
}
8893

89-
function deleteTaskFromStorage(removedTask) {
90-
console.log(removedTask);
94+
function deleteTaskFromStorage(removedTaskId) {
9195
let savedTasks = JSON.parse(localStorage.getItem('tasks'));
96+
9297
const newTaskList = savedTasks.filter(taskItem => {
93-
return taskItem.title !== removedTask;
98+
return taskItem.id !== removedTaskId;
9499
});
100+
95101
localStorage.setItem('tasks', JSON.stringify(newTaskList));
96102
}
97103

98-
function updateTaskInStorage(completedTask, isCompleted) {
104+
function updateTaskInStorage(completedTaskId, isCompleted) {
99105
let savedTasks = JSON.parse(localStorage.getItem('tasks'));
106+
100107
const taskIndex = savedTasks.findIndex(taskItem => {
101-
return taskItem.title === completedTask;
108+
return taskItem.id === completedTaskId;
102109
});
103-
savedTasks[taskIndex].isChecked = isCompleted || !savedTasks[taskIndex].isChecked;
110+
111+
if (savedTasks[taskIndex]) {
112+
savedTasks[taskIndex].isChecked = isCompleted || !savedTasks[taskIndex]?.isChecked;
113+
}
104114
localStorage.setItem('tasks', JSON.stringify(savedTasks));
105115
}
116+
117+
function sanitiseInput(htmlString) {
118+
const entityMap = {
119+
'&': '&amp;',
120+
'<': '&lt;',
121+
'>': '&gt;',
122+
'"': '&quot;',
123+
"'": '&#39;',
124+
'/': '&#x2F;',
125+
'`': '&#x60;',
126+
'=': '&#x3D;'
127+
};
128+
129+
const string = String(htmlString).replace(/[&<>"'`=\/]/g, function (s) {
130+
return entityMap[s];
131+
});
132+
133+
return string.trim();
134+
}
135+
136+
function generateTask(taskTitle) {
137+
return {
138+
id: Date.now(),
139+
title: taskTitle,
140+
isChecked: false
141+
};
142+
}

0 commit comments

Comments
 (0)