Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added add-remove-update feature to app #2

Merged
merged 1 commit into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
201 changes: 201 additions & 0 deletions src/add_remove_update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/* eslint-disable max-classes-per-file */
// Task class : represents one task
export class Task {
constructor(description, completed, index) {
this.description = description;
this.completed = completed;
this.index = index;
}
}

// Store Class: Handles Storage
export class Store {
// Get Tasks : gets the tasks from store
static getTasks() {
let tasks;
if (localStorage.getItem('tasks') === null) {
// if there is nothing in storage
tasks = []; // create empty array
} else {
tasks = JSON.parse(localStorage.getItem('tasks')); // convert them in array
}
return tasks;
}

// add the task to store
static addTask(task) {
const tasks = Store.getTasks(); // get tasks
tasks.push(task); // add new task
localStorage.setItem('tasks', JSON.stringify(tasks)); // convert them in string
}

// remove a task from store
static removeTask(el, description) {
if (el.classList.contains('remove')) {
const tasks = Store.getTasks();
let spliced;
tasks.forEach((task, index) => {
if (task.description === description) {
spliced = tasks.splice(index, 1);
}
});
localStorage.setItem('tasks', JSON.stringify(tasks));
for (let i = 0; i < tasks.length; i += 1) {
if (tasks[i].index >= spliced[0].index) {
tasks[i].index -= 1;
}
}
localStorage.setItem('tasks', JSON.stringify(tasks));
}
}

// clear all completed tasks
static clearCompleted() {
// check in loacal storage
let tasks = Store.getTasks();
const remainingTasks = [];
for (let i = 0; i < tasks.length; i += 1) {
if (tasks[i].completed === false) {
remainingTasks.push(tasks[i]);
}
}
localStorage.setItem('tasks', JSON.stringify(remainingTasks));
tasks = Store.getTasks();
for (let i = 0; i < tasks.length; i += 1) {
tasks[i].index = i;
}
localStorage.setItem('tasks', JSON.stringify(tasks));
}

// update tasks
static updateTask(description) {
const tasks = Store.getTasks();
const taskList = document.querySelector('.tasks');
const nodes = Array.prototype.slice.call(taskList.children); // convert list in array
for (let i = 0; i < tasks.length; i += 1) {
// iterate over tasks to find completed tasks
if (tasks[i].index === nodes.indexOf(description.parentElement.parentElement)) {
if (description.textContent !== tasks[i].description) {
tasks[i].description = description.textContent;
}
}
}
localStorage.setItem('tasks', JSON.stringify(tasks));
}
}

// Ui class : handles ui tasks
export class UI {
static displayTasks() {
const tasks = Store.getTasks(); // getting the tasks from local storage

// looping over the stored taskks and add it to list
tasks.forEach((task) => UI.addTasksToList(task));
}

static addTasksToList(task) {
const list = document.querySelector('.tasks');

const row = document.createElement('li');
row.classList.add('task');

row.innerHTML = `
<div class="task-field">
<input type="checkbox" name="" class="task-checkbox" />
<label class="task-description">${task.description}</label>
</div>
<div class="user-interaction">
<i class="bi bi-pencil edit-btn"></i>
<i class="bi bi-check2 update-btn"></i>
<i class="bi bi-x remove-btn remove"></i>
<div>`;

list.appendChild(row);
}

// for removing task
static removeTask(el) {
if (el.classList.contains('remove')) {
el.parentElement.parentElement.remove();
}
}

// to show Alert when added or Invalid
static showAlert(message, className) {
const div = document.createElement('div');
div.className = `alert ${className}`;
if (className === 'invalid') {
div.innerHTML = '<i class="bi bi-x-circle"></i>';
} else if (className === 'success') {
div.innerHTML = '';
}
div.appendChild(document.createTextNode(message));
const form = document.querySelector('.field-input-to-do');
const btn = document.querySelector('.submit-btn');
form.insertBefore(div, btn);

// Vanish in 3 seconds
setTimeout(() => document.querySelector('.alert').remove(), 3000);
}

static updateTask(el) {
const description = el.parentElement.parentElement.children[0].children[1];
description.setAttribute('contentEditable', 'true');

// to select the text that is editable
const selectText = (ele) => {
let sel; let
range;
// get element id
if (window.getSelection && document.createRange) {
// Browser compatibility
sel = window.getSelection();
if (sel.toString() === '') {
// no text selection
window.setTimeout(() => {
range = document.createRange(); // range object
range.selectNodeContents(ele); // sets Range
sel.removeAllRanges(); // remove all ranges from selection
sel.addRange(range); // add Range to a Selection.
}, 1);
}
} else if (document.selection) {
// older ie
sel = document.selection.createRange();
if (sel.text === '') {
// no text selection
range = document.body.createTextRange(); // Creates TextRange object
range.moveToElementText(ele); // sets Range
range.select(); // make selection.
}
}
};

// select the text that is editable
selectText(description);
description.parentElement.parentElement.classList.add('active');

const editBtn = el;
const updateBtn = el.nextElementSibling;
// to remove edit btn
editBtn.style.display = 'none';
// to display update btn
updateBtn.style.display = 'block';

description.addEventListener('keypress', (keypressed) => {
if (keypressed.key === 'Enter') {
updateBtn.click();
Store.updateTask(description);
}
});

updateBtn.addEventListener('click', () => {
description.setAttribute('contentEditable', 'false');
description.parentElement.parentElement.classList.remove('active');
// to remove edit btn
editBtn.style.display = 'block';
// to display update btn
updateBtn.style.display = 'none';
});
}
}
110 changes: 110 additions & 0 deletions src/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Task, Store, UI } from './add_remove_update.js';

// Event: Add task To list
document.querySelector('.field-input-to-do').addEventListener('submit', (e) => {
e.preventDefault();

const tasks = Store.getTasks();

// get input values
const description = document.querySelector('.input-to-do').value;
const completed = false;
const index = tasks.length;

// validations
// Validate
if (description === '') {
UI.showAlert('', 'invalid');
} else {
// instantiate task
const task = new Task(description, completed, index);

// ADD task
UI.addTasksToList(task);

// Add task to store
Store.addTask(task);
// Show success message
UI.showAlert(' ', 'success');
// clear input field
document.querySelector('.input-to-do').value = '';
document.location.reload(true); // for reloading when item is added
}
});

// Event: Remove a Task
document.querySelector('.tasks').addEventListener('click', (e) => {
if (e.target.classList.contains('remove')) {
// remove from UI
UI.removeTask(e.target);
// update storage
const description = e.target.parentElement.parentElement.children[0].children[1].textContent;
Store.removeTask(e.target, description);
}
});

// event: Update a task
const taskList = document.querySelector('.tasks');
taskList.addEventListener('click', (e) => {
if (e.target.classList.contains('edit-btn')) {
UI.updateTask(e.target);
}
});

/// USER INTERACTIONS
// event: clear completed
document.querySelector('.clear-completed').addEventListener('click', () => {
// clear from loacal storage
Store.clearCompleted();
document.location.reload(true); // for reloading after clearing s completed items
});

// Load tasks
UI.displayTasks();

//* DO IGNORE THESE IT HAS SOMETHING TO DO WITH NEXT Pull Reqest
// //after content is loaded check loacal storage if there is any completed task
// document.querySelectorAll('input[type="checkbox"]').forEach((box) => {
// const tasks = Store.getTasks();
// const taskList = document.querySelectorAll(".task");
// let nodes = Array.prototype.slice.call(taskList); //convert list in array
// for (let i = 0; i < tasks.length; i+= 1) {
// //iterate over tasks to find completed tasks
// let task = tasks[i].completed;
// if (tasks[i].index === nodes.indexOf(box.parentElement.parentElement)) {
// //condition if
// if (task) {
// //if task is completed
// box.setAttribute("checked", ""); //fill the check
// }
// localStorage.setItem("tasks", JSON.stringify(tasks)); //update storage
// }
// }

// // Event: update storage when a task is completed
// document.querySelectorAll('input[type="checkbox"]').forEach((box) => {
// const tasks = Store.getTasks();
// const taskList = document.querySelectorAll(".task");
// box.addEventListener("change", () => {
// //same on when user take action conditions are opposite
// let nodes = Array.prototype.slice.call(taskList);
// for (let i = 0; i < tasks.length; i+= 1) {
// let completed = tasks[i].completed;
// if (tasks[i].index === nodes.indexOf(box.parentElement.parentElement)) {
// if (completed) {
// box.removeAttribute("checked");
// tasks[i].completed = false;
// }
// if (!completed) {
// box.setAttribute("checked", "");
// tasks[i].completed = true;
// }
// }
// }
// localStorage.setItem("tasks", JSON.stringify(tasks));

// //for reloading and updating everytime a task is completed //! Any better way?
// document.location.reload(true);
// });
// });
// });