├── .gitignore ├── .vscode └── settings.json ├── jest.config.js ├── .babelrc ├── src ├── modules │ ├── storage.js │ ├── interactivity.js │ └── functionality.js ├── index.html ├── index.js └── style.css ├── .stylelintrc.js ├── .hintrc ├── .eslintrc.json ├── webpack.config.js ├── .stylelintrc.json ├── LICENSE ├── dist ├── index.html └── index.js ├── package.json ├── addRemove.test.js ├── updateComplete.test.js ├── .github └── workflows │ └── linters.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | node_modules/ 3 | coverage/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "liveServer.settings.port": 5501 3 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'jsdom', 3 | }; -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "plugins": ["@babel/plugin-transform-modules-commonjs"] 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/modules/storage.js: -------------------------------------------------------------------------------- 1 | const storeTasks = (toDoArray) => { 2 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 3 | }; 4 | 5 | export default storeTasks; -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "stylelint-config-standard", 3 | "plugins": ["stylelint-scss"], 4 | "rules": { 5 | "at-rule-no-unknown": null, 6 | "scss/at-rule-no-unknown": true, 7 | "no-descending-specificity": null 8 | }, 9 | } -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "connector": { 3 | "name": "local", 4 | "options": { 5 | "pattern": ["**", "!.git/**", "!node_modules/**"] 6 | } 7 | }, 8 | "extends": ["development"], 9 | "formatters": ["stylish"], 10 | "hints": [ 11 | "button-type", 12 | "disown-opener", 13 | "html-checker", 14 | "meta-charset-utf-8", 15 | "meta-viewport", 16 | "no-inline-styles:error" 17 | ] 18 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parser": "babel-eslint", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "extends": ["airbnb-base"], 13 | "rules": { 14 | "no-shadow": "off", 15 | "no-param-reassign": "off", 16 | "eol-last": "off", 17 | "import/extensions": [ 1, { 18 | "js": "always", "json": "always" 19 | }] 20 | }, 21 | "ignorePatterns": [ 22 | "dist/", 23 | "build/" 24 | ] 25 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | entry: './src/index.js', 7 | devServer: { 8 | static: './dist', 9 | }, 10 | plugins: [ 11 | new HtmlWebpackPlugin({ 12 | template: './src/index.html', 13 | }), 14 | ], 15 | output: { 16 | filename: 'index.js', 17 | path: path.resolve(__dirname, 'dist'), 18 | clean: true, 19 | }, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.css$/i, 24 | use: ['style-loader', 'css-loader'], 25 | }, 26 | ], 27 | }, 28 | }; -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"], 4 | "rules": { 5 | "at-rule-no-unknown": [ 6 | true, 7 | { 8 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"] 9 | } 10 | ], 11 | "scss/at-rule-no-unknown": [ 12 | true, 13 | { 14 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"] 15 | } 16 | ], 17 | "csstree/validator": true 18 | }, 19 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"] 20 | } -------------------------------------------------------------------------------- /src/modules/interactivity.js: -------------------------------------------------------------------------------- 1 | // // CLEAR ALL COMPLETED// 2 | 3 | const clearAllCompleted = () => { 4 | let toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 5 | toDoArray = toDoArray.filter((task) => !task.completed); 6 | toDoArray = toDoArray.map((task, index) => { 7 | task.index = index + 1; 8 | return task; 9 | }); 10 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 11 | }; 12 | /// EDIT TASKS ////// 13 | 14 | const editTask = (index) => { 15 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 16 | const textInputs = document.querySelectorAll('.text-input'); 17 | textInputs[index].addEventListener('change', () => { 18 | toDoArray[index].description = textInputs[index].value; 19 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 20 | }); 21 | }; 22 | 23 | export { clearAllCompleted, editTask }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Maedea9 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | To Do List 8 | 9 | 10 |
11 |

To Do List

12 |
13 | 14 |
15 |
16 |

Today's To Do

17 | 18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | To Do List 8 | 9 | 10 |
11 |

To Do List

12 |
13 | 14 |
15 |
16 |

Today's To Do

17 | 18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "to-do-list", 3 | "version": "1.0.0", 4 | "description": "a tool that helps to organize your day", 5 | "private": true, 6 | "scripts": { 7 | "test": "jest --coverage", 8 | "watch": "jest --watch *.js", 9 | "build": "webpack" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Maedea9/to-do-list.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/Maedea9/to-do-list/issues" 20 | }, 21 | "homepage": "https://github.com/Maedea9/to-do-list#readme", 22 | "devDependencies": { 23 | "@babel/plugin-transform-modules-commonjs": "^7.21.2", 24 | "babel-eslint": "^10.1.0", 25 | "css-loader": "^6.7.3", 26 | "eslint": "^7.32.0", 27 | "eslint-config-airbnb-base": "^14.2.1", 28 | "eslint-plugin-import": "^2.27.5", 29 | "hint": "^7.1.8", 30 | "html-webpack-plugin": "^5.5.0", 31 | "jest": "^29.5.0", 32 | "jest-environment-jsdom": "^29.5.0", 33 | "style-loader": "^3.3.2", 34 | "stylelint": "^13.13.1", 35 | "stylelint-config-standard": "^21.0.0", 36 | "stylelint-csstree-validator": "^1.9.0", 37 | "stylelint-scss": "^3.21.0", 38 | "webpack": "^5.77.0", 39 | "webpack-cli": "^5.0.1", 40 | "webpack-dev-server": "^4.13.2" 41 | }, 42 | "dependencies": { 43 | "lodash": "^4.17.21" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | 3 | import { 4 | addTask, renderTasks, deleteTask, 5 | } from './modules/functionality.js'; 6 | 7 | import { clearAllCompleted, editTask } from './modules/interactivity.js'; 8 | 9 | // ADD TASKS// 10 | 11 | const addButton = document.querySelector('.submit'); // clicking add button 12 | addButton.addEventListener('click', () => { 13 | addTask(); 14 | // renderTasks(); 15 | }); 16 | 17 | const taskInput = document.getElementById('taskInput'); 18 | taskInput.addEventListener('keypress', (e) => { 19 | if (e.key === 'Enter') { 20 | e.preventDefault(); // prevents page to reload when enter is pressed 21 | addTask(); 22 | // renderTasks(); 23 | } 24 | }); 25 | 26 | renderTasks(); 27 | 28 | // DELETE TASKS// 29 | 30 | const listContainer = document.querySelector('.list-content'); 31 | 32 | listContainer.addEventListener('click', (event) => { 33 | const removeTask = event.target.closest('.trash-icon'); 34 | if (removeTask) { 35 | const trashIcons = listContainer.querySelectorAll('.trash-icon'); 36 | const index = Array.from(trashIcons).indexOf(removeTask); 37 | deleteTask(index); 38 | renderTasks(); 39 | } 40 | }); 41 | 42 | // EDIT TASKS // 43 | 44 | // add event listener for editing a task// 45 | listContainer.addEventListener('click', (event) => { 46 | const textInput = event.target.closest('.text-input'); 47 | if (textInput) { 48 | const textInputs = listContainer.querySelectorAll('.text-input'); 49 | const index = Array.from(textInputs).indexOf(textInput); 50 | editTask(index); 51 | } 52 | }); 53 | 54 | // CLEAR ALL COMPLETED // 55 | 56 | const clearButton = document.getElementById('clear-complete'); 57 | clearButton.addEventListener('click', () => { 58 | clearAllCompleted(); 59 | renderTasks(); 60 | }); 61 | -------------------------------------------------------------------------------- /addRemove.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment jsdom 3 | */ 4 | 5 | import { addTask, deleteTask, editTask } from './src/modules/functionality.js'; 6 | 7 | // isolated environment with no tasks 8 | document.body.innerHTML = '

To Do List


Todays To Do

'; 9 | const container = document.querySelector('.list-content'); 10 | 11 | describe('addTask function', () => { 12 | test('should add one task to the container', () => { 13 | const input = document.querySelector('.new-task'); 14 | input.value = 'Task 1'; 15 | addTask(); 16 | setTimeout(() => { 17 | expect(container.children.length).toEqual(1); 18 | 19 | // TEST EDIT TASKS 20 | const index = 0; 21 | const previousTaskArray = document.querySelectorAll('.text-input'); 22 | const previousTask = previousTaskArray[index].value; 23 | const newInput = 'Task 2'; 24 | editTask(index, newInput); 25 | // edit other task// 26 | addTask('another task'); 27 | const actualTaskArray = document.querySelectorAll('text-input'); 28 | const actualTask = actualTaskArray[index + 1].value; 29 | expect(actualTask).not.toBe(previousTask); 30 | }, 1000); 31 | }); 32 | }); 33 | 34 | describe('deleteTask function', () => { 35 | test('should remove exactly one task from the container', () => { 36 | deleteTask(); 37 | expect(container.children.length).toBe(0); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | font-family: Verdana, Geneva, Tahoma, sans-serif; 4 | font-size: 15px; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | body { 10 | background-color: #dee2e6; 11 | } 12 | 13 | h1 { 14 | font-size: 30px; 15 | text-align: center; 16 | margin-bottom: 2%; 17 | color: #0d1b2a; 18 | } 19 | 20 | .task-container { 21 | display: flex; 22 | flex-direction: column; 23 | align-content: center; 24 | justify-content: center; 25 | width: 35%; 26 | margin-left: 31%; 27 | background-color: #fff; 28 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); 29 | border-radius: 3px; 30 | padding: 1%; 31 | color: #0d1b2a; 32 | } 33 | 34 | .new-task { 35 | width: 70%; 36 | } 37 | 38 | .task-header { 39 | display: flex; 40 | justify-content: space-between; 41 | margin-bottom: 3%; 42 | border-bottom: 1px #ddd solid; 43 | } 44 | 45 | .add-task-form { 46 | display: flex; 47 | justify-content: space-between; 48 | align-items: center; 49 | width: 100%; 50 | margin-bottom: 2%; 51 | padding-bottom: 2%; 52 | border-bottom: #ddd 1px solid; 53 | } 54 | 55 | .list-content { 56 | display: flex; 57 | flex-direction: column; 58 | border-bottom: 1px #ddd solid; 59 | width: 100%; 60 | margin-bottom: 2%; 61 | padding-bottom: 1%; 62 | } 63 | 64 | .task-box-css { 65 | display: flex; 66 | justify-content: space-between; 67 | border-bottom: 1px #ddd solid; 68 | margin-bottom: 2.5%; 69 | padding-bottom: 1%; 70 | } 71 | 72 | .task-activity { 73 | width: 100%; 74 | } 75 | 76 | .text-input { 77 | width: 70%; 78 | } 79 | 80 | .submit { 81 | cursor: pointer; 82 | } 83 | 84 | .trash-icon { 85 | cursor: pointer; 86 | } 87 | 88 | .clear-tasks { 89 | display: flex; 90 | justify-content: center; 91 | } 92 | 93 | #clear-complete { 94 | width: 50%; 95 | height: 40px; 96 | outline: none; 97 | border: none; 98 | background-color: #778da9; 99 | padding-inline: 2px; 100 | font-size: 1em; 101 | cursor: pointer; 102 | color: #0d1b2a; 103 | } 104 | -------------------------------------------------------------------------------- /updateComplete.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment jsdom 3 | */ 4 | 5 | import { clearAllCompleted } from './src/modules/interactivity.js'; 6 | import { renderTasks } from './src/modules/functionality.js'; 7 | 8 | describe('clearAllCompleted', () => { 9 | it('The clearAllCompleted function updates the task matrix correctly.', () => { 10 | // Create a test array on the localStorage 11 | const toDoArray = [ 12 | { index: 1, task: 'Go to the market', completed: true }, 13 | { index: 2, task: 'Walk the dog', completed: false }, 14 | { index: 3, task: 'Call the doctor', completed: true }, 15 | ]; 16 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 17 | 18 | // Execute the function 19 | clearAllCompleted(); 20 | 21 | // Check if the task array is well updated 22 | const updatedToDoArray = JSON.parse(localStorage.getItem('toDoArray')); 23 | expect(updatedToDoArray).toEqual([ 24 | { index: 1, task: 'Walk the dog', completed: false }, 25 | ]); 26 | }); 27 | }); 28 | 29 | // CHECKBOX TEST// 30 | 31 | jest.mock('./src/modules/storage.js', () => ({ 32 | getItem: jest.fn(() => '[{"description":"Task 1","completed":false},{"description":"Task 2","completed":false}]'), 33 | setItem: jest.fn(), 34 | })); 35 | 36 | describe('renderTasks', () => { 37 | beforeEach(() => { 38 | // Create some test data to use for localStorage 39 | const testToDoArray = [ 40 | { description: 'Task 1', completed: false }, 41 | { description: 'Task 2', completed: true }, 42 | ]; 43 | localStorage.setItem('toDoArray', JSON.stringify(testToDoArray)); 44 | }); 45 | 46 | describe('COMPLETED TASKS', () => { 47 | test('should mark a task as completed in localStorage when checkbox is clicked', () => { 48 | // render the tasks to DOM 49 | document.body.innerHTML = ` 50 |
51 | `; 52 | renderTasks(); 53 | 54 | // use setTimeout to wait for tasks to be rendered 55 | setTimeout(() => { 56 | // simulation of click on the checkbox for Task 1 57 | const checkbox = document.querySelector('.input-check'); 58 | checkbox.checked = true; 59 | checkbox.dispatchEvent(new Event('click')); 60 | 61 | // check that completed state of Task 1 has been updated in localStorage 62 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')); 63 | expect(toDoArray[0].completed).toBe(true); 64 | 65 | // done(); 66 | }, 1000); 67 | }); 68 | }); 69 | }); -------------------------------------------------------------------------------- /.github/workflows/linters.yml: -------------------------------------------------------------------------------- 1 | name: Linters 2 | 3 | on: pull_request 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | 8 | jobs: 9 | lighthouse: 10 | name: Lighthouse 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "12.x" 17 | - name: Setup Lighthouse 18 | run: npm install -g @lhci/cli@0.7.x 19 | - name: Lighthouse Report 20 | run: lhci autorun --upload.target=temporary-public-storage --collect.staticDistDir=. 21 | webhint: 22 | name: Webhint 23 | runs-on: ubuntu-22.04 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/setup-node@v1 27 | with: 28 | node-version: "18.x" 29 | - name: Setup Webhint 30 | run: | 31 | npm install --save-dev hint@7.x 32 | [ -f .hintrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.hintrc 33 | - name: Webhint Report 34 | run: npx hint . 35 | stylelint: 36 | name: Stylelint 37 | runs-on: ubuntu-22.04 38 | steps: 39 | - uses: actions/checkout@v2 40 | - uses: actions/setup-node@v1 41 | with: 42 | node-version: "18.x" 43 | - name: Setup Stylelint 44 | run: | 45 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x 46 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.stylelintrc.json 47 | - name: Stylelint Report 48 | run: npx stylelint "**/*.{css,scss}" 49 | eslint: 50 | name: ESLint 51 | runs-on: ubuntu-22.04 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: actions/setup-node@v1 55 | with: 56 | node-version: "18.x" 57 | - name: Setup ESLint 58 | run: | 59 | npm install --save-dev eslint@7.x eslint-config-airbnb-base@14.x eslint-plugin-import@2.x babel-eslint@10.x 60 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/html-css-js/.eslintrc.json 61 | - name: ESLint Report 62 | run: npx eslint . 63 | nodechecker: 64 | name: node_modules checker 65 | runs-on: ubuntu-22.04 66 | steps: 67 | - uses: actions/checkout@v2 68 | - name: Check node_modules existence 69 | run: | 70 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi -------------------------------------------------------------------------------- /src/modules/functionality.js: -------------------------------------------------------------------------------- 1 | /// RENDER TASKS/// 2 | 3 | const taskList = document.getElementById('taskList'); 4 | 5 | export const renderTasks = () => { 6 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 7 | if (!taskList) { 8 | return; 9 | } 10 | taskList.innerHTML = ''; 11 | // Loop through tasks and create taskBox element for each task 12 | toDoArray.forEach((task) => { 13 | const taskBox = document.createElement('div'); 14 | taskBox.classList = 'task-box-css'; 15 | let taskCompleted = ''; 16 | if (task.completed) taskCompleted = 'checked'; 17 | taskBox.innerHTML = ` 18 |
19 | 20 | 21 |
22 | 🗑 23 | 24 | `; 25 | taskList.appendChild(taskBox); 26 | 27 | // COMPLETED TASKS// 28 | const checkbox = taskBox.querySelector('.input-check'); 29 | checkbox.addEventListener('click', (e) => { 30 | const taskBox = e.target.parentElement.parentElement; 31 | const taskIndex = Array.from(taskBox.parentElement.children).indexOf(taskBox); 32 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 33 | toDoArray[taskIndex].completed = e.target.checked; 34 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 35 | }); 36 | }); 37 | }; 38 | renderTasks(); 39 | 40 | // ADD TASKS// 41 | export const addTask = () => { 42 | const newTask = document.querySelector('.new-task'); 43 | if (newTask.value !== '') { 44 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 45 | toDoArray.push({ completed: false, description: newTask.value, id: Date.now() }); 46 | for (let i = 1; i <= toDoArray.length; i += 1) { 47 | toDoArray[i - 1].index = i; 48 | } 49 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 50 | newTask.value = ''; 51 | renderTasks(); // 52 | } 53 | }; 54 | 55 | // DELETE TASKS// 56 | 57 | export const deleteTask = (index) => { 58 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 59 | toDoArray.splice(index, 1); 60 | for (let i = 0; i < toDoArray.length; i += 1) { 61 | toDoArray[i].index = i; 62 | } 63 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 64 | }; 65 | 66 | /// EDIT TASKS ////// 67 | 68 | export const editTask = (index) => { 69 | const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || []; 70 | const textInputs = document.querySelectorAll('.text-input'); 71 | textInputs[index].addEventListener('change', () => { 72 | toDoArray[index].description = textInputs[index].value; 73 | localStorage.setItem('toDoArray', JSON.stringify(toDoArray)); 74 | }); 75 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |

ToDo List

6 |

Readme

7 | 8 |
9 | 10 | 11 | 12 | # 📗 Table of Contents 13 | 14 | - [📖 About the Project](#about-project) 15 | - [🛠 Built With](#built-with) 16 | - [Tech Stack](#tech-stack) 17 | - [Key Features](#key-features) 18 | - [🚀 Live Demo](#live-demo) 19 | - [💻 Getting Started](#getting-started) 20 | - [Prerequisites](#prerequisites) 21 | - [Setup](#setup) 22 | - [Usage](#usage) 23 | - [Run tests](#run-tests) 24 | - [Deployment](#deployment) 25 | - [👥 Authors](#authors) 26 | - [🔭 Future Features](#future-features) 27 | - [🤝 Contributing](#contributing) 28 | - [⭐️ Show your support](#support) 29 | - [🙏 Acknowledgements](#acknowledgements) 30 | - [📝 License](#license) 31 | 32 | # 📖 To-Do-List 33 | 34 | **[To-Do-List]** Welcome to my To-Do List. A simple app that will help you organize your day! 35 | 36 | ## 🛠 Built With 37 | 38 | ### Tech Stack 39 | + Webpack 40 | + JavaScript ES6 41 | 42 | > Used HTML, CSS, JavaScript and Webpack to work on this project and Linters configuration provided by Microverse. 43 | 44 |
45 | Capstone project 46 | 49 |
50 | 51 | ### Key Features 52 | 53 | > An exercise to create simple To-Do list using Webpack! 54 | 55 | - **[Webpack]** 56 | - **[JavaScript ES6 Syntax]** 57 | - **[Modular JavaScript]** 58 | 59 | 60 |

(back to top)

61 | 62 | ## 🚀 Live Demo 63 | 64 | - [Live Demo Link](https://maedea9.github.io/to-do-list/dist/) 65 | 66 |

(back to top)

67 | 68 | ## 💻Getting Started 69 | To get a local copy up and running, follow these steps. 70 | ### Prerequisites 71 | In order to run this project you need: 72 | + Visual Studio Code 73 | + Git 74 | + Npm 75 | + Node 76 | + Webpack 77 | + Basic HTML, CSS and JavaScript knowledge 78 | 79 | ### Setup 80 | Clone this repository to your computer 81 | 82 | ### Usage 83 | To run the project, execute the "index.html" file in your browser 84 |

(back to top)

85 | 86 | ### Run tests 87 | 88 | To run tests, run the following command: 89 | 90 | ```sh 91 | To check the HTML functionality use: 'npx hint .' 92 | ``` 93 | 94 | ```sh 95 | To check the CSS functionality use: 'npx stylelint "**/*.{css,scss}"' 96 | ``` 97 | 98 | ```sh 99 | To check the JavaScript functionality use: 'npx eslint."' 100 | ``` 101 | 102 | ### Deployment 103 | 104 | You can deploy this project using: 105 | 106 | ```sh 107 | GitHub pages. 108 | ``` 109 | 110 |

(back to top)

111 | 112 | ## 👥 Authors 113 | 114 | 👤 **Maedea9** 115 | 116 | - GitHub: [@maedea9](https://github.com/Maedea9) 117 | - Twitter: [@MelanieCascant6](https://twitter.com/MelanieCascant6) 118 | - LinkedIn: [LinkedIn](https://www.linkedin.com/in/melanie-cascante-938a93228/) 119 | 120 | ## 🔭 Future Features 121 | 122 | - **-Adding transitions** : Adding styles. 123 | - **Adding drag and drop** : Adding drag and drop to order your list. 124 | 125 |

(back to top)

126 | 127 | ## 🤝 Contributing 128 | Contributions, issues, and feature requests are welcome! 129 | 130 |

(back to top)

131 | 132 | ## ⭐️ Show your support 133 | If you like this project you can follow my work through my social networks. 134 | 135 |

(back to top)

136 | 137 | ## 🙏 Acknowledgments 138 | 139 | I would like to thank Microverse, my Coding partners, Standup Team, Morning Sessions Team and my friend @danifromecuador for supporting me. 140 | 141 | 142 |

(back to top)

143 | 144 | ## 📝 License 145 | 146 | This project is [MIT](./LICENSE) licensed. 147 | 148 |

(back to top)

149 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). 3 | * This devtool is neither made for production nor for readable output files. 4 | * It uses "eval()" calls to create a separate source file in the browser devtools. 5 | * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) 6 | * or disable the default devtool with "devtool: false". 7 | * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | /******/ var __webpack_modules__ = ({ 12 | 13 | /***/ "./node_modules/css-loader/dist/cjs.js!./src/style.css": 14 | /*!*************************************************************!*\ 15 | !*** ./node_modules/css-loader/dist/cjs.js!./src/style.css ***! 16 | \*************************************************************/ 17 | /***/ ((module, __webpack_exports__, __webpack_require__) => { 18 | 19 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \"* {\\r\\n box-sizing: border-box;\\r\\n font-family: Verdana, Geneva, Tahoma, sans-serif;\\r\\n font-size: 15px;\\r\\n margin: 0;\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\nbody {\\r\\n background-color: #dee2e6;\\r\\n}\\r\\n\\r\\nh1 {\\r\\n font-size: 30px;\\r\\n text-align: center;\\r\\n margin-bottom: 2%;\\r\\n color: #0d1b2a;\\r\\n}\\r\\n\\r\\n.task-container {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-content: center;\\r\\n justify-content: center;\\r\\n width: 35%;\\r\\n margin-left: 31%;\\r\\n background-color: #fff;\\r\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\\r\\n border-radius: 3px;\\r\\n padding: 1%;\\r\\n color: #0d1b2a;\\r\\n}\\r\\n\\r\\n.new-task {\\r\\n width: 70%;\\r\\n}\\r\\n\\r\\n.task-header {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n margin-bottom: 3%;\\r\\n border-bottom: 1px #ddd solid;\\r\\n}\\r\\n\\r\\n.add-task-form {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n width: 100%;\\r\\n margin-bottom: 2%;\\r\\n padding-bottom: 2%;\\r\\n border-bottom: #ddd 1px solid;\\r\\n}\\r\\n\\r\\n.list-content {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n border-bottom: 1px #ddd solid;\\r\\n width: 100%;\\r\\n margin-bottom: 2%;\\r\\n padding-bottom: 1%;\\r\\n}\\r\\n\\r\\n.task-box-css {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n border-bottom: 1px #ddd solid;\\r\\n margin-bottom: 2.5%;\\r\\n padding-bottom: 1%;\\r\\n}\\r\\n\\r\\n.task-activity {\\r\\n width: 100%;\\r\\n}\\r\\n\\r\\n.text-input {\\r\\n width: 70%;\\r\\n}\\r\\n\\r\\n.submit {\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.trash-icon {\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.clear-tasks {\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n#clear-complete {\\r\\n width: 50%;\\r\\n height: 40px;\\r\\n outline: none;\\r\\n border: none;\\r\\n background-color: #778da9;\\r\\n padding-inline: 2px;\\r\\n font-size: 1em;\\r\\n cursor: pointer;\\r\\n color: #0d1b2a;\\r\\n}\\r\\n\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://to-do-list/./src/style.css?./node_modules/css-loader/dist/cjs.js"); 20 | 21 | /***/ }), 22 | 23 | /***/ "./node_modules/css-loader/dist/runtime/api.js": 24 | /*!*****************************************************!*\ 25 | !*** ./node_modules/css-loader/dist/runtime/api.js ***! 26 | \*****************************************************/ 27 | /***/ ((module) => { 28 | 29 | eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};\n\n//# sourceURL=webpack://to-do-list/./node_modules/css-loader/dist/runtime/api.js?"); 30 | 31 | /***/ }), 32 | 33 | /***/ "./node_modules/css-loader/dist/runtime/noSourceMaps.js": 34 | /*!**************************************************************!*\ 35 | !*** ./node_modules/css-loader/dist/runtime/noSourceMaps.js ***! 36 | \**************************************************************/ 37 | /***/ ((module) => { 38 | 39 | eval("\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n//# sourceURL=webpack://to-do-list/./node_modules/css-loader/dist/runtime/noSourceMaps.js?"); 40 | 41 | /***/ }), 42 | 43 | /***/ "./src/style.css": 44 | /*!***********************!*\ 45 | !*** ./src/style.css ***! 46 | \***********************/ 47 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 48 | 49 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../node_modules/css-loader/dist/cjs.js!./style.css */ \"./node_modules/css-loader/dist/cjs.js!./src/style.css\");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_style_css__WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://to-do-list/./src/style.css?"); 50 | 51 | /***/ }), 52 | 53 | /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 54 | /*!****************************************************************************!*\ 55 | !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 56 | \****************************************************************************/ 57 | /***/ ((module) => { 58 | 59 | eval("\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?"); 60 | 61 | /***/ }), 62 | 63 | /***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js": 64 | /*!********************************************************************!*\ 65 | !*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***! 66 | \********************************************************************/ 67 | /***/ ((module) => { 68 | 69 | eval("\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/insertBySelector.js?"); 70 | 71 | /***/ }), 72 | 73 | /***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js": 74 | /*!**********************************************************************!*\ 75 | !*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***! 76 | \**********************************************************************/ 77 | /***/ ((module) => { 78 | 79 | eval("\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/insertStyleElement.js?"); 80 | 81 | /***/ }), 82 | 83 | /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js": 84 | /*!**********************************************************************************!*\ 85 | !*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***! 86 | \**********************************************************************************/ 87 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => { 88 | 89 | eval("\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?"); 90 | 91 | /***/ }), 92 | 93 | /***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js": 94 | /*!***************************************************************!*\ 95 | !*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***! 96 | \***************************************************************/ 97 | /***/ ((module) => { 98 | 99 | eval("\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/styleDomAPI.js?"); 100 | 101 | /***/ }), 102 | 103 | /***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js": 104 | /*!*********************************************************************!*\ 105 | !*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***! 106 | \*********************************************************************/ 107 | /***/ ((module) => { 108 | 109 | eval("\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack://to-do-list/./node_modules/style-loader/dist/runtime/styleTagTransform.js?"); 110 | 111 | /***/ }), 112 | 113 | /***/ "./src/index.js": 114 | /*!**********************!*\ 115 | !*** ./src/index.js ***! 116 | \**********************/ 117 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 118 | 119 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./style.css */ \"./src/style.css\");\n/* harmony import */ var _modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/functionality.js */ \"./src/modules/functionality.js\");\n/* harmony import */ var _modules_interactivity_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/interactivity.js */ \"./src/modules/interactivity.js\");\n\n\n\n\n\n\n// ADD TASKS//\n\nconst addButton = document.querySelector('.submit'); // clicking add button\naddButton.addEventListener('click', () => {\n (0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.addTask)();\n // renderTasks();\n});\n\nconst taskInput = document.getElementById('taskInput');\ntaskInput.addEventListener('keypress', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault(); // prevents page to reload when enter is pressed\n (0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.addTask)();\n // renderTasks();\n }\n});\n\n(0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.renderTasks)();\n\n// DELETE TASKS//\n\nconst listContainer = document.querySelector('.list-content');\n\nlistContainer.addEventListener('click', (event) => {\n const removeTask = event.target.closest('.trash-icon');\n if (removeTask) {\n const trashIcons = listContainer.querySelectorAll('.trash-icon');\n const index = Array.from(trashIcons).indexOf(removeTask);\n (0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.deleteTask)(index);\n (0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.renderTasks)();\n }\n});\n\n// EDIT TASKS //\n\n// add event listener for editing a task//\nlistContainer.addEventListener('click', (event) => {\n const textInput = event.target.closest('.text-input');\n if (textInput) {\n const textInputs = listContainer.querySelectorAll('.text-input');\n const index = Array.from(textInputs).indexOf(textInput);\n (0,_modules_interactivity_js__WEBPACK_IMPORTED_MODULE_2__.editTask)(index);\n }\n});\n\n// CLEAR ALL COMPLETED //\n\nconst clearButton = document.getElementById('clear-complete');\nclearButton.addEventListener('click', () => {\n (0,_modules_interactivity_js__WEBPACK_IMPORTED_MODULE_2__.clearAllCompleted)();\n (0,_modules_functionality_js__WEBPACK_IMPORTED_MODULE_1__.renderTasks)();\n});\n\n\n//# sourceURL=webpack://to-do-list/./src/index.js?"); 120 | 121 | /***/ }), 122 | 123 | /***/ "./src/modules/functionality.js": 124 | /*!**************************************!*\ 125 | !*** ./src/modules/functionality.js ***! 126 | \**************************************/ 127 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 128 | 129 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"addTask\": () => (/* binding */ addTask),\n/* harmony export */ \"deleteTask\": () => (/* binding */ deleteTask),\n/* harmony export */ \"editTask\": () => (/* binding */ editTask),\n/* harmony export */ \"renderTasks\": () => (/* binding */ renderTasks)\n/* harmony export */ });\n/// RENDER TASKS///\n\nconst taskList = document.getElementById('taskList');\n\nconst renderTasks = () => {\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n taskList.innerHTML = '';\n // Loop through tasks and create taskBox element for each task\n toDoArray.forEach((task) => {\n const taskBox = document.createElement('div');\n taskBox.classList = 'task-box-css';\n let taskCompleted = '';\n if (task.completed) taskCompleted = 'checked';\n taskBox.innerHTML = `
\n \n \n
\n 🗑\n `;\n taskList.appendChild(taskBox);\n\n // COMPLETED TASKS//\n const checkbox = taskBox.querySelector('.input-check');\n checkbox.addEventListener('click', (e) => {\n const taskBox = e.target.parentElement.parentElement;\n const taskIndex = Array.from(taskBox.parentElement.children).indexOf(taskBox);\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n toDoArray[taskIndex].completed = e.target.checked;\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n });\n });\n};\nrenderTasks();\n\n// ADD TASKS//\n\nconst newTask = document.querySelector('.new-task');\nconst addTask = () => {\n if (newTask.value !== '') {\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n toDoArray.push({ completed: false, description: newTask.value, id: Date.now() });\n for (let i = 1; i <= toDoArray.length; i += 1) {\n toDoArray[i - 1].index = i;\n }\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n newTask.value = '';\n renderTasks(); //\n }\n};\n\n// DELETE TASKS//\n\nconst deleteTask = (index) => {\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n toDoArray.splice(index, 1);\n for (let i = 0; i < toDoArray.length; i += 1) {\n toDoArray[i].index = i;\n }\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n};\n\n/// EDIT TASKS //////\n\nconst editTask = (index) => {\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n const textInputs = document.querySelectorAll('.text-input');\n textInputs[index].addEventListener('change', () => {\n toDoArray[index].description = textInputs[index].value;\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n });\n};\n\n\n\n//# sourceURL=webpack://to-do-list/./src/modules/functionality.js?"); 130 | 131 | /***/ }), 132 | 133 | /***/ "./src/modules/interactivity.js": 134 | /*!**************************************!*\ 135 | !*** ./src/modules/interactivity.js ***! 136 | \**************************************/ 137 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 138 | 139 | eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"clearAllCompleted\": () => (/* binding */ clearAllCompleted),\n/* harmony export */ \"editTask\": () => (/* binding */ editTask)\n/* harmony export */ });\n// // CLEAR ALL COMPLETED//\n\nconst clearAllCompleted = () => {\n let toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n toDoArray = toDoArray.filter((task) => !task.completed);\n toDoArray = toDoArray.map((task, index) => {\n task.index = index + 1;\n return task;\n });\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n};\n/// EDIT TASKS //////\n\nconst editTask = (index) => {\n const toDoArray = JSON.parse(localStorage.getItem('toDoArray')) || [];\n const textInputs = document.querySelectorAll('.text-input');\n textInputs[index].addEventListener('change', () => {\n toDoArray[index].description = textInputs[index].value;\n localStorage.setItem('toDoArray', JSON.stringify(toDoArray));\n });\n};\n\n\n\n\n//# sourceURL=webpack://to-do-list/./src/modules/interactivity.js?"); 140 | 141 | /***/ }) 142 | 143 | /******/ }); 144 | /************************************************************************/ 145 | /******/ // The module cache 146 | /******/ var __webpack_module_cache__ = {}; 147 | /******/ 148 | /******/ // The require function 149 | /******/ function __webpack_require__(moduleId) { 150 | /******/ // Check if module is in cache 151 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; 152 | /******/ if (cachedModule !== undefined) { 153 | /******/ return cachedModule.exports; 154 | /******/ } 155 | /******/ // Create a new module (and put it into the cache) 156 | /******/ var module = __webpack_module_cache__[moduleId] = { 157 | /******/ id: moduleId, 158 | /******/ // no module.loaded needed 159 | /******/ exports: {} 160 | /******/ }; 161 | /******/ 162 | /******/ // Execute the module function 163 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 164 | /******/ 165 | /******/ // Return the exports of the module 166 | /******/ return module.exports; 167 | /******/ } 168 | /******/ 169 | /************************************************************************/ 170 | /******/ /* webpack/runtime/compat get default export */ 171 | /******/ (() => { 172 | /******/ // getDefaultExport function for compatibility with non-harmony modules 173 | /******/ __webpack_require__.n = (module) => { 174 | /******/ var getter = module && module.__esModule ? 175 | /******/ () => (module['default']) : 176 | /******/ () => (module); 177 | /******/ __webpack_require__.d(getter, { a: getter }); 178 | /******/ return getter; 179 | /******/ }; 180 | /******/ })(); 181 | /******/ 182 | /******/ /* webpack/runtime/define property getters */ 183 | /******/ (() => { 184 | /******/ // define getter functions for harmony exports 185 | /******/ __webpack_require__.d = (exports, definition) => { 186 | /******/ for(var key in definition) { 187 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 188 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 189 | /******/ } 190 | /******/ } 191 | /******/ }; 192 | /******/ })(); 193 | /******/ 194 | /******/ /* webpack/runtime/hasOwnProperty shorthand */ 195 | /******/ (() => { 196 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 197 | /******/ })(); 198 | /******/ 199 | /******/ /* webpack/runtime/make namespace object */ 200 | /******/ (() => { 201 | /******/ // define __esModule on exports 202 | /******/ __webpack_require__.r = (exports) => { 203 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 204 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 205 | /******/ } 206 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 207 | /******/ }; 208 | /******/ })(); 209 | /******/ 210 | /******/ /* webpack/runtime/nonce */ 211 | /******/ (() => { 212 | /******/ __webpack_require__.nc = undefined; 213 | /******/ })(); 214 | /******/ 215 | /************************************************************************/ 216 | /******/ 217 | /******/ // startup 218 | /******/ // Load entry module and return exports 219 | /******/ // This entry module can't be inlined because the eval devtool is used. 220 | /******/ var __webpack_exports__ = __webpack_require__("./src/index.js"); 221 | /******/ 222 | /******/ })() 223 | ; --------------------------------------------------------------------------------