From 6b8d5b9b0fb4cb18dab13caf2309967be30ea1e6 Mon Sep 17 00:00:00 2001 From: renee Date: Thu, 8 Jul 2021 17:34:06 +0900 Subject: [PATCH 1/4] =?UTF-8?q?TodoApp=20(1)=20-=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=83=9D=EC=84=B1=20-=20todo=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20-=20todo=20count=20=EC=B6=94=EA=B0=80=20-=20todo=20all,=20ac?= =?UTF-8?q?tive,=20completed=20=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 28 ++++++++- src/js/component/TodoApp.js | 37 +++++++++++ src/js/component/TodoCount.js | 26 ++++++++ src/js/component/TodoInput.js | 29 +++++++++ src/js/component/TodoList.js | 113 ++++++++++++++++++++++++++++++++++ src/js/index.js | 3 + src/js/util/QuerySelector.js | 3 + 7 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/js/component/TodoApp.js create mode 100644 src/js/component/TodoCount.js create mode 100644 src/js/component/TodoInput.js create mode 100644 src/js/component/TodoList.js create mode 100644 src/js/index.js create mode 100644 src/js/util/QuerySelector.js diff --git a/index.html b/index.html index 13a02fdb..89702ac4 100644 --- a/index.html +++ b/index.html @@ -17,7 +17,32 @@

TODOS

/>
- +
0
    @@ -34,5 +59,6 @@

    TODOS

+ diff --git a/src/js/component/TodoApp.js b/src/js/component/TodoApp.js new file mode 100644 index 00000000..764be6d7 --- /dev/null +++ b/src/js/component/TodoApp.js @@ -0,0 +1,37 @@ +import TodoInput from '../component/TodoInput.js' +import TodoList from '../component/TodoList.js' +import TodoCount from '../component/TodoCount.js' + +import $ from '../util/QuerySelector.js' + +function TodoApp () { + this.todos = [] + + this.handleAddTodo = (todoItem) => { + const newTodos = this.todos.slice() + newTodos.push(todoItem) + this.setState(newTodos) + } + + this.render = () => { + this.todoInput = new TodoInput({ + onAddTodo: this.handleAddTodo.bind(this) + }) + this.todoCount = new TodoCount({ + todos: this.todos + }) + this.todoList = new TodoList({ + todos: this.todos + }) + } + + this.setState = (nextState) => { + this.todos = nextState + this.todoList.setState(nextState) + this.todoCount.setState(nextState) + } + + this.render() +} + +export default TodoApp \ No newline at end of file diff --git a/src/js/component/TodoCount.js b/src/js/component/TodoCount.js new file mode 100644 index 00000000..663a675d --- /dev/null +++ b/src/js/component/TodoCount.js @@ -0,0 +1,26 @@ +import $ from '../util/QuerySelector.js' + +function TodoCount({ + todos +}) { + this.todos = todos + this.todoCountGroup = $('.todo-count') + this.todoCount = this.todoCountGroup.querySelector("strong") + + this.handleCountTodo = () => { + this.todoCount.textContent = this.todos.length + } + + this.render = () => { + this.handleCountTodo() + } + + this.setState = (nextState) => { + this.todos = nextState + this.render() + } + + this.render() +} + +export default TodoCount \ No newline at end of file diff --git a/src/js/component/TodoInput.js b/src/js/component/TodoInput.js new file mode 100644 index 00000000..8a5c7a15 --- /dev/null +++ b/src/js/component/TodoInput.js @@ -0,0 +1,29 @@ +import $ from '../util/QuerySelector.js' + +function TodoInput({ + onAddTodo +}) { + this.onAddTodo = onAddTodo + + this.newTodo = $('.new-todo') + + this.handleAddTodo = () => { + this.newTodo.addEventListener("keyup", (e) => { + if(e.keyCode === 13) { + const todoItem = { + todo : this.newTodo.value, + status: "active" + } + this.onAddTodo(todoItem) + } + }) + } + + this.render = () => { + this.handleAddTodo() + } + + this.render() +} + +export default TodoInput \ No newline at end of file diff --git a/src/js/component/TodoList.js b/src/js/component/TodoList.js new file mode 100644 index 00000000..61240e08 --- /dev/null +++ b/src/js/component/TodoList.js @@ -0,0 +1,113 @@ +import $ from '../util/QuerySelector.js' + +const STATUS_ALL = "is-all" +const STATUS_ACTIVE = "is-active" +const STATUS_COMPLETED = "is-completed" + +function TodoList ({ + todos +}) { + this.todoList = $('.todo-list') + this.filters = $('.filters') + this.todos = todos + this.status = STATUS_ALL + + let todoStatus + + this.mapTodos = () => { + switch(this.status) { + case STATUS_ALL : + todoStatus = this.todos + break; + case STATUS_ACTIVE : + todoStatus = this.todos.filter(item => item.status === 'active') + break; + case STATUS_COMPLETED : + todoStatus = this.todos.filter(item => item.status === 'completed') + break; + } + return todos + } + + this.handleMapAllTodo = () => { + this.todoList.innerHTML = this.todos.map(item => { + return `
  • +
    + + + +
    + +
  • ` + }).join('') + } + + this.handleMapActiveTodo = () => { + const todos = this.todos.filter(item => item.status === 'active') + this.todoList.innerHTML = todos.map(item => { + return `
  • +
    + + + +
    + +
  • ` + }).join('') + } + + this.handleMapCompletedTodo = () => { + const todos = this.todos.filter(item => item.status === 'completed') + this.todoList.innerHTML = todos.map(item => { + return `
  • +
    + + + +
    + +
  • ` + }).join('') + } + + this.handleCheckTodo = () => { + + } + + this.handleDelTodo = () => { + + } + + this.handleBindEvents = () => { + this.filters.addEventListener("click", e => { + if(e.target.className == 'active') { + this.status = STATUS_ACTIVE + } else if(e.target.className == 'completed') { + this.status = STATUS_COMPLETED + } + }) + + this.todoList.addEventListener("click", e => { + if(e.target.className == "destroy") { + console.log("삭제") + } else if(e.target.className == "toggle") { + console.log("checkbox") + } + }) + } + + this.render = () => { + this.handleMapList() + this.handleBindEvents() + this.mapTodos() + } + + this.setState = (nextState) => { + this.todos = nextState + this.render() + } + + this.render() +} + +export default TodoList \ No newline at end of file diff --git a/src/js/index.js b/src/js/index.js new file mode 100644 index 00000000..bada07f7 --- /dev/null +++ b/src/js/index.js @@ -0,0 +1,3 @@ +import TodoApp from "./component/TodoApp.js"; + +const todo = new TodoApp() \ No newline at end of file diff --git a/src/js/util/QuerySelector.js b/src/js/util/QuerySelector.js new file mode 100644 index 00000000..588bed07 --- /dev/null +++ b/src/js/util/QuerySelector.js @@ -0,0 +1,3 @@ +const $ = (selector) => document.querySelector(selector) + +export default $ \ No newline at end of file From ddd641a561bb72acab41472c7d4e27c9e770830d Mon Sep 17 00:00:00 2001 From: renee Date: Mon, 12 Jul 2021 17:56:02 +0900 Subject: [PATCH 2/4] =?UTF-8?q?TodoApp=20(2)=20-=20Storage=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85=20-=20Todolist=20active,=20completed=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/component/TodoApp.js | 6 +- src/js/component/TodoInput.js | 1 + src/js/component/TodoList.js | 125 ++++++++++++++++++---------------- src/js/util/Storage.js | 12 ++++ 4 files changed, 84 insertions(+), 60 deletions(-) create mode 100644 src/js/util/Storage.js diff --git a/src/js/component/TodoApp.js b/src/js/component/TodoApp.js index 764be6d7..7c8bb269 100644 --- a/src/js/component/TodoApp.js +++ b/src/js/component/TodoApp.js @@ -2,15 +2,17 @@ import TodoInput from '../component/TodoInput.js' import TodoList from '../component/TodoList.js' import TodoCount from '../component/TodoCount.js' -import $ from '../util/QuerySelector.js' +import { storage } from '../util/Storage.js' function TodoApp () { - this.todos = [] + this.TODOS_KEY = "todos" + this.todos = (localStorage.getItem(this.TODOS_KEY)) ? storage.get(this.TODOS_KEY) : [] this.handleAddTodo = (todoItem) => { const newTodos = this.todos.slice() newTodos.push(todoItem) this.setState(newTodos) + storage.set(this.TODOS_KEY, this.todos) } this.render = () => { diff --git a/src/js/component/TodoInput.js b/src/js/component/TodoInput.js index 8a5c7a15..abba8582 100644 --- a/src/js/component/TodoInput.js +++ b/src/js/component/TodoInput.js @@ -11,6 +11,7 @@ function TodoInput({ this.newTodo.addEventListener("keyup", (e) => { if(e.keyCode === 13) { const todoItem = { + id: String(Date.now()), todo : this.newTodo.value, status: "active" } diff --git a/src/js/component/TodoList.js b/src/js/component/TodoList.js index 61240e08..0e705f45 100644 --- a/src/js/component/TodoList.js +++ b/src/js/component/TodoList.js @@ -10,94 +10,103 @@ function TodoList ({ this.todoList = $('.todo-list') this.filters = $('.filters') this.todos = todos - this.status = STATUS_ALL - - let todoStatus - this.mapTodos = () => { - switch(this.status) { - case STATUS_ALL : - todoStatus = this.todos - break; - case STATUS_ACTIVE : - todoStatus = this.todos.filter(item => item.status === 'active') - break; - case STATUS_COMPLETED : - todoStatus = this.todos.filter(item => item.status === 'completed') - break; - } - return todos + this.todoTemplate = (item) => { + return `
  • +
    + + + +
    +
  • ` } - + this.handleMapAllTodo = () => { - this.todoList.innerHTML = this.todos.map(item => { - return `
  • -
    - - - -
    - -
  • ` - }).join('') + this.todos.map(item => { + this.todoList.insertAdjacentHTML('beforeend', this.todoTemplate(item)) + }) } this.handleMapActiveTodo = () => { const todos = this.todos.filter(item => item.status === 'active') - this.todoList.innerHTML = todos.map(item => { - return `
  • -
    - - - -
    - -
  • ` - }).join('') + todos.map(item => { + this.todoList.insertAdjacentHTML('beforeend', this.todoTemplate(item)) + }) } this.handleMapCompletedTodo = () => { const todos = this.todos.filter(item => item.status === 'completed') - this.todoList.innerHTML = todos.map(item => { - return `
  • -
    - - - -
    - -
  • ` - }).join('') + todos.map(item => { + this.todoList.insertAdjacentHTML('beforeend', this.todoTemplate(item)) + }) } - this.handleCheckTodo = () => { + this.mapTodos = (option = STATUS_ALL) => { + this.todoList.innerHTML = ''; + switch(option) { + case STATUS_ALL : + this.handleMapAllTodo() + break; + case STATUS_ACTIVE : + this.handleMapActiveTodo() + break; + case STATUS_COMPLETED : + this.handleMapCompletedTodo() + break; + } } - this.handleDelTodo = () => { + this.toggleTodo = (target) => { + this.todos.map(item => { + if(item.id == target.id) { + if(item.status == "completed") { + return item.status = "active" + } else if (item.status == "active") { + return item.status = "completed" + } + } + }) + // storage.set(this.TODOS_KEY, this.todos) + } + this.removeTodo = (target) => { + this.todos = this.todos.filter(item => { + if(item.id !== target.id) { + return item + } + }) + // storage.set(this.TODOS_KEY, this.todos) + this.mapTodos() } this.handleBindEvents = () => { this.filters.addEventListener("click", e => { - if(e.target.className == 'active') { - this.status = STATUS_ACTIVE - } else if(e.target.className == 'completed') { - this.status = STATUS_COMPLETED + if(e.target.nodeName === 'A') { + e.target.closest('ul') + .querySelectorAll('a') + .forEach((target) => target.classList.remove('selected')) + e.target.classList.add('selected') + } + if(e.target.classList.contains("active")) { + this.mapTodos(STATUS_ACTIVE) + } else if(e.target.classList.contains("completed")) { + this.mapTodos(STATUS_COMPLETED) + } else if(e.target.classList.contains("all")) { + this.mapTodos(STATUS_ALL) } }) this.todoList.addEventListener("click", e => { - if(e.target.className == "destroy") { - console.log("삭제") - } else if(e.target.className == "toggle") { - console.log("checkbox") + if(e.target.classList.contains("destroy")) { + this.removeTodo(e.target) + } else if(e.target.classList.contains("toggle")) { + this.toggleTodo(e.target) } }) } this.render = () => { - this.handleMapList() this.handleBindEvents() this.mapTodos() } diff --git a/src/js/util/Storage.js b/src/js/util/Storage.js new file mode 100644 index 00000000..beb7edb6 --- /dev/null +++ b/src/js/util/Storage.js @@ -0,0 +1,12 @@ +export const storage = { + get: (TODOS_DATA) => { + try { + return JSON.parse(localStorage.getItem(TODOS_DATA)) + } catch(error) { + console.log(error) + } + }, + set: (key, value) => { + localStorage.setItem(key, JSON.stringify(value)) + } +} From 22374c9df2c83ef239a7ceb4cdf49ac897619594 Mon Sep 17 00:00:00 2001 From: renee Date: Mon, 12 Jul 2021 21:14:42 +0900 Subject: [PATCH 3/4] =?UTF-8?q?TodoApp=20(3)=20-=20Constant=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20-=20toggleTodo,=20removeTodo=20=3D>=20App=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/component/TodoApp.js | 27 +++++++++++++++++++++- src/js/component/TodoList.js | 43 +++++++++++------------------------- src/js/util/Constant.js | 3 +++ 3 files changed, 42 insertions(+), 31 deletions(-) create mode 100644 src/js/util/Constant.js diff --git a/src/js/component/TodoApp.js b/src/js/component/TodoApp.js index 7c8bb269..dfa087f6 100644 --- a/src/js/component/TodoApp.js +++ b/src/js/component/TodoApp.js @@ -15,6 +15,29 @@ function TodoApp () { storage.set(this.TODOS_KEY, this.todos) } + this.handleToggleTodo = (target) => { + this.todos.map(item => { + if(item.id == target.id) { + if(item.status == "completed") { + return item.status = "active" + } else if (item.status == "active") { + return item.status = "completed" + } + } + }) + storage.set(this.TODOS_KEY, this.todos) + } + + this.handleRemoveTodo = (target) => { + this.todos = this.todos.filter(item => { + if(item.id !== target.id) { + return item + } + }) + this.setState(this.todos) + storage.set(this.TODOS_KEY, this.todos) + } + this.render = () => { this.todoInput = new TodoInput({ onAddTodo: this.handleAddTodo.bind(this) @@ -23,7 +46,9 @@ function TodoApp () { todos: this.todos }) this.todoList = new TodoList({ - todos: this.todos + todos: this.todos, + onToggleTodo: this.handleToggleTodo.bind(this), + onRemoveTodo: this.handleRemoveTodo.bind(this) }) } diff --git a/src/js/component/TodoList.js b/src/js/component/TodoList.js index 0e705f45..680b428e 100644 --- a/src/js/component/TodoList.js +++ b/src/js/component/TodoList.js @@ -1,14 +1,20 @@ import $ from '../util/QuerySelector.js' - -const STATUS_ALL = "is-all" -const STATUS_ACTIVE = "is-active" -const STATUS_COMPLETED = "is-completed" +import { + STATUS_ALL, + STATUS_ACTIVE, + STATUS_COMPLETED +} from '../util/Constant.js' function TodoList ({ - todos + todos, + onToggleTodo, + onRemoveTodo }) { this.todoList = $('.todo-list') this.filters = $('.filters') + + this.onToggleTodo = onToggleTodo + this.onRemoveTodo = onRemoveTodo this.todos = todos this.todoTemplate = (item) => { @@ -57,29 +63,6 @@ function TodoList ({ } } - this.toggleTodo = (target) => { - this.todos.map(item => { - if(item.id == target.id) { - if(item.status == "completed") { - return item.status = "active" - } else if (item.status == "active") { - return item.status = "completed" - } - } - }) - // storage.set(this.TODOS_KEY, this.todos) - } - - this.removeTodo = (target) => { - this.todos = this.todos.filter(item => { - if(item.id !== target.id) { - return item - } - }) - // storage.set(this.TODOS_KEY, this.todos) - this.mapTodos() - } - this.handleBindEvents = () => { this.filters.addEventListener("click", e => { if(e.target.nodeName === 'A') { @@ -99,9 +82,9 @@ function TodoList ({ this.todoList.addEventListener("click", e => { if(e.target.classList.contains("destroy")) { - this.removeTodo(e.target) + this.onRemoveTodo(e.target) } else if(e.target.classList.contains("toggle")) { - this.toggleTodo(e.target) + this.onToggleTodo(e.target) } }) } diff --git a/src/js/util/Constant.js b/src/js/util/Constant.js new file mode 100644 index 00000000..4548d771 --- /dev/null +++ b/src/js/util/Constant.js @@ -0,0 +1,3 @@ +export const STATUS_ALL = "is-all" +export const STATUS_ACTIVE = "is-active" +export const STATUS_COMPLETED = "is-completed" \ No newline at end of file From 09b3b7dfe910554ebdeb15a1a8a5c8972e34f90e Mon Sep 17 00:00:00 2001 From: renee Date: Tue, 13 Jul 2021 13:39:44 +0900 Subject: [PATCH 4/4] =?UTF-8?q?TodoApp=20(3)=20-=20completed=20=EC=9D=BC?= =?UTF-8?q?=20=EB=95=8C=20completed=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20active=20=EC=9D=BC=EB=95=8C=20active?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/component/TodoApp.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/js/component/TodoApp.js b/src/js/component/TodoApp.js index dfa087f6..ee41bee2 100644 --- a/src/js/component/TodoApp.js +++ b/src/js/component/TodoApp.js @@ -16,12 +16,15 @@ function TodoApp () { } this.handleToggleTodo = (target) => { + const liItem = target.closest("li") this.todos.map(item => { if(item.id == target.id) { if(item.status == "completed") { - return item.status = "active" - } else if (item.status == "active") { - return item.status = "completed" + item.status = "active" + liItem.classList.remove("completed") + } else if(item.status == "active") { + item.status = "completed" + liItem.classList.add("completed") } } })