From 7d605b9587e8295d99ea5884ff9ff97119d1c0cb Mon Sep 17 00:00:00 2001 From: Dmytro Date: Wed, 31 Mar 2021 19:25:44 +0300 Subject: [PATCH 1/5] HW was rewritten. Now it is with classes. --- HW8(MVC)/images/delete-task.svg | 3 + HW8(MVC)/images/task-done.svg | 4 + HW8(MVC)/images/task.svg | 3 + HW8(MVC)/index.html | 20 +++++ HW8(MVC)/scripts/Controller.js | 138 ++++++++++++++++++++++++++++++ HW8(MVC)/scripts/Model.js | 37 +++++++++ HW8(MVC)/scripts/View.js | 131 +++++++++++++++++++++++++++++ HW8(MVC)/styles/style.css | 143 ++++++++++++++++++++++++++++++++ 8 files changed, 479 insertions(+) create mode 100644 HW8(MVC)/images/delete-task.svg create mode 100644 HW8(MVC)/images/task-done.svg create mode 100644 HW8(MVC)/images/task.svg create mode 100644 HW8(MVC)/index.html create mode 100644 HW8(MVC)/scripts/Controller.js create mode 100644 HW8(MVC)/scripts/Model.js create mode 100644 HW8(MVC)/scripts/View.js create mode 100644 HW8(MVC)/styles/style.css diff --git a/HW8(MVC)/images/delete-task.svg b/HW8(MVC)/images/delete-task.svg new file mode 100644 index 0000000..302135c --- /dev/null +++ b/HW8(MVC)/images/delete-task.svg @@ -0,0 +1,3 @@ + + + diff --git a/HW8(MVC)/images/task-done.svg b/HW8(MVC)/images/task-done.svg new file mode 100644 index 0000000..e0de07c --- /dev/null +++ b/HW8(MVC)/images/task-done.svg @@ -0,0 +1,4 @@ + + + + diff --git a/HW8(MVC)/images/task.svg b/HW8(MVC)/images/task.svg new file mode 100644 index 0000000..f618e5a --- /dev/null +++ b/HW8(MVC)/images/task.svg @@ -0,0 +1,3 @@ + + + diff --git a/HW8(MVC)/index.html b/HW8(MVC)/index.html new file mode 100644 index 0000000..f4dfc61 --- /dev/null +++ b/HW8(MVC)/index.html @@ -0,0 +1,20 @@ + + + + + + + + To-do list + + + + + + +
+ + + + \ No newline at end of file diff --git a/HW8(MVC)/scripts/Controller.js b/HW8(MVC)/scripts/Controller.js new file mode 100644 index 0000000..37d2336 --- /dev/null +++ b/HW8(MVC)/scripts/Controller.js @@ -0,0 +1,138 @@ +import { $V } from './View.js'; +import { $M } from './Model.js'; + +class Controller { + constructor () { + this.invalidInputTimer = null; + this.tasksListIsHidden = true; + } + + initialize() { + $V.tasksContainer.addEventListener('click', this.handleClick); + $V.showButton.addEventListener('click', $V.toggleShowButton); + $V.addButton.addEventListener('click', this.addTask); + + $V.input.addEventListener('input', () => { + if ($V.input.value.length > 0) { + $V.addButton.style.backgroundColor = '#87ff93'; + } else { + $V.addButton.style.backgroundColor = '#fff'; + } + }); + + if (this.anyTasksAlreadySaved()) { + $V.toggleShowButton(); + $V.renderTasks($M.getTasksList()); + } + } + + handleClick(e) { + const clickedOn = e.target; + const clickedOnClassList = clickedOn.classList; + + if (clickedOnClassList.contains('icon')) { + let [type, index] = clickedOnClassList[1].split('-'); + + if (type === 'doneIcon') { + $C.toggleDoneMarker(index); + } else if (type === 'deleteIcon'){ + $C.deleteTask(index); + } else { + $C.switchFilterMode(); + } + } + } + + toggleDoneMarker(index) { + const tasks = $M.getTasksList(); + let isDone = tasks[index].isCompleted; + + if (isDone) { + isDone = false; + } else { + isDone = true; + } + tasks[index].isCompleted = isDone; + + $M.setTasksList(tasks); + $V.renderTasks(tasks); + } + + deleteTask(index) { + const tasks = $M.getTasksList(); + tasks.splice(index, 1); + + $M.setTasksList(tasks); + $V.renderTasks(tasks); + } + + switchFilterMode() { + let currentStatus = this.isFiltered(); + + if (currentStatus === 'true') { + currentStatus = 'false'; + } else { + currentStatus = 'true'; + } + + $M.setFilter(currentStatus); + $V.renderTasks($M.getTasksList()); + } + + addTask() { + $V.addButton.style.backgroundColor = '#fff'; + + if ($V.input.value.length > 0) { + if ($C.tasksListIsHidden) { + $C.tasksListIsHidden = false; + $V.toggleShowButton(); + } + + $M.addTask($V.input.value); + + $V.input.value = ''; + $V.showButton.style.backgroundColor = '#ff8f87'; + $V.renderTasks($M.getTasksList()); + } else { + $V.input.style.border = '1px solid #ff8f87'; + clearTimeout(this.invalidInputTimer); + + this.invalidInputTimer = setTimeout(() => { + $V.input.style.border = '1px solid #000'; + }, 1000); + } + } + + inputIsValid() { + const value = $V.input.value; + $V.input.value = value.trim(); + + if (value.length > 0) { + return true; + } else { + return false; + } + } + + anyTasksAlreadySaved() { + const currentTasksList = $M.getTasksList(); + + if (currentTasksList.length > 0) { + return true; + } else { + return false; + } + } + + isFiltered() { + return localStorage.getItem('isFiltered') ?? 'false'; + } +} + +const $C = new Controller; + +document.body.onload = () => { + $C.initialize(); +} + +export { $C }; \ No newline at end of file diff --git a/HW8(MVC)/scripts/Model.js b/HW8(MVC)/scripts/Model.js new file mode 100644 index 0000000..9a37a73 --- /dev/null +++ b/HW8(MVC)/scripts/Model.js @@ -0,0 +1,37 @@ +// NOT INTERACTING WITH A CONTROLLER. SEEMS LIKE A MISTAKE. +class Model { + constructor() {} + + addTask(title) { + const currentTasks = this.getTasksList(); + + currentTasks.push({ + 'title': title, + 'isCompleted': false + }); + + this.setTasksList(currentTasks); + } + + getTasksList() { + const tasks = JSON.parse(localStorage.getItem('savedTasks')) ?? { list: [] }; + return tasks.list; + } + + setTasksList(tasksList) { + let savedTasks = { + 'list': tasksList + }; + + savedTasks = JSON.stringify(savedTasks); + + localStorage.setItem('savedTasks', savedTasks); + } + + setFilter(newStatus) { + localStorage.setItem('isFiltered', newStatus); + } +} + +const $M = new Model; +export { $M }; \ No newline at end of file diff --git a/HW8(MVC)/scripts/View.js b/HW8(MVC)/scripts/View.js new file mode 100644 index 0000000..f07d14b --- /dev/null +++ b/HW8(MVC)/scripts/View.js @@ -0,0 +1,131 @@ +import { $C } from './Controller.js'; + +class View { + constructor() { + this.toDoContainer = document.querySelector('.to-do'); + + const h1 = document.createElement('h1'); + h1.innerText = 'THINGS TO DO ✌️'; + document.body.prepend(h1); + + this.showButton = document.createElement('button'); + this.showButton.classList.add('to-do__button', 'to-do__button--show'); + this.showButton.title = 'Show all tasks'; + this.showButton.innerText = 'SHOW'; + this.toDoContainer.appendChild(this.showButton); + + this.input = document.createElement('input'); + this.input.classList.add('to-do__input'); + this.input.placeholder = 'Add a new task 👈'; + this.toDoContainer.appendChild(this.input); + + this.addButton = document.createElement('button'); + this.addButton.classList.add('to-do__button', 'to-do__button--add'); + this.addButton.title = 'Add a new task'; + this.addButton.innerText = 'ADD'; + this.toDoContainer.appendChild(this.addButton); + + this.tasksContainer = document.createElement('div'); + this.tasksContainer.classList.add('tasks'); + this.toDoContainer.appendChild(this.tasksContainer); + + this.tasksList = document.createElement('ul'); + this.tasksList.classList.add('tasks__list'); + this.tasksContainer.appendChild(this.tasksList); + } + + renderTasks(tasks) { + if (tasks.length === 0 && $C.isFiltered() === 'false') { + this.toggleShowButton(); + this.showButton.style.display = 'none'; + this.tasksList.style.display = 'none'; + $C.tasksListIsHidden = true; + return; + } + this.createTasksListBody(tasks); + } + + toggleShowButton() { + this.tasksList = document.querySelector('.tasks__list'); + this.showButton = document.querySelector('.to-do__button--show'); + + this.tasksList.style.display = 'inline-block'; + this.showButton.style.display = 'inline-block'; + + if (this.tasksList.style.height >= '25vh') { + this.tasksList.style.height = '0px'; + this.tasksList.style.overflow = 'hidden'; + this.tasksList.style.padding = '0px'; + this.showButton.innerHTML = 'SHOW'; + this.showButton.style.background = '#87ff93'; + } else { + this.tasksList.style.height = '25vh'; + this.tasksList.style.overflowY = 'scroll'; + this.tasksList.style.padding = '15px'; + this.showButton.innerHTML = 'CLOSE'; + this.showButton.style.background = '#ff8f87'; + } + } + + createTasksListBody(tasks) { + this.tasksList.innerHTML = ` +
  • +
    CURRENT TASKS
    +
  • `; + + this.createTasksListItems(tasks); + + let filterButtonText; + if ($C.isFiltered() === 'true') { + filterButtonText = 'NOT DONE'; + } else { + filterButtonText = 'ALL'; + } + + this.tasksList.innerHTML += ` +
  • +
    ADD MORE TASKS
    + +
  • `; + } + + createTasksListItems(tasks) { + let tasksCounter = 0; + + for (const task of tasks) { + if ($C.isFiltered() === 'true' && tasks[tasksCounter].isCompleted === true) { + tasksCounter++; + continue; + } + + this.tasksList.innerHTML += ` +
  • + + +
    ${task.title}
    + + +
  • + `; + + if (task.isCompleted === true) { + const currentMarkAsDoneIcon = document.querySelector('.doneIcon-' + tasksCounter); + currentMarkAsDoneIcon.src = 'images/task-done.svg'; + + const currentTitle = document.querySelector('.title-' + tasksCounter); + currentTitle.classList.add('task__title--done'); + } + + tasksCounter++; + } + } +} + +const $V = new View; +export { $V }; \ No newline at end of file diff --git a/HW8(MVC)/styles/style.css b/HW8(MVC)/styles/style.css new file mode 100644 index 0000000..822353a --- /dev/null +++ b/HW8(MVC)/styles/style.css @@ -0,0 +1,143 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; +} + +body, +button, +input { + font-family: "Roboto", sans-serif; + font-weight: 400; +} + +h1 { + user-select: none; + font-family: "Dela Gothic One", cursive; + font-size: 3.5em; +} + +input { + background-color: #fff; + border: 1px solid #000; +} + +.to-do__input { + margin: 15px 10px 15px 0; + width: 350px; + height: 40px; + padding-left: 10px; + transition: background-color 1s ease; +} + +.to-do__button { + width: 100px; + height: 40px; + cursor: pointer; + font-family: "Dela Gothic One", cursive; + border: 2px solid #000; + background-color: #fff; + transition: all 0.5s ease-out; +} + +.to-do__button:hover { + background-color: rgba(0, 0, 0, 0.137); +} + +.to-do__button--show { + margin-right: 10px; + display: none; + transition: 0.25s ease; + background-color: rgba(50, 218, 50, 0.323); +} + +.tasks { + margin-top: 5px; + height: 0; + transition: 0.5s ease; +} + +.tasks__list { + display: flex; + flex-direction: column; + justify-content: flex-start; + height: 0px; + background-color: rgba(32, 32, 32, 0.096); + transition: 0.35s ease; + overflow-y: scroll; + border: 1px solid #000; + width: 100%; + letter-spacing: 1.1px; + list-style-type: none; +} + +.tasks__list li { + display: flex; + justify-content: space-between; + align-items: center; +} + +.tasks__list-item { + margin: 10px 0; + padding: 10px 0; + border-bottom: 1px solid rgb(119, 119, 119); +} + +.tasks__list li:first-child, +.tasks__list li:last-child { + justify-content: center; + border-bottom: 0; + font-family: "Dela Gothic One", cursive; + letter-spacing: 0; + padding: 0; + user-select: none; +} + +.tasks__list li:first-child { + margin-top: 0; +} + +.tasks__list li:last-child { + margin-bottom: 0; +} + +.tasks__list li:nth-child(2) { + margin-top: 0px; +} + +.tasks__title { + margin: 0 10px; + display: flex; + align-items: center; + justify-content: center; +} + +.task__title--done { + text-decoration: line-through; +} + +.tasks__button { + background-color: transparent; + cursor: pointer; + border: 0; + outline: none; +} + +.tasks__button img { + width: 25px; +} + +.tasks__button--filter { + border: 1px solid #000; + padding: 0 5px; + font-size: 10px; + font-family: "Dela Gothic One", cursive; +} \ No newline at end of file From 738e8020125ac379966d26cb03c70761f718c45a Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 1 Apr 2021 20:45:10 +0300 Subject: [PATCH 2/5] Added check for existing of the root element for rendering View. Throwing an error if not. --- HW8(MVC)/index.html | 2 +- HW8(MVC)/scripts/View.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HW8(MVC)/index.html b/HW8(MVC)/index.html index f4dfc61..44ad98f 100644 --- a/HW8(MVC)/index.html +++ b/HW8(MVC)/index.html @@ -13,7 +13,7 @@ -
    +
    diff --git a/HW8(MVC)/scripts/View.js b/HW8(MVC)/scripts/View.js index f07d14b..b5d993e 100644 --- a/HW8(MVC)/scripts/View.js +++ b/HW8(MVC)/scripts/View.js @@ -2,7 +2,11 @@ import { $C } from './Controller.js'; class View { constructor() { - this.toDoContainer = document.querySelector('.to-do'); + this.toDoContainer = document.getElementById('to-do'); + + if (this.toDoContainer === null) { + throw new Error(`Root HTML element for creating View of this to-do list was not found.`); + } const h1 = document.createElement('h1'); h1.innerText = 'THINGS TO DO ✌️'; From 16efb0cfa830012015261fc4de447f3843256dda Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 1 Apr 2021 22:48:38 +0300 Subject: [PATCH 3/5] Started to fix issues. --- HW8(MVC)/scripts/Controller.js | 22 +++--- HW8(MVC)/scripts/Model.js | 3 +- HW8(MVC)/scripts/View.js | 130 +++++++++++++++++++++------------ HW8(MVC)/styles/style.css | 12 ++- 4 files changed, 103 insertions(+), 64 deletions(-) diff --git a/HW8(MVC)/scripts/Controller.js b/HW8(MVC)/scripts/Controller.js index 37d2336..e57ecbe 100644 --- a/HW8(MVC)/scripts/Controller.js +++ b/HW8(MVC)/scripts/Controller.js @@ -4,13 +4,12 @@ import { $M } from './Model.js'; class Controller { constructor () { this.invalidInputTimer = null; - this.tasksListIsHidden = true; } initialize() { $V.tasksContainer.addEventListener('click', this.handleClick); $V.showButton.addEventListener('click', $V.toggleShowButton); - $V.addButton.addEventListener('click', this.addTask); + $V.addButton.addEventListener('click', this.passTaskToModel); $V.input.addEventListener('input', () => { if ($V.input.value.length > 0) { @@ -22,7 +21,7 @@ class Controller { if (this.anyTasksAlreadySaved()) { $V.toggleShowButton(); - $V.renderTasks($M.getTasksList()); + $V.renderTasks($M.getTasksList(), this.isFiltered()); } } @@ -55,7 +54,7 @@ class Controller { tasks[index].isCompleted = isDone; $M.setTasksList(tasks); - $V.renderTasks(tasks); + $V.renderTasks(tasks, this.isFiltered()); } deleteTask(index) { @@ -63,7 +62,7 @@ class Controller { tasks.splice(index, 1); $M.setTasksList(tasks); - $V.renderTasks(tasks); + $V.renderTasks(tasks, this.isFiltered()); } switchFilterMode() { @@ -76,23 +75,24 @@ class Controller { } $M.setFilter(currentStatus); - $V.renderTasks($M.getTasksList()); + $V.renderTasks($M.getTasksList(), this.isFiltered()); } - addTask() { + passTaskToModel() { $V.addButton.style.backgroundColor = '#fff'; if ($V.input.value.length > 0) { - if ($C.tasksListIsHidden) { - $C.tasksListIsHidden = false; + const tasksList = document.querySelector('.tasks__list'); + + if (!tasksList.classList.contains('open')) { $V.toggleShowButton(); } - $M.addTask($V.input.value); + $M.addTaskToTheStorage($V.input.value); $V.input.value = ''; $V.showButton.style.backgroundColor = '#ff8f87'; - $V.renderTasks($M.getTasksList()); + $V.renderTasks($M.getTasksList(), $C.isFiltered()); } else { $V.input.style.border = '1px solid #ff8f87'; clearTimeout(this.invalidInputTimer); diff --git a/HW8(MVC)/scripts/Model.js b/HW8(MVC)/scripts/Model.js index 9a37a73..20b202d 100644 --- a/HW8(MVC)/scripts/Model.js +++ b/HW8(MVC)/scripts/Model.js @@ -1,8 +1,7 @@ -// NOT INTERACTING WITH A CONTROLLER. SEEMS LIKE A MISTAKE. class Model { constructor() {} - addTask(title) { + addTaskToTheStorage(title) { const currentTasks = this.getTasksList(); currentTasks.push({ diff --git a/HW8(MVC)/scripts/View.js b/HW8(MVC)/scripts/View.js index b5d993e..0be0464 100644 --- a/HW8(MVC)/scripts/View.js +++ b/HW8(MVC)/scripts/View.js @@ -1,119 +1,153 @@ import { $C } from './Controller.js'; +const h1Text = 'THINGS TO DO ✌️'; +const showButtonTextOnClose = 'SHOW'; +const showButtonTextOnOpen = 'CLOSE'; +const showButtonTitle = 'Show all tasks'; +const addButtonText = 'ADD'; +const addButtonTitle = 'Add a new task'; +const inputPlaceholder = 'Add a new task 👈'; +const tasksListHeaderText = 'CURRENT TASKS'; +const tasksListFooterText = 'ADD MORE TASKS'; +const filterButtonTextOnFiltered = 'NOT DONE'; +const filterButtonTextOnNotFiltered = 'ALL'; +const doneIconAltText = 'Press to mark task as done'; +const deleteIconAltText = 'Press to delete task'; + +const rootElementId = 'to-do'; +const buttonsClassList = 'to-do__button'; +const showButtonClassList = 'to-do__button--show'; +const addButtonClassList = 'to-do__button--add'; +const inputClassList = 'to-do__input'; +const tasksContainerClassList = 'tasks'; +const tasksListClassList = 'tasks__list'; +const tasksListItemClassList = 'tasks__list-item'; +const taskTitleClassList = 'tasks__title'; +const lastTaskTitleClassList = 'tasks__title--last'; +const doneTaskTitleClassList = 'tasks__title--done'; +const iconsButtonClassList = 'tasks__button'; +const filterButtonClassList = 'tasks__button--filter'; +const deleteButtonClassList = 'tasks__button--delete'; +const filterButtonOnFilteredClassList = 'tasks__button--done'; +const iconsClassList = 'icon'; +const taskClassList = 'task'; + +const showButtonColorOnClose = '#87ff93'; +const showButtonColorOnOpen = '#ff8f87'; + class View { constructor() { - this.toDoContainer = document.getElementById('to-do'); + this.toDoContainer = document.getElementById(rootElementId); if (this.toDoContainer === null) { throw new Error(`Root HTML element for creating View of this to-do list was not found.`); } + this.renderUserInerface(); + } + + renderUserInerface() { const h1 = document.createElement('h1'); - h1.innerText = 'THINGS TO DO ✌️'; + h1.textContent = h1Text; document.body.prepend(h1); this.showButton = document.createElement('button'); - this.showButton.classList.add('to-do__button', 'to-do__button--show'); - this.showButton.title = 'Show all tasks'; - this.showButton.innerText = 'SHOW'; + this.showButton.classList.add(buttonsClassList, showButtonClassList); + this.showButton.textContent = showButtonTextOnClose; + this.showButton.title = showButtonTitle; this.toDoContainer.appendChild(this.showButton); this.input = document.createElement('input'); - this.input.classList.add('to-do__input'); - this.input.placeholder = 'Add a new task 👈'; + this.input.classList.add(inputClassList); + this.input.placeholder = inputPlaceholder; this.toDoContainer.appendChild(this.input); this.addButton = document.createElement('button'); - this.addButton.classList.add('to-do__button', 'to-do__button--add'); - this.addButton.title = 'Add a new task'; - this.addButton.innerText = 'ADD'; + this.addButton.classList.add(buttonsClassList, addButtonClassList); + this.addButton.innerText = addButtonText; + this.addButton.title = addButtonTitle; this.toDoContainer.appendChild(this.addButton); this.tasksContainer = document.createElement('div'); - this.tasksContainer.classList.add('tasks'); + this.tasksContainer.classList.add(tasksContainerClassList); this.toDoContainer.appendChild(this.tasksContainer); this.tasksList = document.createElement('ul'); - this.tasksList.classList.add('tasks__list'); + this.tasksList.classList.add(tasksListClassList); this.tasksContainer.appendChild(this.tasksList); } - renderTasks(tasks) { - if (tasks.length === 0 && $C.isFiltered() === 'false') { + renderTasks(tasks, isFiltered) { + if (tasks.length === 0 && isFiltered === 'false') { this.toggleShowButton(); this.showButton.style.display = 'none'; this.tasksList.style.display = 'none'; - $C.tasksListIsHidden = true; return; } - this.createTasksListBody(tasks); + + this.createTasksListBody(tasks, isFiltered); } toggleShowButton() { - this.tasksList = document.querySelector('.tasks__list'); - this.showButton = document.querySelector('.to-do__button--show'); + this.tasksList = document.querySelector(`.${tasksListClassList}`); + this.showButton = document.querySelector(`.${showButtonClassList}`); this.tasksList.style.display = 'inline-block'; this.showButton.style.display = 'inline-block'; + this.tasksList.classList.toggle('open'); - if (this.tasksList.style.height >= '25vh') { - this.tasksList.style.height = '0px'; - this.tasksList.style.overflow = 'hidden'; - this.tasksList.style.padding = '0px'; - this.showButton.innerHTML = 'SHOW'; - this.showButton.style.background = '#87ff93'; + if (this.tasksList.classList.contains('open')) { + this.showButton.textContent = showButtonTextOnOpen; + this.showButton.style.background = showButtonColorOnOpen; } else { - this.tasksList.style.height = '25vh'; - this.tasksList.style.overflowY = 'scroll'; - this.tasksList.style.padding = '15px'; - this.showButton.innerHTML = 'CLOSE'; - this.showButton.style.background = '#ff8f87'; + this.showButton.textContent = showButtonTextOnClose; + this.showButton.style.background = showButtonColorOnClose; } } - createTasksListBody(tasks) { + createTasksListBody(tasks, isFiltered) { this.tasksList.innerHTML = ` -
  • -
    CURRENT TASKS
    +
  • +
    ${tasksListHeaderText}
  • `; - this.createTasksListItems(tasks); + this.createTasksListItems(tasks, isFiltered); let filterButtonText; - if ($C.isFiltered() === 'true') { - filterButtonText = 'NOT DONE'; + if (isFiltered === 'true') { + filterButtonText = filterButtonTextOnFiltered; } else { - filterButtonText = 'ALL'; + filterButtonText = filterButtonTextOnNotFiltered; } this.tasksList.innerHTML += ` -
  • -
    ADD MORE TASKS
    -
  • `; } - createTasksListItems(tasks) { + createTasksListItems(tasks, isFiltered) { let tasksCounter = 0; for (const task of tasks) { - if ($C.isFiltered() === 'true' && tasks[tasksCounter].isCompleted === true) { + if (isFiltered === 'true' && tasks[tasksCounter].isCompleted === true) { tasksCounter++; continue; } this.tasksList.innerHTML += ` -
  • - -
    ${task.title}
    +
    ${task.title}
    -
  • `; @@ -123,7 +157,7 @@ class View { currentMarkAsDoneIcon.src = 'images/task-done.svg'; const currentTitle = document.querySelector('.title-' + tasksCounter); - currentTitle.classList.add('task__title--done'); + currentTitle.classList.add(doneTaskTitleClassList); } tasksCounter++; diff --git a/HW8(MVC)/styles/style.css b/HW8(MVC)/styles/style.css index 822353a..2b86c69 100644 --- a/HW8(MVC)/styles/style.css +++ b/HW8(MVC)/styles/style.css @@ -56,7 +56,6 @@ input { margin-right: 10px; display: none; transition: 0.25s ease; - background-color: rgba(50, 218, 50, 0.323); } .tasks { @@ -69,14 +68,15 @@ input { display: flex; flex-direction: column; justify-content: flex-start; - height: 0px; background-color: rgba(32, 32, 32, 0.096); transition: 0.35s ease; - overflow-y: scroll; border: 1px solid #000; width: 100%; letter-spacing: 1.1px; list-style-type: none; + height: 0px; + overflow-y: hidden; + padding: 0px; } .tasks__list li { @@ -140,4 +140,10 @@ input { padding: 0 5px; font-size: 10px; font-family: "Dela Gothic One", cursive; +} + +.open { + height: 25vh; + overflow-y: scroll; + padding: 15px; } \ No newline at end of file From 87015e1cd40c5888516a27b396aabe3f39287442 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Fri, 2 Apr 2021 13:24:07 +0300 Subject: [PATCH 4/5] Fixed more issues. --- HW8(MVC)/scripts/Controller.js | 54 ++++++++++------------------------ HW8(MVC)/scripts/Model.js | 16 +++++----- HW8(MVC)/scripts/View.js | 30 ++++++++++++++----- 3 files changed, 46 insertions(+), 54 deletions(-) diff --git a/HW8(MVC)/scripts/Controller.js b/HW8(MVC)/scripts/Controller.js index e57ecbe..c9d25f8 100644 --- a/HW8(MVC)/scripts/Controller.js +++ b/HW8(MVC)/scripts/Controller.js @@ -2,30 +2,26 @@ import { $V } from './View.js'; import { $M } from './Model.js'; class Controller { - constructor () { - this.invalidInputTimer = null; - } - initialize() { - $V.tasksContainer.addEventListener('click', this.handleClick); + $V.tasksContainer.addEventListener('click', this.handleClickOnTasksContainer); $V.showButton.addEventListener('click', $V.toggleShowButton); $V.addButton.addEventListener('click', this.passTaskToModel); $V.input.addEventListener('input', () => { if ($V.input.value.length > 0) { - $V.addButton.style.backgroundColor = '#87ff93'; + $V.addButton.style.backgroundColor = $V.greenColor; } else { - $V.addButton.style.backgroundColor = '#fff'; + $V.addButton.style.backgroundColor = $V.redColor; } }); - if (this.anyTasksAlreadySaved()) { + if (this.checkIfAnyTasksAlreadySaved()) { $V.toggleShowButton(); $V.renderTasks($M.getTasksList(), this.isFiltered()); } } - handleClick(e) { + handleClickOnTasksContainer(e) { const clickedOn = e.target; const clickedOnClassList = clickedOn.classList; @@ -44,25 +40,15 @@ class Controller { toggleDoneMarker(index) { const tasks = $M.getTasksList(); - let isDone = tasks[index].isCompleted; - - if (isDone) { - isDone = false; - } else { - isDone = true; - } - tasks[index].isCompleted = isDone; + tasks[index].isCompleted = !tasks[index].isCompleted; - $M.setTasksList(tasks); + $M.saveTasksList(tasks); $V.renderTasks(tasks, this.isFiltered()); } deleteTask(index) { - const tasks = $M.getTasksList(); - tasks.splice(index, 1); - - $M.setTasksList(tasks); - $V.renderTasks(tasks, this.isFiltered()); + $M.removeTaskFromTheTasksList(index); + $V.renderTasks($M.getTasksList(), this.isFiltered()); } switchFilterMode() { @@ -79,7 +65,7 @@ class Controller { } passTaskToModel() { - $V.addButton.style.backgroundColor = '#fff'; + $V.addButton.style.backgroundColor = $V.whiteColor; if ($V.input.value.length > 0) { const tasksList = document.querySelector('.tasks__list'); @@ -88,33 +74,23 @@ class Controller { $V.toggleShowButton(); } - $M.addTaskToTheStorage($V.input.value); + $M.addTaskToTheTasksList($V.input.value); $V.input.value = ''; - $V.showButton.style.backgroundColor = '#ff8f87'; + $V.showButton.style.backgroundColor = $V.redColor; $V.renderTasks($M.getTasksList(), $C.isFiltered()); } else { - $V.input.style.border = '1px solid #ff8f87'; - clearTimeout(this.invalidInputTimer); - - this.invalidInputTimer = setTimeout(() => { - $V.input.style.border = '1px solid #000'; - }, 1000); + $V.addInvalidStyleToTheInput(); } } inputIsValid() { const value = $V.input.value; $V.input.value = value.trim(); - - if (value.length > 0) { - return true; - } else { - return false; - } + return value.length > 0; } - anyTasksAlreadySaved() { + checkIfAnyTasksAlreadySaved() { const currentTasksList = $M.getTasksList(); if (currentTasksList.length > 0) { diff --git a/HW8(MVC)/scripts/Model.js b/HW8(MVC)/scripts/Model.js index 20b202d..10db56a 100644 --- a/HW8(MVC)/scripts/Model.js +++ b/HW8(MVC)/scripts/Model.js @@ -1,15 +1,18 @@ class Model { - constructor() {} - - addTaskToTheStorage(title) { + addTaskToTheTasksList(title) { const currentTasks = this.getTasksList(); - currentTasks.push({ 'title': title, 'isCompleted': false }); - this.setTasksList(currentTasks); + this.saveTasksList(currentTasks); + } + + removeTaskFromTheTasksList(index) { + const currentTasks = $M.getTasksList(); + currentTasks.splice(index, 1); + $M.saveTasksList(currentTasks); } getTasksList() { @@ -17,13 +20,12 @@ class Model { return tasks.list; } - setTasksList(tasksList) { + saveTasksList(tasksList) { let savedTasks = { 'list': tasksList }; savedTasks = JSON.stringify(savedTasks); - localStorage.setItem('savedTasks', savedTasks); } diff --git a/HW8(MVC)/scripts/View.js b/HW8(MVC)/scripts/View.js index 0be0464..5ae5bd6 100644 --- a/HW8(MVC)/scripts/View.js +++ b/HW8(MVC)/scripts/View.js @@ -23,8 +23,7 @@ const tasksContainerClassList = 'tasks'; const tasksListClassList = 'tasks__list'; const tasksListItemClassList = 'tasks__list-item'; const taskTitleClassList = 'tasks__title'; -const lastTaskTitleClassList = 'tasks__title--last'; -const doneTaskTitleClassList = 'tasks__title--done'; +const doneTaskTitleClassList = 'task__title--done'; const iconsButtonClassList = 'tasks__button'; const filterButtonClassList = 'tasks__button--filter'; const deleteButtonClassList = 'tasks__button--delete'; @@ -32,12 +31,18 @@ const filterButtonOnFilteredClassList = 'tasks__button--done'; const iconsClassList = 'icon'; const taskClassList = 'task'; -const showButtonColorOnClose = '#87ff93'; -const showButtonColorOnOpen = '#ff8f87'; +const redColor = '#ff8f87'; +const greenColor = '#87ff93'; +const whiteColor = '#fff'; class View { constructor() { + this.whiteColor = whiteColor; + this.greenColor = greenColor; + this.redColor = redColor; + this.toDoContainer = document.getElementById(rootElementId); + this.invalidInputTimer = null; if (this.toDoContainer === null) { throw new Error(`Root HTML element for creating View of this to-do list was not found.`); @@ -98,17 +103,26 @@ class View { if (this.tasksList.classList.contains('open')) { this.showButton.textContent = showButtonTextOnOpen; - this.showButton.style.background = showButtonColorOnOpen; + this.showButton.style.backgroundColor = '#ff8f87'; } else { this.showButton.textContent = showButtonTextOnClose; - this.showButton.style.background = showButtonColorOnClose; + this.showButton.style.backgroundColor = '#87ff93'; } } + addInvalidStyleToTheInput() { + this.input.style.border = '1px solid #ff8f87'; + clearTimeout(this.invalidInputTimer); + + this.invalidInputTimer = setTimeout(() => { + this.input.style.border = '1px solid #000'; + }, 1000); + } + createTasksListBody(tasks, isFiltered) { this.tasksList.innerHTML = `
  • -
    ${tasksListHeaderText}
    +
    ${tasksListHeaderText}
  • `; this.createTasksListItems(tasks, isFiltered); @@ -122,7 +136,7 @@ class View { this.tasksList.innerHTML += `
  • -
    ${tasksListFooterText}
    +
    ${tasksListFooterText}
    From 3ae5db6edb0472b88d119fbdc0ce3eab8b604fc4 Mon Sep 17 00:00:00 2001 From: Dmytro Date: Mon, 5 Apr 2021 15:25:22 +0300 Subject: [PATCH 5/5] Fixed additional issues. --- HW8(MVC)/index.html | 1 + HW8(MVC)/scripts/View.js | 159 +++++++++++++++++++-------------------- 2 files changed, 79 insertions(+), 81 deletions(-) diff --git a/HW8(MVC)/index.html b/HW8(MVC)/index.html index 44ad98f..83dff9a 100644 --- a/HW8(MVC)/index.html +++ b/HW8(MVC)/index.html @@ -15,6 +15,7 @@
    + \ No newline at end of file diff --git a/HW8(MVC)/scripts/View.js b/HW8(MVC)/scripts/View.js index 5ae5bd6..cb9918b 100644 --- a/HW8(MVC)/scripts/View.js +++ b/HW8(MVC)/scripts/View.js @@ -1,47 +1,42 @@ -import { $C } from './Controller.js'; - -const h1Text = 'THINGS TO DO ✌️'; -const showButtonTextOnClose = 'SHOW'; -const showButtonTextOnOpen = 'CLOSE'; -const showButtonTitle = 'Show all tasks'; -const addButtonText = 'ADD'; -const addButtonTitle = 'Add a new task'; -const inputPlaceholder = 'Add a new task 👈'; -const tasksListHeaderText = 'CURRENT TASKS'; -const tasksListFooterText = 'ADD MORE TASKS'; -const filterButtonTextOnFiltered = 'NOT DONE'; -const filterButtonTextOnNotFiltered = 'ALL'; -const doneIconAltText = 'Press to mark task as done'; -const deleteIconAltText = 'Press to delete task'; - -const rootElementId = 'to-do'; -const buttonsClassList = 'to-do__button'; -const showButtonClassList = 'to-do__button--show'; -const addButtonClassList = 'to-do__button--add'; -const inputClassList = 'to-do__input'; -const tasksContainerClassList = 'tasks'; -const tasksListClassList = 'tasks__list'; -const tasksListItemClassList = 'tasks__list-item'; -const taskTitleClassList = 'tasks__title'; -const doneTaskTitleClassList = 'task__title--done'; -const iconsButtonClassList = 'tasks__button'; -const filterButtonClassList = 'tasks__button--filter'; -const deleteButtonClassList = 'tasks__button--delete'; -const filterButtonOnFilteredClassList = 'tasks__button--done'; -const iconsClassList = 'icon'; -const taskClassList = 'task'; - -const redColor = '#ff8f87'; -const greenColor = '#87ff93'; -const whiteColor = '#fff'; - class View { - constructor() { - this.whiteColor = whiteColor; - this.greenColor = greenColor; - this.redColor = redColor; + static h1Text = 'THINGS TO DO ✌️'; + static showButtonTextOnClose = 'SHOW'; + static showButtonTextOnOpen = 'CLOSE'; + static showButtonTitle = 'Show all tasks'; + static addButtonText = 'ADD'; + static addButtonTitle = 'Add a new task'; + static inputPlaceholder = 'Add a new task 👈'; + static tasksListHeaderText = 'CURRENT TASKS'; + static tasksListFooterText = 'ADD MORE TASKS'; + static filterButtonTextOnFiltered = 'NOT DONE'; + static filterButtonTextOnNotFiltered = 'ALL'; + static doneIconAltText = 'Press to mark task as done'; + static deleteIconAltText = 'Press to delete task'; + + static rootElementId = 'to-do'; + static buttonsClassList = 'to-do__button'; + static showButtonClassList = 'to-do__button--show'; + static addButtonClassList = 'to-do__button--add'; + static inputClassList = 'to-do__input'; + static tasksContainerClassList = 'tasks'; + static tasksListClassList = 'tasks__list'; + + static tasksListItemClassList = 'tasks__list-item'; + static taskTitleClassList = 'tasks__title'; + static doneTaskTitleClassList = 'task__title--done'; + static iconsButtonClassList = 'tasks__button'; + static filterButtonClassList = 'tasks__button--filter'; + static deleteButtonClassList = 'tasks__button--delete'; + static filterButtonOnFilteredClassList = 'tasks__button--done'; + static iconsClassList = 'icon'; + static taskClassList = 'task'; + + static redColor = '#ff8f87'; + static greenColor = '#87ff93'; + static whiteColor = '#fff'; - this.toDoContainer = document.getElementById(rootElementId); + constructor() { + this.toDoContainer = document.getElementById(View.rootElementId); this.invalidInputTimer = null; if (this.toDoContainer === null) { @@ -53,36 +48,40 @@ class View { renderUserInerface() { const h1 = document.createElement('h1'); - h1.textContent = h1Text; + h1.textContent = View.h1Text; document.body.prepend(h1); this.showButton = document.createElement('button'); - this.showButton.classList.add(buttonsClassList, showButtonClassList); - this.showButton.textContent = showButtonTextOnClose; - this.showButton.title = showButtonTitle; + this.showButton.classList.add(View.buttonsClassList, View.showButtonClassList); + this.showButton.textContent = View.showButtonTextOnClose; + this.showButton.title = View.showButtonTitle; this.toDoContainer.appendChild(this.showButton); this.input = document.createElement('input'); - this.input.classList.add(inputClassList); - this.input.placeholder = inputPlaceholder; + this.input.classList.add(View.inputClassList); + this.input.placeholder = View.inputPlaceholder; this.toDoContainer.appendChild(this.input); this.addButton = document.createElement('button'); - this.addButton.classList.add(buttonsClassList, addButtonClassList); - this.addButton.innerText = addButtonText; - this.addButton.title = addButtonTitle; + this.addButton.classList.add(View.buttonsClassList, View.addButtonClassList); + this.addButton.textContent = View.addButtonText; + this.addButton.title = View.addButtonTitle; this.toDoContainer.appendChild(this.addButton); this.tasksContainer = document.createElement('div'); - this.tasksContainer.classList.add(tasksContainerClassList); + this.tasksContainer.classList.add(View.tasksContainerClassList); this.toDoContainer.appendChild(this.tasksContainer); this.tasksList = document.createElement('ul'); - this.tasksList.classList.add(tasksListClassList); + this.tasksList.classList.add(View.tasksListClassList); this.tasksContainer.appendChild(this.tasksList); } renderTasks(tasks, isFiltered) { + /* + Here and below 'true' and 'false' can appear as a string + because localStorage saves only strings. + */ if (tasks.length === 0 && isFiltered === 'false') { this.toggleShowButton(); this.showButton.style.display = 'none'; @@ -94,18 +93,17 @@ class View { } toggleShowButton() { - this.tasksList = document.querySelector(`.${tasksListClassList}`); - this.showButton = document.querySelector(`.${showButtonClassList}`); - + this.tasksList = document.querySelector(`.${View.tasksListClassList}`); + this.showButton = document.querySelector(`.${View.showButtonClassList}`); this.tasksList.style.display = 'inline-block'; this.showButton.style.display = 'inline-block'; this.tasksList.classList.toggle('open'); if (this.tasksList.classList.contains('open')) { - this.showButton.textContent = showButtonTextOnOpen; + this.showButton.textContent = View.showButtonTextOnOpen; this.showButton.style.backgroundColor = '#ff8f87'; } else { - this.showButton.textContent = showButtonTextOnClose; + this.showButton.textContent = View.showButtonTextOnClose; this.showButton.style.backgroundColor = '#87ff93'; } } @@ -121,26 +119,27 @@ class View { createTasksListBody(tasks, isFiltered) { this.tasksList.innerHTML = ` -
  • -
    ${tasksListHeaderText}
    +
  • +
    ${View.tasksListHeaderText}
  • `; this.createTasksListItems(tasks, isFiltered); let filterButtonText; if (isFiltered === 'true') { - filterButtonText = filterButtonTextOnFiltered; + filterButtonText = View.filterButtonTextOnFiltered; } else { - filterButtonText = filterButtonTextOnNotFiltered; + filterButtonText = View.filterButtonTextOnNotFiltered; } - this.tasksList.innerHTML += ` -
  • -
    ${tasksListFooterText}
    - -
  • `; + + `); } createTasksListItems(tasks, isFiltered) { @@ -152,26 +151,24 @@ class View { continue; } - this.tasksList.innerHTML += ` -
  • - - -
    ${task.title}
    - - -
  • - `; + this.tasksList.insertAdjacentHTML('beforeend', + `
  • + +
    ${task.title}
    + +
  • ` + ); if (task.isCompleted === true) { const currentMarkAsDoneIcon = document.querySelector('.doneIcon-' + tasksCounter); currentMarkAsDoneIcon.src = 'images/task-done.svg'; const currentTitle = document.querySelector('.title-' + tasksCounter); - currentTitle.classList.add(doneTaskTitleClassList); + currentTitle.classList.add(View.doneTaskTitleClassList); } tasksCounter++;