From 127295de43e519be8a3d62b9e9291a9ff87b454e Mon Sep 17 00:00:00 2001 From: chanin Date: Mon, 17 Feb 2020 17:03:59 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat=20:=20inputItem.js=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 새로운 todo item 등록기능 --- mission001/pci2676/origin/css/style.css | 334 ++++++++++++++++++++++ mission001/pci2676/origin/index.html | 61 ++++ mission001/pci2676/origin/js/inputItem.js | 62 ++++ 3 files changed, 457 insertions(+) create mode 100644 mission001/pci2676/origin/css/style.css create mode 100644 mission001/pci2676/origin/index.html create mode 100644 mission001/pci2676/origin/js/inputItem.js diff --git a/mission001/pci2676/origin/css/style.css b/mission001/pci2676/origin/css/style.css new file mode 100644 index 0000000..8cd8fc0 --- /dev/null +++ b/mission001/pci2676/origin/css/style.css @@ -0,0 +1,334 @@ +html, +body { + margin: 0; + padding: 10px; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #f5f5f5; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 300; +} + +:focus { + outline: 0; +} + +.hidden { + display: none; +} + +.todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.1); +} + +.todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; +} + +.todoapp h1 { + position: absolute; + top: -125px; + width: 100%; + font-size: 60px; + text-align: center; + color: dimgray; + font-weight: 100; + font-family: Helvetica Neue, Helvetica, Arial, sans-serif; +} + +.new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + color: inherit; + padding: 6px; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03); +} + +.main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; +} + +.toggle-all { + width: 1px; + height: 1px; + border: none; + opacity: 0; + position: absolute; + right: 100%; + bottom: 100%; +} + +.toggle-all + label { + width: 60px; + height: 34px; + font-size: 0; + position: absolute; + top: -52px; + left: -13px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.toggle-all + label:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked + label:before { + color: #737373; +} + +.todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +.todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; +} + +.todo-list li:last-child { + border-bottom: none; +} + +.todo-list li.editing { + border-bottom: none; + padding: 0; +} + +.todo-list li.editing .edit { + display: block; + width: calc(100% - 43px); + padding: 12px 16px; + margin: 0 0 0 43px; +} + +.todo-list li.editing .view { + display: none; +} + +.todo-list li .toggle { + text-align: center; + width: 40px; + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; + -webkit-appearance: none; + appearance: none; +} + +.todo-list li .toggle { + opacity: 0; +} + +.todo-list li .toggle + label { + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-position: center left; +} + +.todo-list li .toggle:checked + label { + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E'); +} + +.todo-list li label { + word-break: break-all; + padding: 15px 15px 15px 60px; + display: block; + line-height: 1.2; + transition: color 0.4s; +} + +.todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; +} + +.todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; + cursor: pointer; +} + +.todo-list li .destroy:hover { + color: #af5b5e; +} + +.todo-list li .destroy:after { + content: '×'; +} + +.todo-list li:hover .destroy { + display: block; +} + +.todo-list li .edit { + display: none; +} + +.todo-list li.editing:last-child { + margin-bottom: -1px; +} + +.count-container { + color: #777; + padding: 10px 15px; + height: 20px; + text-align: center; + border-top: 1px solid #e6e6e6; +} + +.count-container:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), + 0 8px 0 -3px #f6f6f6, + 0 9px 1px -3px rgba(0, 0, 0, 0.2), + 0 16px 0 -6px #f6f6f6, + 0 17px 2px -6px rgba(0, 0, 0, 0.2); +} + +.todo-count { + float: left; + text-align: left; +} + +.todo-count strong { + font-weight: 300; +} + +.filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +.filters li { + display: inline; +} + +.filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); +} + +.filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); +} + +.clear-completed, html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; +} + +.clear-completed:hover { + text-decoration: underline; +} + +.info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; +} + +.info p { + line-height: 1; +} + +.info a { + color: inherit; + text-decoration: none; + font-weight: 400; +} + +.info a:hover { + text-decoration: underline; +} diff --git a/mission001/pci2676/origin/index.html b/mission001/pci2676/origin/index.html new file mode 100644 index 0000000..0825d70 --- /dev/null +++ b/mission001/pci2676/origin/index.html @@ -0,0 +1,61 @@ + + + + + + 이벤트 - TODOS + + + +
+
+

TODOS

+ +
+
+ +
    +
  • +
    + + + +
    + +
  • +
  • +
    + + + +
    + +
  • +
  • +
    + + + +
    + +
  • +
+
+
+ 0 + +
+
+ + + diff --git a/mission001/pci2676/origin/js/inputItem.js b/mission001/pci2676/origin/js/inputItem.js new file mode 100644 index 0000000..1d96ab9 --- /dev/null +++ b/mission001/pci2676/origin/js/inputItem.js @@ -0,0 +1,62 @@ +const todoInput = document.getElementById("new-todo-title"); + +todoInput.onkeyup = function (event) { + if (isNotEnter(event)) { + return false; + } + + const item = todoInput.value; + if (isEmpty(item)) { + return false; + } + + addNewTodoItem(item); +}; + +function isNotEnter(event) { + return event.key !== "Enter"; +} + +function isEmpty(item) { + return !item || item.trim() === ""; +} + +function addNewTodoItem(item) { + //새로운 아이템 append + const list = document.createElement("li"); + const div = makeDiv(item); + list.appendChild(div); + + const todoItemList = document.getElementById("todo-list"); + todoItemList.appendChild(list); +} + +function makeDiv(item) { + const div = document.createElement("div"); + const input = makeToggleCheckBoxInput(); + const label = makeLabel(item); + const button = makeDestroyButton(); + div.appendChild(input); + div.appendChild(label); + div.appendChild(button); + return div; +} + +function makeToggleCheckBoxInput() { + const input = document.createElement("input"); + input.className = "toggle"; + input.type = "checkbox"; + return input; +} + +function makeLabel(item) { + const label = document.createElement("label"); + label.innerText = item; + return label; +} + +function makeDestroyButton() { + const button = document.createElement("button"); + button.className = "destroy"; + return button; +} From f4f58a5e6ff4c6e01ab5f3ed955829393207bc5e Mon Sep 17 00:00:00 2001 From: chanin Date: Wed, 19 Feb 2020 21:11:48 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat=20:=20inputItem.js=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 새로운 todo item 등록기능 --- mission001/pci2676/{origin => }/css/style.css | 0 mission001/pci2676/index.html | 61 ++++++++++++++++++ mission001/pci2676/js/app.js | 8 +++ mission001/pci2676/js/todo/todo_input.js | 24 +++++++ mission001/pci2676/js/todo/todo_template.js | 12 ++++ mission001/pci2676/js/utils/utils.js | 10 +++ mission001/pci2676/origin/index.html | 61 ------------------ mission001/pci2676/origin/js/inputItem.js | 62 ------------------- 8 files changed, 115 insertions(+), 123 deletions(-) rename mission001/pci2676/{origin => }/css/style.css (100%) create mode 100644 mission001/pci2676/index.html create mode 100644 mission001/pci2676/js/app.js create mode 100644 mission001/pci2676/js/todo/todo_input.js create mode 100644 mission001/pci2676/js/todo/todo_template.js create mode 100644 mission001/pci2676/js/utils/utils.js delete mode 100644 mission001/pci2676/origin/index.html delete mode 100644 mission001/pci2676/origin/js/inputItem.js diff --git a/mission001/pci2676/origin/css/style.css b/mission001/pci2676/css/style.css similarity index 100% rename from mission001/pci2676/origin/css/style.css rename to mission001/pci2676/css/style.css diff --git a/mission001/pci2676/index.html b/mission001/pci2676/index.html new file mode 100644 index 0000000..57bd1a2 --- /dev/null +++ b/mission001/pci2676/index.html @@ -0,0 +1,61 @@ + + + + + + 이벤트 - TODOS + + + +
+
+

TODOS

+ +
+
+ +
    +
  • +
    + + + +
    + +
  • +
  • +
    + + + +
    + +
  • +
  • +
    + + + +
    + +
  • +
+
+
+ 0 + +
+
+ + + diff --git a/mission001/pci2676/js/app.js b/mission001/pci2676/js/app.js new file mode 100644 index 0000000..7f0a680 --- /dev/null +++ b/mission001/pci2676/js/app.js @@ -0,0 +1,8 @@ +import todoInput from "./todo/todo_input.js" + +function App() { + var items = []; + todoInput(); +} + +new App(); \ No newline at end of file diff --git a/mission001/pci2676/js/todo/todo_input.js b/mission001/pci2676/js/todo/todo_input.js new file mode 100644 index 0000000..04bf255 --- /dev/null +++ b/mission001/pci2676/js/todo/todo_input.js @@ -0,0 +1,24 @@ +import utils from "../utils/utils.js" +import todoTemplate from "./todo_template.js"; + +function todoInput() { + const todoInput = document.getElementById("new-todo-title"); + const todoList = document.getElementById("todo-list"); + + todoInput.addEventListener('keyup', event => addNewTodo(event)); + + const addNewTodo = function add(event) { + if (utils.isNotEnter(event)) { + return false; + } + const text = todoInput.value; + todoInput.value = ""; + if (utils.isStringEmpty(text)) { + return false; + } + const todoItem = todoTemplate(text, "todo"); + todoList.innerHTML += todoItem; + } +} + +export default todoInput; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/todo_template.js b/mission001/pci2676/js/todo/todo_template.js new file mode 100644 index 0000000..44392e4 --- /dev/null +++ b/mission001/pci2676/js/todo/todo_template.js @@ -0,0 +1,12 @@ +const todoTemplate = function (text, status) { + return `
  • +
    + + + +
    + +
  • ` +}; + +export default todoTemplate; \ No newline at end of file diff --git a/mission001/pci2676/js/utils/utils.js b/mission001/pci2676/js/utils/utils.js new file mode 100644 index 0000000..e7c9233 --- /dev/null +++ b/mission001/pci2676/js/utils/utils.js @@ -0,0 +1,10 @@ +const utils = { + isStringEmpty(item) { + return !item || item.length === 0; + }, + isNotEnter(event) { + return event.key !== "Enter"; + } +}; + +export default utils; diff --git a/mission001/pci2676/origin/index.html b/mission001/pci2676/origin/index.html deleted file mode 100644 index 0825d70..0000000 --- a/mission001/pci2676/origin/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - 이벤트 - TODOS - - - -
    -
    -

    TODOS

    - -
    -
    - -
      -
    • -
      - - - -
      - -
    • -
    • -
      - - - -
      - -
    • -
    • -
      - - - -
      - -
    • -
    -
    -
    - 0 - -
    -
    - - - diff --git a/mission001/pci2676/origin/js/inputItem.js b/mission001/pci2676/origin/js/inputItem.js deleted file mode 100644 index 1d96ab9..0000000 --- a/mission001/pci2676/origin/js/inputItem.js +++ /dev/null @@ -1,62 +0,0 @@ -const todoInput = document.getElementById("new-todo-title"); - -todoInput.onkeyup = function (event) { - if (isNotEnter(event)) { - return false; - } - - const item = todoInput.value; - if (isEmpty(item)) { - return false; - } - - addNewTodoItem(item); -}; - -function isNotEnter(event) { - return event.key !== "Enter"; -} - -function isEmpty(item) { - return !item || item.trim() === ""; -} - -function addNewTodoItem(item) { - //새로운 아이템 append - const list = document.createElement("li"); - const div = makeDiv(item); - list.appendChild(div); - - const todoItemList = document.getElementById("todo-list"); - todoItemList.appendChild(list); -} - -function makeDiv(item) { - const div = document.createElement("div"); - const input = makeToggleCheckBoxInput(); - const label = makeLabel(item); - const button = makeDestroyButton(); - div.appendChild(input); - div.appendChild(label); - div.appendChild(button); - return div; -} - -function makeToggleCheckBoxInput() { - const input = document.createElement("input"); - input.className = "toggle"; - input.type = "checkbox"; - return input; -} - -function makeLabel(item) { - const label = document.createElement("label"); - label.innerText = item; - return label; -} - -function makeDestroyButton() { - const button = document.createElement("button"); - button.className = "destroy"; - return button; -} From 7eb64e4a1cfe9a8e38b8c073254983339df88718 Mon Sep 17 00:00:00 2001 From: chanin Date: Wed, 4 Mar 2020 22:43:37 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission001/pci2676/js/app.js | 11 +++++----- mission001/pci2676/js/todo/todo_input.js | 24 --------------------- mission001/pci2676/js/todo/todo_template.js | 12 ----------- mission001/pci2676/js/utils/utils.js | 14 ++++++++++-- 4 files changed, 18 insertions(+), 43 deletions(-) delete mode 100644 mission001/pci2676/js/todo/todo_input.js delete mode 100644 mission001/pci2676/js/todo/todo_template.js diff --git a/mission001/pci2676/js/app.js b/mission001/pci2676/js/app.js index 7f0a680..3e1b4a8 100644 --- a/mission001/pci2676/js/app.js +++ b/mission001/pci2676/js/app.js @@ -1,8 +1,9 @@ -import todoInput from "./todo/todo_input.js" - function App() { - var items = []; - todoInput(); + initialize(); +} + +function initialize() { + } -new App(); \ No newline at end of file +App(); \ No newline at end of file diff --git a/mission001/pci2676/js/todo/todo_input.js b/mission001/pci2676/js/todo/todo_input.js deleted file mode 100644 index 04bf255..0000000 --- a/mission001/pci2676/js/todo/todo_input.js +++ /dev/null @@ -1,24 +0,0 @@ -import utils from "../utils/utils.js" -import todoTemplate from "./todo_template.js"; - -function todoInput() { - const todoInput = document.getElementById("new-todo-title"); - const todoList = document.getElementById("todo-list"); - - todoInput.addEventListener('keyup', event => addNewTodo(event)); - - const addNewTodo = function add(event) { - if (utils.isNotEnter(event)) { - return false; - } - const text = todoInput.value; - todoInput.value = ""; - if (utils.isStringEmpty(text)) { - return false; - } - const todoItem = todoTemplate(text, "todo"); - todoList.innerHTML += todoItem; - } -} - -export default todoInput; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/todo_template.js b/mission001/pci2676/js/todo/todo_template.js deleted file mode 100644 index 44392e4..0000000 --- a/mission001/pci2676/js/todo/todo_template.js +++ /dev/null @@ -1,12 +0,0 @@ -const todoTemplate = function (text, status) { - return `
  • -
    - - - -
    - -
  • ` -}; - -export default todoTemplate; \ No newline at end of file diff --git a/mission001/pci2676/js/utils/utils.js b/mission001/pci2676/js/utils/utils.js index e7c9233..3b99c19 100644 --- a/mission001/pci2676/js/utils/utils.js +++ b/mission001/pci2676/js/utils/utils.js @@ -1,10 +1,20 @@ -const utils = { +const Utils = { isStringEmpty(item) { return !item || item.length === 0; }, isNotEnter(event) { return event.key !== "Enter"; + }, + makeDateAsString() { + const date = new Date(); + return date.getFullYear().toString() + + date.getMonth().toString() + + date.getDay().toString() + + date.getHours().toString() + + date.getMinutes().toString() + + date.getSeconds().toString() + + date.getMilliseconds().toString() } }; -export default utils; +export default Utils; From d06f2502d525d6794d76f55986231c731e43a973 Mon Sep 17 00:00:00 2001 From: chanin Date: Thu, 16 Apr 2020 21:12:55 +0900 Subject: [PATCH 04/10] feat : add new todo item --- mission001/pci2676/js/app.js | 17 +++++++++++++---- mission001/pci2676/js/todo/Controller.js | 23 +++++++++++++++++++++++ mission001/pci2676/js/todo/Service.js | 11 +++++++++++ mission001/pci2676/js/todo/Storage.js | 13 +++++++++++++ mission001/pci2676/js/todo/Template.js | 19 +++++++++++++++++++ mission001/pci2676/js/todo/View.js | 12 ++++++++++++ 6 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 mission001/pci2676/js/todo/Controller.js create mode 100644 mission001/pci2676/js/todo/Service.js create mode 100644 mission001/pci2676/js/todo/Storage.js create mode 100644 mission001/pci2676/js/todo/Template.js create mode 100644 mission001/pci2676/js/todo/View.js diff --git a/mission001/pci2676/js/app.js b/mission001/pci2676/js/app.js index 3e1b4a8..70e2e08 100644 --- a/mission001/pci2676/js/app.js +++ b/mission001/pci2676/js/app.js @@ -1,9 +1,18 @@ +import Controller from "./todo/Controller.js"; +import Service from "./todo/Service.js"; +import View from "./todo/View.js"; +import Storage from "./todo/Storage.js"; + function App() { - initialize(); + initialize(this); } -function initialize() { - +function initialize(app) { + console.log(app); + const view = new View(); + const storage = new Storage(); + const service = new Service(storage); + app.Controller = new Controller(service, view); } -App(); \ No newline at end of file +new App(); \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js new file mode 100644 index 0000000..983fce9 --- /dev/null +++ b/mission001/pci2676/js/todo/Controller.js @@ -0,0 +1,23 @@ +function Controller(service, view) { + const inputTextBox = document.querySelector("#new-todo-title"); + + inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); + + Controller.prototype.inputListener = (event) => { + const inputItem = inputTextBox.value; + if (isEnter(event) && isNotEmpty(inputItem)) { + inputTextBox.value = ""; + service.addTodoItem(view.addNewItem, inputItem); + } + }; + + function isEnter(event) { + return event.key === 'Enter'; + } + + function isNotEmpty(item) { + return item && item.trim().length !== 0; + } +} + +export default Controller; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Service.js b/mission001/pci2676/js/todo/Service.js new file mode 100644 index 0000000..9eaf19b --- /dev/null +++ b/mission001/pci2676/js/todo/Service.js @@ -0,0 +1,11 @@ +function Service(storage) { + + Service.prototype.addTodoItem = (callback, inputItem) => { + const entity = {}; + entity.value = inputItem; + storage.save(callback, entity); + }; + +} + +export default Service; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Storage.js b/mission001/pci2676/js/todo/Storage.js new file mode 100644 index 0000000..38f43da --- /dev/null +++ b/mission001/pci2676/js/todo/Storage.js @@ -0,0 +1,13 @@ +function Storage() { + let id = 0; + + Storage.prototype.save = (callback, entity) => { + id++; + entity.id = id.toString(); + window.localStorage.setItem(entity.id, entity); + callback(entity); + }; + +} + +export default Storage; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Template.js b/mission001/pci2676/js/todo/Template.js new file mode 100644 index 0000000..a419ade --- /dev/null +++ b/mission001/pci2676/js/todo/Template.js @@ -0,0 +1,19 @@ +const Template = { + getNewItem: (entity) => { + const li = document.createElement('li'); + li.id = entity.id; + + li.innerHTML = ` +
    + + + +
    + + `; + + return li; + } +}; + +export default Template; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js new file mode 100644 index 0000000..f5ca74e --- /dev/null +++ b/mission001/pci2676/js/todo/View.js @@ -0,0 +1,12 @@ +import Template from "./Template.js"; + +function View() { + const todoList = document.querySelector("#todo-list"); + + View.prototype.addNewItem = (entity) => { + const item = Template.getNewItem(entity); + todoList.appendChild(item); + }; +} + +export default View; \ No newline at end of file From 28106c3e47089d976ede430bdc2d32ffbbf21c9e Mon Sep 17 00:00:00 2001 From: chanin Date: Thu, 16 Apr 2020 21:37:23 +0900 Subject: [PATCH 05/10] feat : toggle event --- mission001/pci2676/js/todo/Controller.js | 12 ++++++++++++ mission001/pci2676/js/todo/View.js | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index 983fce9..6e24ea0 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -1,7 +1,9 @@ function Controller(service, view) { const inputTextBox = document.querySelector("#new-todo-title"); + const todoList = document.querySelector("#todo-list"); inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); + todoList.addEventListener('click', (event) => Controller.prototype.toggleListener(event)); Controller.prototype.inputListener = (event) => { const inputItem = inputTextBox.value; @@ -18,6 +20,16 @@ function Controller(service, view) { function isNotEmpty(item) { return item && item.trim().length !== 0; } + + Controller.prototype.toggleListener = (event) => { + if (isToggle(event)) { + view.toggle(event.target.parentElement.parentElement); + } + }; + + function isToggle(event) { + return event.target.className === 'toggle'; + } } export default Controller; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index f5ca74e..d24dcc4 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -7,6 +7,15 @@ function View() { const item = Template.getNewItem(entity); todoList.appendChild(item); }; + + View.prototype.toggle = (target) => { + const status = target.className; + if (!status) { + target.className = 'completed'; + } else if (status === 'completed') { + target.className = ''; + } + } } export default View; \ No newline at end of file From 650b36df262a07c6a2d929d8c9eeef71fef00088 Mon Sep 17 00:00:00 2001 From: chanin Date: Thu, 16 Apr 2020 21:40:32 +0900 Subject: [PATCH 06/10] feat : remove event --- mission001/pci2676/js/todo/Controller.js | 11 +++++++++-- mission001/pci2676/js/todo/View.js | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index 6e24ea0..d2bf8cd 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -3,7 +3,7 @@ function Controller(service, view) { const todoList = document.querySelector("#todo-list"); inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); - todoList.addEventListener('click', (event) => Controller.prototype.toggleListener(event)); + todoList.addEventListener('click', (event) => Controller.prototype.clickListener(event)); Controller.prototype.inputListener = (event) => { const inputItem = inputTextBox.value; @@ -21,15 +21,22 @@ function Controller(service, view) { return item && item.trim().length !== 0; } - Controller.prototype.toggleListener = (event) => { + Controller.prototype.clickListener = (event) => { if (isToggle(event)) { view.toggle(event.target.parentElement.parentElement); } + if (isDelete(event)) { + view.remove(event.target.parentElement.parentElement); + } }; function isToggle(event) { return event.target.className === 'toggle'; } + + function isDelete(event) { + return event.target.className === 'destroy'; + } } export default Controller; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index d24dcc4..494e178 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -16,6 +16,10 @@ function View() { target.className = ''; } } + + View.prototype.remove = (target) => { + target.parentElement.removeChild(target); + } } export default View; \ No newline at end of file From 3f73b52febb2f9421948799eec2425c515df05b7 Mon Sep 17 00:00:00 2001 From: chanin Date: Fri, 17 Apr 2020 19:06:38 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat=20:=20=EC=88=98=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission001/pci2676/index.html | 24 ------------- mission001/pci2676/js/todo/Controller.js | 42 ++++++++++++++-------- mission001/pci2676/js/todo/Service.js | 35 +++++++++++++++++-- mission001/pci2676/js/todo/Storage.js | 31 +++++++++++++++-- mission001/pci2676/js/todo/Template.js | 3 +- mission001/pci2676/js/todo/View.js | 44 ++++++++++++++++++------ 6 files changed, 126 insertions(+), 53 deletions(-) diff --git a/mission001/pci2676/index.html b/mission001/pci2676/index.html index 57bd1a2..8c05a73 100644 --- a/mission001/pci2676/index.html +++ b/mission001/pci2676/index.html @@ -15,30 +15,6 @@

    TODOS

      -
    • -
      - - - -
      - -
    • -
    • -
      - - - -
      - -
    • -
    • -
      - - - -
      - -
    diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index d2bf8cd..5e7fa35 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -1,15 +1,19 @@ function Controller(service, view) { const inputTextBox = document.querySelector("#new-todo-title"); - const todoList = document.querySelector("#todo-list"); inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); - todoList.addEventListener('click', (event) => Controller.prototype.clickListener(event)); Controller.prototype.inputListener = (event) => { const inputItem = inputTextBox.value; if (isEnter(event) && isNotEmpty(inputItem)) { inputTextBox.value = ""; - service.addTodoItem(view.addNewItem, inputItem); + + const eventListener = {}; + eventListener.deleteClick = Controller.prototype.deleteClick; + eventListener.toggleClick = Controller.prototype.toggleClick; + eventListener.editContent = Controller.prototype.editContent; + + service.addTodoItem(view.addNewItem, inputItem, eventListener); } }; @@ -21,21 +25,31 @@ function Controller(service, view) { return item && item.trim().length !== 0; } - Controller.prototype.clickListener = (event) => { - if (isToggle(event)) { - view.toggle(event.target.parentElement.parentElement); + Controller.prototype.toggleClick = (event) => { + const target = event.target.offsetParent; + service.changeStatus(view.toggle, target); + }; + + Controller.prototype.deleteClick = (event) => { + const target = event.target.offsetParent; + service.delete(view.remove, target.id); + }; + + Controller.prototype.editContent = (event) => { + const li = event.target.offsetParent; + + if (isEsc(event)) { + view.editExit(event); + return; } - if (isDelete(event)) { - view.remove(event.target.parentElement.parentElement); + if (isEnter(event)) { + const edited = event.target.value; + service.update(view.update, li.id, edited); } }; - function isToggle(event) { - return event.target.className === 'toggle'; - } - - function isDelete(event) { - return event.target.className === 'destroy'; + function isEsc(event) { + return event.key === 'Escape'; } } diff --git a/mission001/pci2676/js/todo/Service.js b/mission001/pci2676/js/todo/Service.js index 9eaf19b..96d2aab 100644 --- a/mission001/pci2676/js/todo/Service.js +++ b/mission001/pci2676/js/todo/Service.js @@ -1,11 +1,42 @@ function Service(storage) { - Service.prototype.addTodoItem = (callback, inputItem) => { + Service.prototype.addTodoItem = (callback, inputItem, eventListener) => { const entity = {}; entity.value = inputItem; - storage.save(callback, entity); + entity.status = "ready"; + storage.save(callback, entity, eventListener); }; + Service.prototype.delete = (callback, id) => { + const todoId = extractTodoId(id); + storage.delete(callback, todoId); + }; + + Service.prototype.changeStatus = (callback, target) => { + const todoId = extractTodoId(target.id); + const status = target.className; + + const changeStatus = toggle(status); + + storage.changeStatus(callback, todoId, changeStatus); + }; + + function toggle(status) { + if (status === 'ready') { + return 'completed'; + } else if (status === 'completed') { + return 'ready'; + } + } + + Service.prototype.update = (callback, id, edited) => { + const todoId = extractTodoId(id); + storage.update(callback, todoId, edited); + }; + + function extractTodoId(id) { + return id.replace('todo-', ''); + } } export default Service; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Storage.js b/mission001/pci2676/js/todo/Storage.js index 38f43da..93db74a 100644 --- a/mission001/pci2676/js/todo/Storage.js +++ b/mission001/pci2676/js/todo/Storage.js @@ -1,13 +1,40 @@ function Storage() { let id = 0; - Storage.prototype.save = (callback, entity) => { + Storage.prototype.save = (callback, entity, eventListener) => { id++; entity.id = id.toString(); - window.localStorage.setItem(entity.id, entity); + save(entity); + callback(entity, eventListener); + }; + + Storage.prototype.delete = (callback, id) => { + window.localStorage.removeItem(id); + callback(id); + }; + + Storage.prototype.changeStatus = (callback, id, changeStatus) => { + const entity = findById(id); + entity.status = changeStatus; + save(entity); callback(entity); }; + Storage.prototype.update = (callback, id, edited) => { + const entity = findById(id); + entity.value = edited; + save(entity); + callback(entity); + } + + function save(entity) { + window.localStorage.setItem(entity.id, JSON.stringify(entity)); + } + + function findById(id) { + return JSON.parse(window.localStorage.getItem(id)); + } + } export default Storage; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Template.js b/mission001/pci2676/js/todo/Template.js index a419ade..585b86b 100644 --- a/mission001/pci2676/js/todo/Template.js +++ b/mission001/pci2676/js/todo/Template.js @@ -1,7 +1,8 @@ const Template = { getNewItem: (entity) => { const li = document.createElement('li'); - li.id = entity.id; + li.id = 'todo-' + entity.id; + li.className = entity.status; li.innerHTML = `
    diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index 494e178..b838ebc 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -3,23 +3,47 @@ import Template from "./Template.js"; function View() { const todoList = document.querySelector("#todo-list"); - View.prototype.addNewItem = (entity) => { + View.prototype.addNewItem = (entity, eventListener) => { const item = Template.getNewItem(entity); + item.querySelector('.toggle').onclick = eventListener.toggleClick; + item.querySelector('.destroy').onclick = eventListener.deleteClick; + item.querySelector('.label').ondblclick = View.prototype.editMode; + item.querySelector('.edit').addEventListener('keyup', (event) => eventListener.editContent(event)); todoList.appendChild(item); }; - View.prototype.toggle = (target) => { - const status = target.className; - if (!status) { - target.className = 'completed'; - } else if (status === 'completed') { - target.className = ''; - } - } + View.prototype.editMode = (event) => { + const li = event.target.offsetParent; + li.className = 'editing'; + }; - View.prototype.remove = (target) => { + View.prototype.toggle = (entity) => { + const id = '#todo-' + entity.id; + const status = entity.status; + const li = document.querySelector(id); + li.className = status; + }; + + View.prototype.remove = (id) => { + const target = document.querySelector('#todo-' + id.toString()); target.parentElement.removeChild(target); + }; + + View.prototype.editExit = (event) => { + const li = event.target.offsetParent; + + li.className = 'ready'; + event.target.value = li.querySelector('.label').textContent; + }; + + View.prototype.update = (entity) => { + const id = '#todo-' + entity.id; + const li = document.querySelector(id); + li.querySelector('.label').textContent = entity.value; + li.querySelector('.edit').value = entity.value; + li.className = 'ready'; } + } export default View; \ No newline at end of file From 9bd50f1374109cb9e061695ff2d8b13e942c22eb Mon Sep 17 00:00:00 2001 From: chanin Date: Sat, 18 Apr 2020 20:04:12 +0900 Subject: [PATCH 08/10] =?UTF-8?q?feat=20:=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EC=84=B1=EA=B2=A9=EB=B3=84=EB=A1=9C=20=EA=B0=AF=EC=88=98?= =?UTF-8?q?=EC=83=88=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission001/pci2676/index.html | 2 +- mission001/pci2676/js/todo/Controller.js | 12 +++++++++ mission001/pci2676/js/todo/Service.js | 7 ++--- mission001/pci2676/js/todo/View.js | 33 +++++++++++++++++++++++- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/mission001/pci2676/index.html b/mission001/pci2676/index.html index 8c05a73..fb4b3cd 100644 --- a/mission001/pci2676/index.html +++ b/mission001/pci2676/index.html @@ -18,7 +18,7 @@

    TODOS

    - 0 + 0
    • 전체보기 diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index 5e7fa35..a1bd035 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -1,7 +1,9 @@ function Controller(service, view) { const inputTextBox = document.querySelector("#new-todo-title"); + const filters = document.querySelector(".filters"); inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); + filters.addEventListener('click', (event) => Controller.prototype.todoCountClickListener(event)); Controller.prototype.inputListener = (event) => { const inputItem = inputTextBox.value; @@ -51,6 +53,16 @@ function Controller(service, view) { function isEsc(event) { return event.key === 'Escape'; } + + Controller.prototype.todoCountClickListener = (event) => { + const tagName = event.target.tagName; + if (tagName !== 'A') { + return; + } + const target = event.target.classList.item(0); + view.select(target); + view.updateCount(); + }; } export default Controller; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Service.js b/mission001/pci2676/js/todo/Service.js index 96d2aab..d533ee8 100644 --- a/mission001/pci2676/js/todo/Service.js +++ b/mission001/pci2676/js/todo/Service.js @@ -3,7 +3,7 @@ function Service(storage) { Service.prototype.addTodoItem = (callback, inputItem, eventListener) => { const entity = {}; entity.value = inputItem; - entity.status = "ready"; + entity.status = "active"; storage.save(callback, entity, eventListener); }; @@ -22,10 +22,10 @@ function Service(storage) { }; function toggle(status) { - if (status === 'ready') { + if (status === 'active') { return 'completed'; } else if (status === 'completed') { - return 'ready'; + return 'active'; } } @@ -37,6 +37,7 @@ function Service(storage) { function extractTodoId(id) { return id.replace('todo-', ''); } + } export default Service; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index b838ebc..7f57cd8 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -2,6 +2,8 @@ import Template from "./Template.js"; function View() { const todoList = document.querySelector("#todo-list"); + const todoCount = document.querySelector(".count"); + const filters = document.querySelector(".filters"); View.prototype.addNewItem = (entity, eventListener) => { const item = Template.getNewItem(entity); @@ -10,6 +12,7 @@ function View() { item.querySelector('.label').ondblclick = View.prototype.editMode; item.querySelector('.edit').addEventListener('keyup', (event) => eventListener.editContent(event)); todoList.appendChild(item); + View.prototype.updateCount(); }; View.prototype.editMode = (event) => { @@ -22,11 +25,13 @@ function View() { const status = entity.status; const li = document.querySelector(id); li.className = status; + View.prototype.updateCount(); }; View.prototype.remove = (id) => { const target = document.querySelector('#todo-' + id.toString()); target.parentElement.removeChild(target); + View.prototype.updateCount(); }; View.prototype.editExit = (event) => { @@ -42,8 +47,34 @@ function View() { li.querySelector('.label').textContent = entity.value; li.querySelector('.edit').value = entity.value; li.className = 'ready'; - } + }; + + View.prototype.updateCount = () => { + let target; + for (let item of filters.getElementsByTagName('A')) { + if (item.classList.length === 2) { + target = item.classList.item(0); + } + } + + if (target === 'all') { + todoCount.innerHTML = todoList.getElementsByClassName('view').length.toString(); + } else { + todoCount.innerHTML = todoList.getElementsByClassName(target).length.toString(); + } + }; + + View.prototype.select = (target) => { + removeAllSelected(); + filters.querySelector('.' + target).classList.add('selected'); + }; + function removeAllSelected() { + const filterList = filters.children; + for (let idx = 0; idx < filterList.length; idx++) { + filterList[idx].firstElementChild.classList.remove('selected'); + } + } } export default View; \ No newline at end of file From bf87e51e85da167af99ac47846a8f88fdf4815b9 Mon Sep 17 00:00:00 2001 From: chanin Date: Sat, 18 Apr 2020 20:52:14 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat=20:=20=ED=95=84=ED=84=B0=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B4=EC=9D=B4=EA=B2=8C=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission001/pci2676/js/todo/Controller.js | 14 +++++++----- mission001/pci2676/js/todo/View.js | 29 ++++++++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index a1bd035..44bdce9 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -3,7 +3,13 @@ function Controller(service, view) { const filters = document.querySelector(".filters"); inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); - filters.addEventListener('click', (event) => Controller.prototype.todoCountClickListener(event)); + addFilterEvents(); + + function addFilterEvents() { + for (let filter of filters.getElementsByTagName('a')) { + filter.addEventListener('click', (event) => Controller.prototype.filterClick(event)); + } + } Controller.prototype.inputListener = (event) => { const inputItem = inputTextBox.value; @@ -54,11 +60,7 @@ function Controller(service, view) { return event.key === 'Escape'; } - Controller.prototype.todoCountClickListener = (event) => { - const tagName = event.target.tagName; - if (tagName !== 'A') { - return; - } + Controller.prototype.filterClick = (event) => { const target = event.target.classList.item(0); view.select(target); view.updateCount(); diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index 7f57cd8..708b581 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -50,29 +50,40 @@ function View() { }; View.prototype.updateCount = () => { - let target; - for (let item of filters.getElementsByTagName('A')) { - if (item.classList.length === 2) { - target = item.classList.item(0); - } - } + let target = document.querySelector('.selected').classList.item(0); if (target === 'all') { todoCount.innerHTML = todoList.getElementsByClassName('view').length.toString(); } else { todoCount.innerHTML = todoList.getElementsByClassName(target).length.toString(); } + showSelected(); }; View.prototype.select = (target) => { removeAllSelected(); filters.querySelector('.' + target).classList.add('selected'); + showSelected(); }; function removeAllSelected() { - const filterList = filters.children; - for (let idx = 0; idx < filterList.length; idx++) { - filterList[idx].firstElementChild.classList.remove('selected'); + document.querySelector('.selected').classList.remove('selected'); + } + + function showSelected() { + const target = document.querySelector('.selected').classList.item(0); + if (target === 'all') { + for (let li of todoList.getElementsByTagName('li')) { + li.style.display = ''; + } + } else { + for (let li of todoList.getElementsByTagName('li')) { + if (li.className === target) { + li.style.display = ''; + } else { + li.style.display = 'none'; + } + } } } } From 90b29e660054820abfbefa3508ee807cf683ce3e Mon Sep 17 00:00:00 2001 From: chanin Date: Wed, 27 May 2020 01:52:11 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor=20:=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mission001/pci2676/css/style.css | 4 + mission001/pci2676/index.html | 6 +- mission001/pci2676/js/app.js | 23 ++++-- mission001/pci2676/js/todo/Controller.js | 94 ++++++++++++----------- mission001/pci2676/js/todo/Service.js | 4 +- mission001/pci2676/js/todo/Storage.js | 4 +- mission001/pci2676/js/todo/Template.js | 24 +++--- mission001/pci2676/js/todo/View.js | 63 ++++++++------- mission001/pci2676/js/utils/Contants.js | 9 +++ mission001/pci2676/js/utils/Validators.js | 19 +++++ mission001/pci2676/js/utils/utils.js | 20 ----- 11 files changed, 144 insertions(+), 126 deletions(-) create mode 100644 mission001/pci2676/js/utils/Contants.js create mode 100644 mission001/pci2676/js/utils/Validators.js delete mode 100644 mission001/pci2676/js/utils/utils.js diff --git a/mission001/pci2676/css/style.css b/mission001/pci2676/css/style.css index 8cd8fc0..905a92a 100644 --- a/mission001/pci2676/css/style.css +++ b/mission001/pci2676/css/style.css @@ -332,3 +332,7 @@ body { .info a:hover { text-decoration: underline; } + +.d-none { + display: none; +} diff --git a/mission001/pci2676/index.html b/mission001/pci2676/index.html index fb4b3cd..224db60 100644 --- a/mission001/pci2676/index.html +++ b/mission001/pci2676/index.html @@ -21,13 +21,13 @@

      TODOS

      0
    diff --git a/mission001/pci2676/js/app.js b/mission001/pci2676/js/app.js index 70e2e08..dfbfa4e 100644 --- a/mission001/pci2676/js/app.js +++ b/mission001/pci2676/js/app.js @@ -4,15 +4,22 @@ import View from "./todo/View.js"; import Storage from "./todo/Storage.js"; function App() { - initialize(this); -} -function initialize(app) { - console.log(app); - const view = new View(); - const storage = new Storage(); - const service = new Service(storage); - app.Controller = new Controller(service, view); + function initialize(app) { + const $inputTextBox = document.querySelector("#new-todo-title"); + const $filters = document.querySelector(".filters"); + const $todoList = document.querySelector("#todo-list"); + const $todoCount = document.querySelector(".count"); + + const view = new View($todoList, $todoCount); + const storage = new Storage(); + const service = new Service(storage); + const controller = new Controller(service, view); + + controller.init($inputTextBox, $todoList, $filters); + } + + initialize(this); } new App(); \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Controller.js b/mission001/pci2676/js/todo/Controller.js index 44bdce9..47985cb 100644 --- a/mission001/pci2676/js/todo/Controller.js +++ b/mission001/pci2676/js/todo/Controller.js @@ -1,70 +1,74 @@ -function Controller(service, view) { - const inputTextBox = document.querySelector("#new-todo-title"); - const filters = document.querySelector(".filters"); - - inputTextBox.addEventListener('keyup', event => Controller.prototype.inputListener(event)); - addFilterEvents(); +import {EVENT_KEY} from "../utils/Contants.js" +import {EVENT_VALIDATOR, STRING_VALIDATOR} from "../utils/Validators.js"; - function addFilterEvents() { - for (let filter of filters.getElementsByTagName('a')) { - filter.addEventListener('click', (event) => Controller.prototype.filterClick(event)); - } - } - - Controller.prototype.inputListener = (event) => { - const inputItem = inputTextBox.value; - if (isEnter(event) && isNotEmpty(inputItem)) { - inputTextBox.value = ""; - - const eventListener = {}; - eventListener.deleteClick = Controller.prototype.deleteClick; - eventListener.toggleClick = Controller.prototype.toggleClick; - eventListener.editContent = Controller.prototype.editContent; +function Controller(service, view) { - service.addTodoItem(view.addNewItem, inputItem, eventListener); + Controller.prototype.inputListener = (event, $inputTextBox) => { + const inputItem = $inputTextBox.value; + if (EVENT_VALIDATOR.isEnter(event) && STRING_VALIDATOR.isNotEmpty(inputItem)) { + $inputTextBox.value = ""; + service.addTodoItem(view.addNewItem, inputItem); } }; - function isEnter(event) { - return event.key === 'Enter'; - } - - function isNotEmpty(item) { - return item && item.trim().length !== 0; - } - Controller.prototype.toggleClick = (event) => { - const target = event.target.offsetParent; - service.changeStatus(view.toggle, target); + event.preventDefault() + + if (event.target.classList.contains('toggle')) { + const $li = event.target.closest('li'); + service.changeStatus(view.toggle, $li); + } }; Controller.prototype.deleteClick = (event) => { - const target = event.target.offsetParent; - service.delete(view.remove, target.id); + event.preventDefault() + + if (event.target.classList.contains('destroy')) { + const $li = event.target.closest('li'); + service.delete(view.remove, $li.id); + } }; Controller.prototype.editContent = (event) => { - const li = event.target.offsetParent; + event.preventDefault() - if (isEsc(event)) { + const $li = event.target.closest('li'); + + if (EVENT_VALIDATOR.isEsc(event)) { view.editExit(event); return; } - if (isEnter(event)) { + if (EVENT_VALIDATOR.isEnter(event)) { const edited = event.target.value; - service.update(view.update, li.id, edited); + service.update(view.update, $li.id, edited); } }; - function isEsc(event) { - return event.key === 'Escape'; - } - Controller.prototype.filterClick = (event) => { - const target = event.target.classList.item(0); - view.select(target); - view.updateCount(); + event.preventDefault() + + const $target = event.target.closest('a'); + if ($target) { + view.select($target); + view.updateCount(); + } }; + + Controller.prototype.initEventListener = ($inputTextBox, $todoList, $filters) => { + $inputTextBox.addEventListener(EVENT_KEY.KEY_UP, event => Controller.prototype.inputListener(event, $inputTextBox)); + + $todoList.addEventListener(EVENT_KEY.CLICK, (event) => Controller.prototype.toggleClick(event)); + $todoList.addEventListener(EVENT_KEY.CLICK, (event) => Controller.prototype.deleteClick(event)); + $todoList.addEventListener(EVENT_KEY.CLICK, (event) => Controller.prototype.filterClick(event)); + $todoList.addEventListener(EVENT_KEY.DOUBLE_CLICK, (event) => view.editMode(event)); + $todoList.addEventListener(EVENT_KEY.KEY_UP, (event) => Controller.prototype.editContent(event)); + + $filters.addEventListener(EVENT_KEY.CLICK, (event) => Controller.prototype.filterClick(event)); + }; + + Controller.prototype.init = ($inputTextBox, $todoList, $filters) => { + Controller.prototype.initEventListener($inputTextBox, $todoList, $filters); + } } export default Controller; \ No newline at end of file diff --git a/mission001/pci2676/js/todo/Service.js b/mission001/pci2676/js/todo/Service.js index d533ee8..cdf351e 100644 --- a/mission001/pci2676/js/todo/Service.js +++ b/mission001/pci2676/js/todo/Service.js @@ -1,10 +1,10 @@ function Service(storage) { - Service.prototype.addTodoItem = (callback, inputItem, eventListener) => { + Service.prototype.addTodoItem = (callback, inputItem) => { const entity = {}; entity.value = inputItem; entity.status = "active"; - storage.save(callback, entity, eventListener); + storage.save(callback, entity); }; Service.prototype.delete = (callback, id) => { diff --git a/mission001/pci2676/js/todo/Storage.js b/mission001/pci2676/js/todo/Storage.js index 93db74a..ebc30fb 100644 --- a/mission001/pci2676/js/todo/Storage.js +++ b/mission001/pci2676/js/todo/Storage.js @@ -1,11 +1,11 @@ function Storage() { let id = 0; - Storage.prototype.save = (callback, entity, eventListener) => { + Storage.prototype.save = (callback, entity) => { id++; entity.id = id.toString(); save(entity); - callback(entity, eventListener); + callback(entity); }; Storage.prototype.delete = (callback, id) => { diff --git a/mission001/pci2676/js/todo/Template.js b/mission001/pci2676/js/todo/Template.js index 585b86b..11df4f1 100644 --- a/mission001/pci2676/js/todo/Template.js +++ b/mission001/pci2676/js/todo/Template.js @@ -1,19 +1,15 @@ const Template = { - getNewItem: (entity) => { - const li = document.createElement('li'); - li.id = 'todo-' + entity.id; - li.className = entity.status; - - li.innerHTML = ` -
    - - - -
    - + getNewItem(entity) { + return ` +
  • +
    + + + +
    + +
  • `; - - return li; } }; diff --git a/mission001/pci2676/js/todo/View.js b/mission001/pci2676/js/todo/View.js index 708b581..5c42773 100644 --- a/mission001/pci2676/js/todo/View.js +++ b/mission001/pci2676/js/todo/View.js @@ -1,23 +1,21 @@ import Template from "./Template.js"; -function View() { - const todoList = document.querySelector("#todo-list"); - const todoCount = document.querySelector(".count"); - const filters = document.querySelector(".filters"); +function View($todoList, $todoCount) { - View.prototype.addNewItem = (entity, eventListener) => { + View.prototype.addNewItem = (entity) => { const item = Template.getNewItem(entity); - item.querySelector('.toggle').onclick = eventListener.toggleClick; - item.querySelector('.destroy').onclick = eventListener.deleteClick; - item.querySelector('.label').ondblclick = View.prototype.editMode; - item.querySelector('.edit').addEventListener('keyup', (event) => eventListener.editContent(event)); - todoList.appendChild(item); + $todoList.insertAdjacentHTML('afterbegin', item); View.prototype.updateCount(); }; View.prototype.editMode = (event) => { - const li = event.target.offsetParent; - li.className = 'editing'; + event.preventDefault(); + + const $label = event.target.closest('label'); + if ($label) { + const $li = event.target.closest('li'); + $li.className = 'editing'; + } }; View.prototype.toggle = (entity) => { @@ -35,6 +33,8 @@ function View() { }; View.prototype.editExit = (event) => { + event.preventDefault(); + const li = event.target.offsetParent; li.className = 'ready'; @@ -43,26 +43,26 @@ function View() { View.prototype.update = (entity) => { const id = '#todo-' + entity.id; - const li = document.querySelector(id); - li.querySelector('.label').textContent = entity.value; - li.querySelector('.edit').value = entity.value; - li.className = 'ready'; + const $li = document.querySelector(id); + $li.querySelector('.label').textContent = entity.value; + $li.querySelector('.edit').value = entity.value; + $li.className = 'ready'; }; View.prototype.updateCount = () => { - let target = document.querySelector('.selected').classList.item(0); + const target = document.querySelector('.selected').classList.item(0); if (target === 'all') { - todoCount.innerHTML = todoList.getElementsByClassName('view').length.toString(); + $todoCount.innerHTML = $todoList.getElementsByClassName('view').length.toString(); } else { - todoCount.innerHTML = todoList.getElementsByClassName(target).length.toString(); + $todoCount.innerHTML = $todoList.getElementsByClassName(target).length.toString(); } showSelected(); }; View.prototype.select = (target) => { removeAllSelected(); - filters.querySelector('.' + target).classList.add('selected'); + target.classList.add('selected'); showSelected(); }; @@ -71,18 +71,17 @@ function View() { } function showSelected() { - const target = document.querySelector('.selected').classList.item(0); - if (target === 'all') { - for (let li of todoList.getElementsByTagName('li')) { - li.style.display = ''; - } - } else { - for (let li of todoList.getElementsByTagName('li')) { - if (li.className === target) { - li.style.display = ''; - } else { - li.style.display = 'none'; - } + for (let $li of $todoList.getElementsByTagName('li')) { + $li.classList.remove('d-none'); + } + + const filter = document.querySelector('.selected').dataset.filter; + if (filter === 'all') { + return; + } + for (let $li of $todoList.getElementsByTagName('li')) { + if ($li.className !== filter) { + $li.classList.add('d-none') } } } diff --git a/mission001/pci2676/js/utils/Contants.js b/mission001/pci2676/js/utils/Contants.js new file mode 100644 index 0000000..22fd56e --- /dev/null +++ b/mission001/pci2676/js/utils/Contants.js @@ -0,0 +1,9 @@ +const EVENT_KEY = { + CLICK: 'click', + KEY_UP: 'keyup', + DOUBLE_CLICK: 'dblclick' +}; + +export { + EVENT_KEY +} \ No newline at end of file diff --git a/mission001/pci2676/js/utils/Validators.js b/mission001/pci2676/js/utils/Validators.js new file mode 100644 index 0000000..05e845f --- /dev/null +++ b/mission001/pci2676/js/utils/Validators.js @@ -0,0 +1,19 @@ +const EVENT_VALIDATOR = { + isEsc: function (event) { + return event.key === 'Escape'; + }, + isEnter: function (event) { + return event.key === 'Enter'; + } +}; + +const STRING_VALIDATOR = { + isNotEmpty: function (string) { + return string && string.trim().length !== 0; + } +}; + +export { + EVENT_VALIDATOR, + STRING_VALIDATOR +}; \ No newline at end of file diff --git a/mission001/pci2676/js/utils/utils.js b/mission001/pci2676/js/utils/utils.js deleted file mode 100644 index 3b99c19..0000000 --- a/mission001/pci2676/js/utils/utils.js +++ /dev/null @@ -1,20 +0,0 @@ -const Utils = { - isStringEmpty(item) { - return !item || item.length === 0; - }, - isNotEnter(event) { - return event.key !== "Enter"; - }, - makeDateAsString() { - const date = new Date(); - return date.getFullYear().toString() - + date.getMonth().toString() - + date.getDay().toString() - + date.getHours().toString() - + date.getMinutes().toString() - + date.getSeconds().toString() - + date.getMilliseconds().toString() - } -}; - -export default Utils;