diff --git a/dist/index.html b/dist/index.html index bf66122..1d7e8fa 100644 --- a/dist/index.html +++ b/dist/index.html @@ -4,22 +4,23 @@ Output Management + -
TODOs
+

TODOs Manager

-
+
-

Todos

+

Todos

- + - +
@@ -45,7 +46,7 @@

Todos

Title
-
+ diff --git a/dist/main.js b/dist/main.js index 8174f09..cb95685 100644 --- a/dist/main.js +++ b/dist/main.js @@ -36,7 +36,7 @@ eval("/*!\n * Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com\ /***/ ((module, __webpack_exports__, __webpack_require__) => { "use strict"; -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, \"body {\\r\\n background-color: red;\\r\\n height: 100vh;\\r\\n display: grid;\\r\\n grid-template-columns: 1fr 4fr;\\r\\n grid-template-rows: 1fr 3fr 1fr;\\r\\n font-family: monospace;\\r\\n}\\r\\n\\r\\nheader {\\r\\n background-color: aliceblue;\\r\\n grid-column: 1/3;\\r\\n grid-row: 1/2;\\r\\n}\\r\\n\\r\\naside {\\r\\n grid-column: 1/2;\\r\\n grid-row: 2/3;\\r\\n}\\r\\n.content {\\r\\n background-color: coral;\\r\\n grid-column: 2/3;\\r\\n grid-row: 2/3;\\r\\n}\\r\\n\\r\\nfooter {\\r\\n background-color: aqua;\\r\\n grid-column: 1/3;\\r\\n grid-row: 3/4;\\r\\n}\\r\\n\\r\\n.popup {\\r\\n display: none;\\r\\n}\\r\\n\\r\\n.active {\\r\\n display: block;\\r\\n}\\r\\n\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://todo/./src/style.css?./node_modules/css-loader/dist/cjs.js"); +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, \":root {\\r\\n --body-color: #e63946;\\r\\n --header-color: #1d3557;\\r\\n --footer-color: #1d3557 ;\\r\\n --aside-color: #f1faee;\\r\\n --content-color: #f1faee;\\r\\n}\\r\\n\\r\\n* {\\r\\n padding: 0;\\r\\n margin: 0;\\r\\n box-sizing: border-box;\\r\\n}\\r\\n\\r\\nbody {\\r\\n background-color: var(--body-color);\\r\\n height: 100vh;\\r\\n width: 100vw;\\r\\n display: grid;\\r\\n grid-template-columns: 1fr 4fr;\\r\\n grid-template-rows: .5fr 3fr .5fr;\\r\\n font-family: monospace;\\r\\n}\\r\\n\\r\\nheader, aside, .content, footer {\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\n\\r\\n\\r\\nbutton {\\r\\n padding: 10px;\\r\\n border: none;\\r\\n}\\r\\n\\r\\nheader {\\r\\n color: white;\\r\\n background-color: var(--header-color);\\r\\n font-size: x-large;\\r\\n grid-column: 1/3;\\r\\n grid-row: 1/2;\\r\\n}\\r\\n\\r\\naside {\\r\\n background-color: var(--aside-color);\\r\\n grid-column: 1/2;\\r\\n grid-row: 2/3;\\r\\n}\\r\\n\\r\\nul {\\r\\n list-style-type: none;\\r\\n}\\r\\n\\r\\nli {\\r\\n margin: 0;\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n}\\r\\n\\r\\n.content {\\r\\n padding-left: 1rem;\\r\\n background-color: var(--content-color);\\r\\n grid-column: 2/3;\\r\\n grid-row: 2/3;\\r\\n}\\r\\n\\r\\nfooter {\\r\\n color: white;\\r\\n background-color: var(--footer-color);\\r\\n grid-column: 1/3;\\r\\n grid-row: 3/4;\\r\\n}\\r\\n\\r\\n.popup {\\r\\n display: none;\\r\\n}\\r\\n\\r\\n.active {\\r\\n display: block;\\r\\n}\\r\\n\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://todo/./src/style.css?./node_modules/css-loader/dist/cjs.js"); /***/ }), @@ -157,7 +157,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _sty /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Controller\": () => (/* binding */ Controller)\n/* harmony export */ });\n/* harmony import */ var _view__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./view */ \"./src/modules/view.js\");\n/* harmony import */ var _model_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./model.js */ \"./src/modules/model.js\");\n/* harmony import */ var _entities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./entities */ \"./src/modules/entities.js\");\n\r\n\r\n\r\n\r\nclass Controller {\r\n model;\r\n view;\r\n todoInputField;\r\n addTodoButton;\r\n projectInputField;\r\n addProjectButton;\r\n currentProjectId;\r\n allCurrentProjects;\r\n showPopupButton;\r\n popup;\r\n todoDate;\r\n todoPrio;\r\n isUpdate;\r\n idToUpdate;\r\n\r\n constructor() {\r\n this.model = new _model_js__WEBPACK_IMPORTED_MODULE_1__.Model();\r\n this.view = new _view__WEBPACK_IMPORTED_MODULE_0__.View();\r\n this.todoInputField = document.querySelector(\"#todoInputField\");\r\n this.addTodoButton = document.querySelector(\".addTodoButton\");\r\n this.projectInputField = document.querySelector(\"#projectsInputField\");\r\n this.addProjectButton = document.querySelector(\".addProjectButton\");\r\n this.currentProjectId = 0;\r\n this.showPopupButton = document.querySelector(\".showPopupButton\");\r\n this.popup = document.querySelector(\".popup\");\r\n this.todoDate = document.querySelector(\"#dateInput\");\r\n this.todoPrio = document.querySelector(\"#prio\");\r\n this.isUpdate = false;\r\n this.idToUpdate = -1;\r\n }\r\n\r\n initializeUI() {\r\n // Load stored data when the page is first loaded\r\n let data = this.getData();\r\n if(data){\r\n console.log(\"There is data\");\r\n this.model.revive(data);\r\n } else {\r\n console.log(\"There is NO data\");\r\n }\r\n let currentProjects = this.model.getProjects();\r\n console.log(currentProjects);\r\n this.view.displayProjects(currentProjects);\r\n this.listenForProjects();\r\n this.listenForProjectAdd();\r\n this.listenForTodoAdd();\r\n this.listenForShowPopupButton();\r\n }\r\n\r\n // Store data whenever a project or todo is added\r\n saveData() {\r\n let data = JSON.stringify(this.model.getProjects());\r\n console.log(`stringified data: ${data}`);\r\n localStorage.setItem(\"projects\", data);\r\n }\r\n\r\n getData() {\r\n let data = localStorage.getItem(\"projects\"); \r\n return JSON.parse(data);\r\n }\r\n\r\n\r\n\r\n listenForProjects() {\r\n this.allCurrentProjects = Array.from(document.querySelectorAll(\"li\"));\r\n this.allCurrentProjects?.forEach((project) => {\r\n project.addEventListener(\"click\", (e) => {\r\n this.currentProjectId = e.target.getAttribute(\"id\");\r\n // Display all todos for active project\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.listenForTodos();\r\n this.listenForEdit();\r\n this.listenForDelete();\r\n });\r\n });\r\n }\r\n\r\n listenForProjectAdd() {\r\n this.addProjectButton.addEventListener(\"click\", () => {\r\n this.addProjectHelper();\r\n });\r\n // Add keyboard listener but to the input field not to the projects themselves\r\n this.projectInputField.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n this.addProjectHelper();\r\n }\r\n });\r\n }\r\n\r\n addProjectHelper() {\r\n let projectTitle = this.projectInputField.value;\r\n this.model.addProject(projectTitle);\r\n this.view.displayProjects(this.model.getProjects());\r\n // Save your current data\r\n this.saveData();\r\n this.listenForProjects();\r\n this.listenForDescriptions();\r\n this.listenForEdit();\r\n }\r\n\r\n listenForTodoAdd() {\r\n this.addTodoButton.addEventListener(\"click\", () => {\r\n this.addTodoHelper();\r\n });\r\n // Listen for keypress also\r\n this.todoInputField.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n this.addTodoHelper();\r\n }\r\n });\r\n }\r\n\r\n addTodoHelper() {\r\n let todoTitle = this.todoInputField.value;\r\n let todoDate = this.todoDate.value;\r\n let todoPrio = this.todoPrio.value;\r\n if(this.isUpdate){\r\n // If we update dont create a new todo but overwrite the old one\r\n // The id of the todo to update is saved in a global variable\r\n // Also get the description as the popup is showing at this flow\r\n let todoDescription = document.querySelector(`tr[id='${this.idToUpdate}']`).nextElementSibling.firstElementChild.firstElementChild.value;\r\n this.model.updateTodo(this.currentProjectId, this.idToUpdate, todoTitle, todoDate, todoPrio, todoDescription); \r\n this.isUpdate=false;\r\n } else {\r\n this.model.addTodoToProject(\r\n this.currentProjectId,\r\n todoTitle,\r\n todoDate,\r\n todoPrio\r\n );\r\n }\r\n // Display all todos after the change\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.popup.classList.remove(\"active\");\r\n this.listenForDescriptions();\r\n this.listenForTodos();\r\n this.listenForDelete();\r\n this.listenForEdit();\r\n // Save the current data\r\n this.saveData();\r\n }\r\n\r\n // Listen for delete icon\r\n listenForDelete() {\r\n const deleteIcons = Array.from(document.querySelectorAll(\".trash-icon\"));\r\n deleteIcons.forEach((icon) => {\r\n icon.parentNode.addEventListener(\"click\", () => {\r\n // Get id of corresponding todo\r\n let thisTodoId =\r\n +icon.parentNode.parentNode.previousElementSibling.getAttribute(\"id\");\r\n this.model.getProject(this.currentProjectId).deleteTodo(thisTodoId);\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.saveData();\r\n });\r\n });\r\n }\r\n\r\n listenForEdit(){\r\n const editIcons = Array.from(document.querySelectorAll(\".edit-icon\"));\r\n editIcons.forEach((icon)=>{\r\n icon.addEventListener(\"click\", ()=>{\r\n // Set the global update flag to true so the add button handlers can know. \r\n this.isUpdate=true;\r\n // Get id of todo to edit and save it in global variable\r\n this.idToUpdate =\r\n +icon.parentNode.parentNode.previousElementSibling.getAttribute(\"id\");\r\n // Get data from the popup + descr\r\n this.popup.classList.add(\"active\");\r\n })\r\n })\r\n }\r\n\r\n listenForTodos() {\r\n const todos = Array.from(document.querySelectorAll(\"tr[id]\"));\r\n todos.forEach((todo) => {\r\n todo.addEventListener(\"click\", () => {\r\n todo.nextElementSibling.classList.toggle(\"popup\");\r\n this.listenForDescriptions();\r\n });\r\n });\r\n }\r\n\r\n listenForShowPopupButton() {\r\n this.showPopupButton.addEventListener(\"click\", () => {\r\n this.popup.classList.add(\"active\");\r\n });\r\n }\r\n\r\n listenForDescriptions() {\r\n const descriptions = Array.from(document.querySelectorAll(\"textarea\"));\r\n descriptions.forEach((description) => {\r\n description.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n // Save the description in the corresponding todo\r\n let correspondingTodoId =\r\n e.target.parentNode.parentNode.previousElementSibling.getAttribute(\r\n \"id\"\r\n );\r\n this.model.addDescriptionToTodo(\r\n this.currentProjectId,\r\n correspondingTodoId,\r\n e.target.value\r\n );\r\n // Save the description\r\n this.saveData();\r\n }\r\n });\r\n });\r\n }\r\n\r\n\r\n\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/controller.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Controller\": () => (/* binding */ Controller)\n/* harmony export */ });\n/* harmony import */ var _view__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./view */ \"./src/modules/view.js\");\n/* harmony import */ var _model_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./model.js */ \"./src/modules/model.js\");\n/* harmony import */ var _entities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./entities */ \"./src/modules/entities.js\");\n\r\n\r\n\r\n\r\nclass Controller {\r\n model;\r\n view;\r\n todoInputField;\r\n addTodoButton;\r\n projectInputField;\r\n addProjectButton;\r\n currentProjectId;\r\n allCurrentProjects;\r\n showPopupButton;\r\n popup;\r\n todoDate;\r\n todoPrio;\r\n isUpdate;\r\n idToUpdate;\r\n\r\n constructor() {\r\n this.model = new _model_js__WEBPACK_IMPORTED_MODULE_1__.Model();\r\n this.view = new _view__WEBPACK_IMPORTED_MODULE_0__.View();\r\n this.todoInputField = document.querySelector(\"#todoInputField\");\r\n this.addTodoButton = document.querySelector(\".addTodoButton\");\r\n this.projectInputField = document.querySelector(\"#projectsInputField\");\r\n this.addProjectButton = document.querySelector(\".addProjectButton\");\r\n this.currentProjectId = 0;\r\n this.showPopupButton = document.querySelector(\".showPopupButton\");\r\n this.popup = document.querySelector(\".popup\");\r\n this.todoDate = document.querySelector(\"#dateInput\");\r\n this.todoPrio = document.querySelector(\"#prio\");\r\n this.isUpdate = false;\r\n this.idToUpdate = -1;\r\n }\r\n\r\n initializeUI() {\r\n // Load stored data when the page is first loaded\r\n let data = this.getData();\r\n if (data) {\r\n console.log(\"There is data\");\r\n this.model.revive(data);\r\n } else {\r\n console.log(\"There is NO data\");\r\n }\r\n let currentProjects = this.model.getProjects();\r\n console.log(currentProjects);\r\n this.view.displayProjects(currentProjects);\r\n this.listenForProjects();\r\n this.listenForProjectAdd();\r\n this.listenForTodoAdd();\r\n this.listenForShowPopupButton();\r\n }\r\n\r\n // Store data whenever a project or todo is added\r\n saveData() {\r\n let data = JSON.stringify(this.model.getProjects());\r\n console.log(`stringified data: ${data}`);\r\n localStorage.setItem(\"projects\", data);\r\n }\r\n\r\n getData() {\r\n let data = localStorage.getItem(\"projects\");\r\n return JSON.parse(data);\r\n }\r\n\r\n listenForProjects() {\r\n this.allCurrentProjects = Array.from(document.querySelectorAll(\"li\"));\r\n this.allCurrentProjects?.forEach((project) => {\r\n project.addEventListener(\"click\", (e) => {\r\n // Check if user clicked on delete div\r\n if (e.target.tagName === \"svg\") {\r\n this.model.deleteProject(this.currentProjectId);\r\n this.view.displayProjects(this.model.getProjects());\r\n this.listenForProjects();\r\n this.saveData();\r\n }\r\n this.currentProjectId = e.currentTarget.getAttribute(\"id\");\r\n // Display all todos for active project\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.listenForTodos();\r\n this.listenForEdit();\r\n this.listenForDelete();\r\n });\r\n });\r\n }\r\n\r\n listenForProjectAdd() {\r\n this.addProjectButton.addEventListener(\"click\", () => {\r\n this.addProjectHelper();\r\n });\r\n // Add keyboard listener but to the input field not to the projects themselves\r\n this.projectInputField.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n this.addProjectHelper();\r\n }\r\n });\r\n }\r\n\r\n addProjectHelper() {\r\n let projectTitle = this.projectInputField.value;\r\n this.model.addProject(projectTitle);\r\n this.view.displayProjects(this.model.getProjects());\r\n // Save your current data\r\n this.saveData();\r\n this.listenForProjects();\r\n this.listenForDescriptions();\r\n this.listenForEdit();\r\n }\r\n\r\n listenForTodoAdd() {\r\n this.addTodoButton.addEventListener(\"click\", () => {\r\n this.addTodoHelper();\r\n });\r\n // Listen for keypress also\r\n this.todoInputField.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n this.addTodoHelper();\r\n }\r\n });\r\n }\r\n\r\n addTodoHelper() {\r\n let todoTitle = this.todoInputField.value;\r\n let todoDate = this.todoDate.value;\r\n let todoPrio = this.todoPrio.value;\r\n if (this.isUpdate) {\r\n // If we update dont create a new todo but overwrite the old one\r\n // The id of the todo to update is saved in a global variable\r\n // Also get the description as the popup is showing at this flow\r\n let todoDescription = document.querySelector(\r\n `tr[id='${this.idToUpdate}']`\r\n ).nextElementSibling.firstElementChild.firstElementChild.value;\r\n this.model.updateTodo(\r\n this.currentProjectId,\r\n this.idToUpdate,\r\n todoTitle,\r\n todoDate,\r\n todoPrio,\r\n todoDescription\r\n );\r\n this.isUpdate = false;\r\n } else {\r\n this.model.addTodoToProject(\r\n this.currentProjectId,\r\n todoTitle,\r\n todoDate,\r\n todoPrio\r\n );\r\n }\r\n // Display all todos after the change\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.popup.classList.remove(\"active\");\r\n this.listenForDescriptions();\r\n this.listenForTodos();\r\n this.listenForDelete();\r\n this.listenForEdit();\r\n // Save the current data\r\n this.saveData();\r\n }\r\n\r\n // Listen for delete icon\r\n listenForDelete() {\r\n const deleteIcons = Array.from(document.querySelectorAll(\".trash-icon\"));\r\n deleteIcons.forEach((icon) => {\r\n icon.parentNode.addEventListener(\"click\", () => {\r\n // Get id of corresponding todo\r\n let thisTodoId =\r\n +icon.parentNode.parentNode.previousElementSibling.getAttribute(\"id\");\r\n this.model.getProject(this.currentProjectId).deleteTodo(thisTodoId);\r\n this.view.displayTodos(\r\n this.model.getProject(this.currentProjectId).getTodos()\r\n );\r\n this.listenForTodos();\r\n this.listenForEdit();\r\n this.saveData();\r\n });\r\n });\r\n }\r\n\r\n listenForEdit() {\r\n const editIcons = Array.from(document.querySelectorAll(\".edit-icon\"));\r\n editIcons.forEach((icon) => {\r\n icon.addEventListener(\"click\", () => {\r\n // Set the global update flag to true so the add button handlers can know.\r\n this.isUpdate = true;\r\n // Get id of todo to edit and save it in global variable\r\n this.idToUpdate =\r\n +icon.parentNode.parentNode.previousElementSibling.getAttribute(\"id\");\r\n // Get data from the popup + descr\r\n this.popup.classList.add(\"active\");\r\n });\r\n });\r\n }\r\n\r\n listenForTodos() {\r\n const todos = Array.from(document.querySelectorAll(\"tr[id]\"));\r\n todos.forEach((todo) => {\r\n todo.addEventListener(\"click\", () => {\r\n todo.nextElementSibling.classList.toggle(\"popup\");\r\n this.listenForDescriptions();\r\n });\r\n });\r\n }\r\n\r\n listenForShowPopupButton() {\r\n this.showPopupButton.addEventListener(\"click\", () => {\r\n this.popup.classList.add(\"active\");\r\n });\r\n }\r\n\r\n listenForDescriptions() {\r\n const descriptions = Array.from(document.querySelectorAll(\"textarea\"));\r\n descriptions.forEach((description) => {\r\n description.addEventListener(\"keypress\", (e) => {\r\n if (e.key === \"Enter\") {\r\n // Save the description in the corresponding todo\r\n let correspondingTodoId =\r\n e.target.parentNode.parentNode.previousElementSibling.getAttribute(\r\n \"id\"\r\n );\r\n this.model.addDescriptionToTodo(\r\n this.currentProjectId,\r\n correspondingTodoId,\r\n e.target.value\r\n );\r\n // Save the description\r\n this.saveData();\r\n }\r\n });\r\n });\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/controller.js?"); /***/ }), @@ -168,7 +168,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Project\": () => (/* binding */ Project),\n/* harmony export */ \"Todo\": () => (/* binding */ Todo)\n/* harmony export */ });\nclass Todo {\r\n static id = 0;\r\n title;\r\n due;\r\n prio;\r\n description;\r\n\r\n constructor(title, due, prio) {\r\n this.id = ++Todo.id;\r\n this.title = title;\r\n this.due = due;\r\n this.prio = prio;\r\n }\r\n\r\n setId(id){\r\n this.id = id;\r\n }\r\n\r\n getId(){\r\n return this.id;\r\n }\r\n\r\n setDescription(text){\r\n this.description=text;\r\n console.log(this.description);\r\n }\r\n\r\n getDescription(){\r\n return this.description;\r\n }\r\n\r\n setTitle(title) {\r\n this.title = title;\r\n }\r\n\r\n getTitle() {\r\n return this.title;\r\n }\r\n\r\n\r\n setDue(due) {\r\n this.due = due;\r\n }\r\n\r\n getDue() {\r\n return this.due;\r\n }\r\n\r\n setPriority(prio) {\r\n this.prio = prio;\r\n }\r\n\r\n getPrio() {\r\n return this.prio;\r\n }\r\n}\r\n\r\nclass Project {\r\n title;\r\n todoList = [];\r\n\r\n constructor(title){\r\n this.title = title;\r\n }\r\n\r\n setTitle(title){\r\n this.title = title;\r\n }\r\n\r\n getTitle(){\r\n return this.title;\r\n }\r\n\r\n addTodo(title,due,prio){\r\n this.todoList.push(new Todo(title,due,prio));\r\n }\r\n\r\n addRevivedTodo(todo){\r\n this.todoList.push(todo);\r\n }\r\n\r\n getTodo(id){\r\n return this.todoList[id];\r\n }\r\n\r\n setTodo(id, title, due, prio, description){\r\n this.todoList[id].setTitle(title);\r\n this.todoList[id].setDue(due);\r\n this.todoList[id].setPriority(prio);\r\n this.todoList[id].setDescription(description);\r\n }\r\n\r\n getTodos(){\r\n return this.todoList;\r\n }\r\n\r\n deleteTodo(id){\r\n this.todoList.splice(id,1);\r\n }\r\n}\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/entities.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Project\": () => (/* binding */ Project),\n/* harmony export */ \"Todo\": () => (/* binding */ Todo)\n/* harmony export */ });\nclass Todo {\r\n static id = 0;\r\n title;\r\n due;\r\n prio;\r\n description;\r\n\r\n constructor(title, due, prio) {\r\n this.id = ++Todo.id;\r\n this.title = title;\r\n this.due = due;\r\n this.prio = prio;\r\n }\r\n\r\n setId(id){\r\n this.id = id;\r\n }\r\n\r\n getId(){\r\n return this.id;\r\n }\r\n\r\n setDescription(text){\r\n this.description=text;\r\n }\r\n\r\n getDescription(){\r\n return this.description;\r\n }\r\n\r\n setTitle(title) {\r\n this.title = title;\r\n }\r\n\r\n getTitle() {\r\n return this.title;\r\n }\r\n\r\n\r\n setDue(due) {\r\n this.due = due;\r\n }\r\n\r\n getDue() {\r\n return this.due;\r\n }\r\n\r\n setPriority(prio) {\r\n this.prio = prio;\r\n }\r\n\r\n getPrio() {\r\n return this.prio;\r\n }\r\n}\r\n\r\nclass Project {\r\n title;\r\n static id = 0;\r\n todoList = [];\r\n\r\n constructor(title){\r\n this.title = title;\r\n this.id = ++Project.id;\r\n }\r\n\r\n setId(id){\r\n this.id = id;\r\n }\r\n\r\n getId(){\r\n return this.id;\r\n }\r\n\r\n setTitle(title){\r\n this.title = title;\r\n }\r\n\r\n getTitle(){\r\n return this.title;\r\n }\r\n\r\n addTodo(title,due,prio){\r\n this.todoList.push(new Todo(title,due,prio));\r\n }\r\n\r\n addRevivedTodo(todo){\r\n this.todoList.push(todo);\r\n }\r\n\r\n getTodo(id){\r\n return this.todoList[id];\r\n }\r\n\r\n setTodo(id, title, due, prio, description){\r\n this.todoList[id].setTitle(title);\r\n this.todoList[id].setDue(due);\r\n this.todoList[id].setPriority(prio);\r\n this.todoList[id].setDescription(description);\r\n }\r\n\r\n getTodos(){\r\n return this.todoList;\r\n }\r\n\r\n deleteTodo(id){\r\n this.todoList.splice(id,1);\r\n }\r\n}\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/entities.js?"); /***/ }), @@ -179,7 +179,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Model\": () => (/* binding */ Model)\n/* harmony export */ });\n/* harmony import */ var _entities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./entities */ \"./src/modules/entities.js\");\n\r\n\r\nclass Model {\r\n projectList;\r\n\r\n constructor() {\r\n const defaultProject = new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(\"default\");\r\n this.projectList = [defaultProject];\r\n }\r\n\r\n revive(data) {\r\n // When reviving empty the plist we dont want duplicate defautl\r\n this.projectList = [];\r\n data.forEach((project) => {\r\n this.reviveProject(project);\r\n });\r\n }\r\n\r\n reviveProject(project) {\r\n const newProject = new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(project.title);\r\n // revive and add its todos\r\n project.todoList.forEach((todo) => {\r\n newProject.addRevivedTodo(this.reviveTodo(todo));\r\n });\r\n this.addRevivedProject(newProject);\r\n }\r\n\r\n reviveTodo(todo) {\r\n let newTodo = new _entities__WEBPACK_IMPORTED_MODULE_0__.Todo(todo.title, todo.due, todo.prio);\r\n newTodo.setId(todo.id);\r\n newTodo.setDescription(todo.description);\r\n return newTodo;\r\n }\r\n\r\n addRevivedProject(project) {\r\n this.projectList.push(project);\r\n }\r\n\r\n addProject(title) {\r\n this.projectList.push(new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(title));\r\n }\r\n\r\n getProject(id) {\r\n return this.projectList[id];\r\n }\r\n\r\n getProjects() {\r\n return this.projectList;\r\n }\r\n\r\n addTodoToProject(id, title, due, prio) {\r\n this.projectList[id].addTodo(title, due, prio);\r\n\r\n }\r\n\r\n addDescriptionToTodo(projectId, todoId, text) {\r\n this.projectList[projectId].getTodo(todoId).setDescription(text);\r\n }\r\n\r\n updateTodo(projectId, todoId, title, due, prio, description) {\r\n this.projectList[projectId].setTodo(todoId, title, due, prio, description);\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/model.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Model\": () => (/* binding */ Model)\n/* harmony export */ });\n/* harmony import */ var _entities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./entities */ \"./src/modules/entities.js\");\n\r\n\r\nclass Model {\r\n projectList;\r\n\r\n constructor() {\r\n const defaultProject = new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(\"default\");\r\n this.projectList = [defaultProject];\r\n }\r\n\r\n revive(data) {\r\n // When reviving empty the plist we dont want duplicate defautl\r\n this.projectList = [];\r\n data.forEach((project) => {\r\n this.reviveProject(project);\r\n });\r\n }\r\n\r\n reviveProject(project) {\r\n const newProject = new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(project.title);\r\n // revive and add its todos\r\n project.todoList.forEach((todo) => {\r\n newProject.addRevivedTodo(this.reviveTodo(todo));\r\n });\r\n this.addRevivedProject(newProject);\r\n }\r\n\r\n reviveTodo(todo) {\r\n let newTodo = new _entities__WEBPACK_IMPORTED_MODULE_0__.Todo(todo.title, todo.due, todo.prio);\r\n newTodo.setId(todo.id);\r\n newTodo.setDescription(todo.description);\r\n return newTodo;\r\n }\r\n\r\n addRevivedProject(project) {\r\n this.projectList.push(project);\r\n }\r\n\r\n addProject(title) {\r\n this.projectList.push(new _entities__WEBPACK_IMPORTED_MODULE_0__.Project(title));\r\n }\r\n\r\n getProject(id) {\r\n return this.projectList[id];\r\n }\r\n\r\n getProjects() {\r\n return this.projectList;\r\n }\r\n\r\n addTodoToProject(id, title, due, prio) {\r\n this.projectList[id].addTodo(title, due, prio);\r\n }\r\n\r\n addDescriptionToTodo(projectId, todoId, text) {\r\n this.projectList[projectId].getTodo(todoId).setDescription(text);\r\n }\r\n\r\n updateTodo(projectId, todoId, title, due, prio, description) {\r\n this.projectList[projectId].setTodo(todoId, title, due, prio, description);\r\n }\r\n\r\n deleteProject(id){\r\n this.projectList.splice(id, 1);\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/model.js?"); /***/ }), @@ -190,7 +190,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"View\": () => (/* binding */ View)\n/* harmony export */ });\nclass View {\r\n todoTable;\r\n projectList;\r\n constructor(){\r\n this.todoTable = document.querySelector(\"tbody\");\r\n this.projectList = document.querySelector(\".projectList\");\r\n }\r\n\r\n displayProjects(currentProjectsList) {\r\n this.projectList.innerHTML = \"\";\r\n let id = 0;\r\n currentProjectsList.forEach((project) => {\r\n this.projectList.appendChild(this.createLi(project.title, id++));\r\n });\r\n }\r\n \r\n createLi(projectTitle, id) {\r\n const newLi = document.createElement(\"li\");\r\n newLi.textContent = projectTitle;\r\n newLi.setAttribute(\"id\", id);\r\n return newLi;\r\n }\r\n \r\n displayTodos(currentTodoArray) {\r\n // Wipeout current list\r\n this.todoTable.innerHTML = \"\";\r\n let id = 0;\r\n // loop through list\r\n currentTodoArray.forEach((todo) => {\r\n // Create and add a new row to the table\r\n this.todoTable.appendChild(this.createRow(todo.title, todo.due, todo.prio, id++));\r\n this.todoTable.appendChild(this.createNewTodoPopup(todo.description));\r\n });\r\n }\r\n \r\n createRow(title, due, prio, id) {\r\n const newRow = document.createElement(\"tr\");\r\n newRow.innerHTML = `${title}\r\n ${due}${prio}`;\r\n newRow.setAttribute(\"id\", id);\r\n return newRow;\r\n }\r\n\r\n createNewTodoPopup(description){\r\n const newRowPopup = document.createElement(\"tr\");\r\n newRowPopup.innerHTML = `\r\n
\r\n
`;\r\n newRowPopup.setAttribute(\"class\", \"popup\");\r\n return newRowPopup;\r\n }\r\n\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/view.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"View\": () => (/* binding */ View)\n/* harmony export */ });\nclass View {\r\n todoTable;\r\n projectList;\r\n constructor(){\r\n this.todoTable = document.querySelector(\"tbody\");\r\n this.projectList = document.querySelector(\".projectList\");\r\n }\r\n\r\n displayProjects(currentProjectsList) {\r\n this.projectList.innerHTML = \"\";\r\n let id = 0;\r\n currentProjectsList.forEach((project) => {\r\n this.projectList.appendChild(this.createLi(project.title, id++));\r\n });\r\n }\r\n \r\n createLi(projectTitle, id) {\r\n const newLi = document.createElement(\"li\");\r\n newLi.textContent = projectTitle;\r\n newLi.innerHTML = `${projectTitle}
`;\r\n newLi.setAttribute(\"id\", id);\r\n return newLi;\r\n }\r\n \r\n displayTodos(currentTodoArray) {\r\n // Wipeout current list\r\n this.todoTable.innerHTML = \"\";\r\n let id = 0;\r\n // loop through list\r\n currentTodoArray.forEach((todo) => {\r\n // Create and add a new row to the table\r\n this.todoTable.appendChild(this.createRow(todo.title, todo.due, todo.prio, id++));\r\n this.todoTable.appendChild(this.createNewTodoPopup(todo.description));\r\n });\r\n }\r\n \r\n createRow(title, due, prio, id) {\r\n const newRow = document.createElement(\"tr\");\r\n newRow.innerHTML = `${title}\r\n ${due}${prio}`;\r\n newRow.setAttribute(\"id\", id);\r\n return newRow;\r\n }\r\n\r\n createNewTodoPopup(description){\r\n const newRowPopup = document.createElement(\"tr\");\r\n newRowPopup.innerHTML = `\r\n
\r\n
`;\r\n newRowPopup.setAttribute(\"class\", \"popup\");\r\n return newRowPopup;\r\n }\r\n\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack://todo/./src/modules/view.js?"); /***/ }) diff --git a/src/index.html b/src/index.html index 4197b57..2a314d8 100644 --- a/src/index.html +++ b/src/index.html @@ -4,22 +4,23 @@ Output Management + -
TODOs
+

TODOs Manager

-
+
-

Todos

+

Todos

- + - +
@@ -45,7 +46,7 @@

Todos

Title
-
+
Made by Benjamin-Re
diff --git a/src/modules/controller.js b/src/modules/controller.js index 9e05d82..7549ae4 100644 --- a/src/modules/controller.js +++ b/src/modules/controller.js @@ -37,7 +37,7 @@ class Controller { initializeUI() { // Load stored data when the page is first loaded let data = this.getData(); - if(data){ + if (data) { console.log("There is data"); this.model.revive(data); } else { @@ -60,17 +60,22 @@ class Controller { } getData() { - let data = localStorage.getItem("projects"); + let data = localStorage.getItem("projects"); return JSON.parse(data); } - - listenForProjects() { this.allCurrentProjects = Array.from(document.querySelectorAll("li")); this.allCurrentProjects?.forEach((project) => { project.addEventListener("click", (e) => { - this.currentProjectId = e.target.getAttribute("id"); + // Check if user clicked on delete div + if (e.target.tagName === "svg") { + this.model.deleteProject(this.currentProjectId); + this.view.displayProjects(this.model.getProjects()); + this.listenForProjects(); + this.saveData(); + } + this.currentProjectId = e.currentTarget.getAttribute("id"); // Display all todos for active project this.view.displayTodos( this.model.getProject(this.currentProjectId).getTodos() @@ -121,13 +126,22 @@ class Controller { let todoTitle = this.todoInputField.value; let todoDate = this.todoDate.value; let todoPrio = this.todoPrio.value; - if(this.isUpdate){ + if (this.isUpdate) { // If we update dont create a new todo but overwrite the old one // The id of the todo to update is saved in a global variable // Also get the description as the popup is showing at this flow - let todoDescription = document.querySelector(`tr[id='${this.idToUpdate}']`).nextElementSibling.firstElementChild.firstElementChild.value; - this.model.updateTodo(this.currentProjectId, this.idToUpdate, todoTitle, todoDate, todoPrio, todoDescription); - this.isUpdate=false; + let todoDescription = document.querySelector( + `tr[id='${this.idToUpdate}']` + ).nextElementSibling.firstElementChild.firstElementChild.value; + this.model.updateTodo( + this.currentProjectId, + this.idToUpdate, + todoTitle, + todoDate, + todoPrio, + todoDescription + ); + this.isUpdate = false; } else { this.model.addTodoToProject( this.currentProjectId, @@ -161,24 +175,26 @@ class Controller { this.view.displayTodos( this.model.getProject(this.currentProjectId).getTodos() ); - this.saveData(); + this.listenForTodos(); + this.listenForEdit(); + this.saveData(); }); }); } - listenForEdit(){ + listenForEdit() { const editIcons = Array.from(document.querySelectorAll(".edit-icon")); - editIcons.forEach((icon)=>{ - icon.addEventListener("click", ()=>{ - // Set the global update flag to true so the add button handlers can know. - this.isUpdate=true; + editIcons.forEach((icon) => { + icon.addEventListener("click", () => { + // Set the global update flag to true so the add button handlers can know. + this.isUpdate = true; // Get id of todo to edit and save it in global variable this.idToUpdate = +icon.parentNode.parentNode.previousElementSibling.getAttribute("id"); // Get data from the popup + descr this.popup.classList.add("active"); - }) - }) + }); + }); } listenForTodos() { @@ -212,15 +228,12 @@ class Controller { correspondingTodoId, e.target.value ); - // Save the description - this.saveData(); + // Save the description + this.saveData(); } }); }); } - - - } export { Controller }; diff --git a/src/modules/entities.js b/src/modules/entities.js index a6d2991..e2ae9d3 100644 --- a/src/modules/entities.js +++ b/src/modules/entities.js @@ -22,7 +22,6 @@ class Todo { setDescription(text){ this.description=text; - console.log(this.description); } getDescription(){ @@ -57,10 +56,20 @@ class Todo { class Project { title; + static id = 0; todoList = []; constructor(title){ this.title = title; + this.id = ++Project.id; + } + + setId(id){ + this.id = id; + } + + getId(){ + return this.id; } setTitle(title){ diff --git a/src/modules/model.js b/src/modules/model.js index 0ab36b3..200c803 100644 --- a/src/modules/model.js +++ b/src/modules/model.js @@ -50,7 +50,6 @@ class Model { addTodoToProject(id, title, due, prio) { this.projectList[id].addTodo(title, due, prio); - } addDescriptionToTodo(projectId, todoId, text) { @@ -60,6 +59,10 @@ class Model { updateTodo(projectId, todoId, title, due, prio, description) { this.projectList[projectId].setTodo(todoId, title, due, prio, description); } + + deleteProject(id){ + this.projectList.splice(id, 1); + } } export { Model }; diff --git a/src/modules/view.js b/src/modules/view.js index 89fd4eb..116c073 100644 --- a/src/modules/view.js +++ b/src/modules/view.js @@ -17,6 +17,7 @@ class View { createLi(projectTitle, id) { const newLi = document.createElement("li"); newLi.textContent = projectTitle; + newLi.innerHTML = `${projectTitle}
`; newLi.setAttribute("id", id); return newLi; } diff --git a/src/style.css b/src/style.css index 32daf68..b630309 100644 --- a/src/style.css +++ b/src/style.css @@ -1,30 +1,72 @@ +:root { + --body-color: #e63946; + --header-color: #1d3557; + --footer-color: #1d3557 ; + --aside-color: #f1faee; + --content-color: #f1faee; +} + +* { + padding: 0; + margin: 0; + box-sizing: border-box; +} + body { - background-color: red; + background-color: var(--body-color); height: 100vh; + width: 100vw; display: grid; grid-template-columns: 1fr 4fr; - grid-template-rows: 1fr 3fr 1fr; + grid-template-rows: .5fr 3fr .5fr; font-family: monospace; } +header, aside, .content, footer { + padding: 0; +} + + + +button { + padding: 10px; + border: none; +} + header { - background-color: aliceblue; + color: white; + background-color: var(--header-color); + font-size: x-large; grid-column: 1/3; grid-row: 1/2; } aside { + background-color: var(--aside-color); grid-column: 1/2; grid-row: 2/3; } + +ul { + list-style-type: none; +} + +li { + margin: 0; + display: flex; + justify-content: space-between; +} + .content { - background-color: coral; + padding-left: 1rem; + background-color: var(--content-color); grid-column: 2/3; grid-row: 2/3; } footer { - background-color: aqua; + color: white; + background-color: var(--footer-color); grid-column: 1/3; grid-row: 3/4; }