Skip to content

Commit

Permalink
Added Todo List Feature (#322)
Browse files Browse the repository at this point in the history
* Added Todo List Feature

* Added a To Do List Toggle in Settings

* Fixed the To Do List loosing focus issue

* Fixed the Errors in Todo List

* Removed the Use of innerHTML to prevent XSS vulnerabilities

* Fixed the Blink Issue and Made the Alert Translatable and Added some Translations

* Removed todo Translations

* Made a few changes to Todo List translations

* Changed Todo Input Placeholder

* Fixed Silly Mistakes

* Switched to JSON Based Approach for To Do List

* Fixed Issue when todoList was not in Local Storage

* Sanitized User Input and Reduced redundancy in Todo code

* Added Comments

* Optimised Todo functions for Reduced Resource Usage

* Removed Alert for when no input is given to ToDo Input Box
  • Loading branch information
Thunder-Blaze authored Dec 16, 2024
1 parent a1033a2 commit dce23b9
Show file tree
Hide file tree
Showing 4 changed files with 396 additions and 0 deletions.
36 changes: 36 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@
</head>

<body>
<!----------------------- ToDo List Setup Starting ----------------------->
<!-- 9 Dot Icon -->
<div class="todoListCont" id="todoListCont">
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="dot-icon" width="36" height="36" viewBox="0 0 32 32" xml:space="preserve">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="0.128"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M11,30H5c-1.7,0-3-1.3-3-3v-6c0-1.7,1.3-3,3-3h6c1.7,0,3,1.3,3,3v6C14,28.7,12.7,30,11,30z"></path> </g> <g> <path d="M29,6H17c-0.6,0-1-0.4-1-1s0.4-1,1-1h12c0.6,0,1,0.4,1,1S29.6,6,29,6z"></path> </g> <g> <path d="M24,10h-7c-0.6,0-1-0.4-1-1s0.4-1,1-1h7c0.6,0,1,0.4,1,1S24.6,10,24,10z"></path> </g> <g> <path d="M29,22H17c-0.6,0-1-0.4-1-1s0.4-1,1-1h12c0.6,0,1,0.4,1,1S29.6,22,29,22z"></path> </g> <g> <path d="M24,26h-7c-0.6,0-1-0.4-1-1s0.4-1,1-1h7c0.6,0,1,0.4,1,1S24.6,26,24,26z"></path> </g> <path d="M11,2H5C3.3,2,2,3.3,2,5v6c0,1.7,1.3,3,3,3h6c1.7,0,3-1.3,3-3V5C14,3.3,12.7,2,11,2z M11.7,6.7l-3,3C8.5,9.9,8.3,10,8,10 S7.5,9.9,7.3,9.7l-2-2c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0L8,7.6l2.3-2.3c0.4-0.4,1-0.4,1.4,0S12.1,6.3,11.7,6.7z"></path> </g>
</svg>
<!-- Text to appear on hover -->
<span class="tooltip-text" id="todoListHover">ToDo List</span>
</div>

<!-- Centered Icon Container -->
<div id="todoContainer" class="todo-container" style="display: none;">
<h2 id="todoListHeading">To Do List</h2>
<div class="searchbar-content">
<input id="todoInput" placeholder="Type here..." type="text" autocomplete="off">
<div class="searchControls">
<!-- Add Button -->
<button id="todoAdd">+</button>
</div>
</div>
<ul class="todolist" id="todoullist">

</ul>
</div>

<!----------------------- Google App Menu Setup Starting ----------------------->
<!-- 9 Dot Icon -->
<div class="googleAppsCont" id="googleAppsCont">
Expand Down Expand Up @@ -960,6 +985,17 @@ <h1>Material You NewTab</h1>
<span class="toggle"></span>
</label>
</div>

<div class="ttcont">
<div class="texts">
<div class="bigText" id="todoListText">To Do List</div>
<div class="infoText" id="todoListInfo">Show a Daily To Do List</div>
</div>
<label class="switch">
<input id="todoListCheckbox" type="checkbox">
<span class="toggle"></span>
</label>
</div>
<!-- ---🟡--- -->
<div class="ttcont">
<div class="texts">
Expand Down
13 changes: 13 additions & 0 deletions languages.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const translations = {
"enable_ai_tools": "Show shortcuts for AI tools",
"googleAppsMenuText": "Google Apps",
"googleAppsMenuInfo": "Show shortcuts for Google Apps",
"todoListText": "To Do List",
"todoListInfo": "Show a Daily To Do List",
// Digital Clock
"digitalclocktittle": "Digital Clock",
"digitalclockinfo": "Switch to the digital clock",
Expand Down Expand Up @@ -83,10 +85,12 @@ const translations = {
"enterBtn": "Search",
"searchPlaceholder": "Type here...",
"listenPlaceholder": "Listening...",
"todoPlaceholder": "Add task...",
"searchWithHint": "Search With",
"ai_tools": "AI Tools",
"userText": "Click here to edit",
"googleAppsHover": "Google Apps", // Keep this untranslated if string width is much longer
"todoListHover": "ToDo List", // Keep this untranslated if string width is much longer
// End of Body and New Tab Items

// Greeting
Expand Down Expand Up @@ -345,6 +349,8 @@ const translations = {
"enable_ai_tools": "AI उपकरणों के शॉर्टकट्स प्रदर्शित करें",
"googleAppsMenuText": "गूगल ऐप्स",
"googleAppsMenuInfo": "गूगल ऐप्स के शॉर्टकट्स प्रदर्शित करें",
"todoListText": "कार्य सूची",
"todoListInfo": "अपनी दैनिक कार्य सूची देखें और व्यवस्थित रहें",
// Digital Clock
"digitalclocktittle": "डिजिटल घड़ी",
"digitalclockinfo": "डिजिटल घड़ी पर स्विच करें",
Expand Down Expand Up @@ -402,6 +408,7 @@ const translations = {
"enterBtn": "खोजें",
"searchPlaceholder": "यहाँ लिखें...",
"listenPlaceholder": "सुन रहे हैं...",
"todoPlaceholder": "कार्य जोड़ें...",
"searchWithHint": "खोज माध्यम",
"ai_tools": "AI उपकरण",
"userText": "यहाँ अपना टेक्स्ट लिखें",
Expand All @@ -427,6 +434,7 @@ const translations = {
"firefly": "एडोबी फायरफ्लाई",
"github": "गिटहब",
"googleAppsHover": "गूगल ऐप्स",
"todoListHover": "कार्य सूची",

// Wallpaper and alerts
"uploadWallpaperText": "वॉलपेपर अपलोड करें",
Expand Down Expand Up @@ -1858,6 +1866,9 @@ function applyLanguage(lang) {
{ id: 'enable_ai_tools', key: 'enable_ai_tools' },
{ id: 'googleAppsMenuText', key: 'googleAppsMenuText' },
{ id: 'googleAppsMenuInfo', key: 'googleAppsMenuInfo' },
{ id: 'todoListHeading', key: 'todoListText' },
{ id: 'todoListText', key: 'todoListText' },
{ id: 'todoListInfo', key: 'todoListInfo' },
{ id: 'fahrenheitCelsiusCheckbox', key: 'fahrenheitCelsiusCheckbox' },
{ id: 'fahrenheitCelsiusText', key: 'fahrenheitCelsiusText' },
{ id: 'micIconTitle', key: 'micIconTitle' },
Expand Down Expand Up @@ -1893,6 +1904,7 @@ function applyLanguage(lang) {
{ id: 'conditionText', key: 'conditionText' },
{ id: 'enterBtn', key: 'enterBtn' },
{ id: 'searchQ', key: 'searchPlaceholder', isPlaceholder: true },
{ id: 'todoInput', key: 'todoPlaceholder', isPlaceholder: true },
{ id: 'searchWithHint', key: 'searchWithHint' },
{ id: 'ai_tools', key: 'ai_tools' },
{ id: 'humidityLevel', key: 'humidityLevel' },
Expand All @@ -1916,6 +1928,7 @@ function applyLanguage(lang) {
{ id: 'metaAI', key: 'metaAI'},
{ id: 'github', key: 'github' },
{ id: 'googleAppsHover', key: 'googleAppsHover' },
{ id: 'todoListHover', key: 'todoListHover' },
{ id: 'uploadWallpaperText', key: 'uploadWallpaperText' },
{ id: 'backupText', key: 'backupText' },
{ id: 'restoreText', key: 'restoreText' },
Expand Down
147 changes: 147 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,139 @@ document.addEventListener("click", function (event) {
}
});
// ------------------------End of Google App Menu Setup-----------------------------------
// ----------------------------------- To Do List ----------------------------------------

// DOM Variables
const todoContainer = document.getElementById("todoContainer");
const todoListCont = document.getElementById("todoListCont");
const todoulList = document.getElementById("todoullist");
const todoAdd = document.getElementById("todoAdd");
const todoInput = document.getElementById("todoInput");
let todoList = {}; // Initialize todoList JSON

// Add event listeners for Add button click or Enter key press
todoAdd.addEventListener("click", addtodoItem);
todoInput.addEventListener("keypress", (event) => {
if (event.key === "Enter") {
addtodoItem();
}
});

// Utility function to sanitize input
function sanitizeInput(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}

// Function to add items to the TODO list
function addtodoItem() {
const inputText = todoInput.value.trim(); // Remove useless whitespaces
if (inputText === '') {
return; // Return the function when the input is empty
}
const t = "t" + Date.now(); // Generate a Unique ID
const rawText = inputText;
todoList[t] = { title: rawText, status: "pending" }; // Add data to the JSON variable
const li = createTodoItemDOM(t, rawText, "pending"); // Create List item
todoulList.appendChild(li); // Append the new item to the DOM immediately
todoInput.value = ''; // Clear Input
SaveToDoData(); // Save changes
}

function createTodoItemDOM(id, title, status) {
let li = document.createElement('li');
li.innerHTML = sanitizeInput(title); // Sanitize before rendering in DOM
const span = document.createElement("span"); // Create the Cross Icon
span.setAttribute("class", "todoremovebtn");
span.textContent = "\u00d7";
li.appendChild(span); // Add the cross icon to the LI tag
li.setAttribute("class", "todolistitem");
if (status === 'completed') {
li.classList.add("checked");
}
li.setAttribute("data-todoitem", id); // Set a data attribute to the li so that we can uniquely identify which li has been modified or deleted
return li; // Return the created `li` element
}

// Event delegation for task check and remove
todoulList.addEventListener("click", (event) => {
if (event.target.tagName === "LI"){
event.target.classList.toggle("checked"); // Check the clicked LI tag
let id = event.target.dataset.todoitem;
todoList[id].status = ((todoList[id].status === "completed")? "pending" : "completed"); // Update status
SaveToDoData(); // Save Changes
} else if (event.target.tagName === "SPAN"){
let id = event.target.parentElement.dataset.todoitem;
event.target.parentElement.remove(); // Remove the clicked LI tag
delete todoList[id]; // Remove the deleted List item data
SaveToDoData(); // Save Changes
}
});

// Save JSON to local Storage
function SaveToDoData(){
localStorage.setItem("todoList", JSON.stringify(todoList));
}
// Fetch saved JSON and create list items using it
function ShowToDoList() {
try {
todoList = JSON.parse(localStorage.getItem("todoList")) || {}; // Parse stored data or initialize empty
const fragment = document.createDocumentFragment(); // Create a DocumentFragment
for (let id in todoList) {
const todo = todoList[id];
const li = createTodoItemDOM(id, todo.title, todo.status); // Create `li` elements
fragment.appendChild(li); // Add `li` to the fragment
}
todoulList.appendChild(fragment); // Append all `li` to the `ul` at once
} catch (error) {
console.error("Error loading from localStorage:", error);
localStorage.setItem("todoList", '{}'); // Reset corrupted data
}
}

// Code to reset the List on the Next Day
let todoLastUpdateDate = localStorage.getItem("todoLastUpdateDate"); // Get the date of last update
let todoCurrentDate = new Date().toLocaleDateString(); // Get current date
if (todoLastUpdateDate===todoCurrentDate){
ShowToDoList();
} else {
// Reset the list when last update date and the current date does not match
localStorage.setItem("todoLastUpdateDate",todoCurrentDate);
localStorage.setItem("todoList",'{}');
ShowToDoList();
}

// Toggle menu and tooltip visibility
todoListCont.addEventListener("click", function (event) {
const isMenuVisible = todoContainer.style.display === 'grid';

// Toggle menu visibility
todoContainer.style.display = isMenuVisible ? 'none' : 'grid';

// Add or remove the class to hide the tooltip
if (!isMenuVisible) {
todoListCont.classList.add('menu-open'); // Hide tooltip
todoInput.focus(); // Auto focus on input box
} else {
todoListCont.classList.remove('menu-open'); // Restore tooltip
}
});

// Close menu when clicking outside
document.addEventListener("click", function (event) {
const isClickInside =
todoContainer.contains(event.target) || todoListCont.contains(event.target) || event.target.classList.contains('todoremovebtn');

if (!isClickInside && todoContainer.style.display === 'grid') {
todoContainer.style.display = 'none'; // Hide menu
todoListCont.classList.remove('menu-open'); // Restore tooltip
}

event.stopPropagation();
});

// ------------------------------- End of To Do List -------------------------------------

// Retrieve current time and calculate initial angles
var currentTime = new Date();
Expand Down Expand Up @@ -2313,6 +2446,7 @@ document.addEventListener("DOMContentLoaded", function () {
const adaptiveIconToggle = document.getElementById("adaptiveIconToggle");
const aiToolsCheckbox = document.getElementById("aiToolsCheckbox");
const googleAppsCheckbox = document.getElementById("googleAppsCheckbox");
const todoListCheckbox = document.getElementById("todoListCheckbox");
const timeformatField = document.getElementById("timeformatField");
const hourcheckbox = document.getElementById("12hourcheckbox");
const digitalCheckbox = document.getElementById("digitalCheckbox");
Expand Down Expand Up @@ -2977,6 +3111,17 @@ document.addEventListener("DOMContentLoaded", function () {
}
});

todoListCheckbox.addEventListener("change", function () {
saveCheckboxState("todoListCheckboxState", todoListCheckbox);
if (todoListCheckbox.checked) {
todoListCont.style.display = "flex";
saveDisplayStatus("todoListDisplayStatus", "flex");
} else {
todoListCont.style.display = "none";
saveDisplayStatus("todoListDisplayStatus", "none");
}
});

fahrenheitCheckbox.addEventListener("change", function () {
saveCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox);
});
Expand Down Expand Up @@ -3050,9 +3195,11 @@ document.addEventListener("DOMContentLoaded", function () {
loadActiveStatus("proxybypassField", proxybypassField);
loadCheckboxState("aiToolsCheckboxState", aiToolsCheckbox);
loadCheckboxState("googleAppsCheckboxState", googleAppsCheckbox);
loadCheckboxState("todoListCheckboxState", todoListCheckbox);
loadDisplayStatus("shortcutsDisplayStatus", shortcuts);
loadDisplayStatus("aiToolsDisplayStatus", aiToolsCont);
loadDisplayStatus("googleAppsDisplayStatus", googleAppsCont);
loadDisplayStatus("todoListDisplayStatus", todoListCont);
loadCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox);
loadShortcuts();
});
Loading

0 comments on commit dce23b9

Please sign in to comment.