Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1단계 - todo list] 알리(허진호) 미션 제출합니다. #48

Open
wants to merge 4 commits into
base: jh8579
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,48 @@

## 🎯 요구사항

- [ ] todo list에 todoItem을 키보드로 입력하여 추가하기
- [ ] todo list의 체크박스를 클릭하여 complete 상태로 변경. (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
- [ ] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
- [ ] todo list를 더블클릭했을 때 input 모드로 변경. (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면 수정되지 않은 채로 다시 view 모드로 복귀
- [ ] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기
- [ ] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기
- [x] todo list에 todoItem을 키보드로 입력하여 추가하기
- [x] todo list의 체크박스를 클릭하여 complete 상태로 변경 (li tag 에 completed class 추가, input 태그에 checked 속성 추가)
- [x] todo list의 x버튼을 이용해서 해당 엘리먼트를 삭제
- [x] todo list를 더블클릭했을 때 input 모드로 변경 (li tag 에 editing class 추가) 단 이때 수정을 완료하지 않은 상태에서 esc키를 누르면
수정되지 않은 채로 다시 view 모드로 복귀
- [x] todo list의 item갯수를 count한 갯수를 리스트의 하단에 보여주기
- [x] todo list의 상태값을 확인하여, 해야할 일과, 완료한 일을 클릭하면 해당 상태의 아이템만 보여주기
- [ ] localStorage에 데이터를 저장하여, TodoItem의 CRUD를 반영하기. 따라서 새로고침하여도 저장된 데이터를 확인할 수 있어야 함

<br/>

## 🔔 참고사항

`TodoItem`을 추가할 시 아래 템플릿을 활용하면 됩니다.

```html

<ul id="todo-list" class="todo-list">
<li>
<div class="view">
<input class="toggle" type="checkbox"/>
<label class="label">새로운 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="새로운 타이틀" />
</li>
<li class="editing">
<div class="view">
<input class="toggle" type="checkbox" />
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li class="completed">
<div class="view">
<input class="toggle" type="checkbox" checked/>
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀" />
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox"/>
<label class="label">새로운 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="새로운 타이틀"/>
</li>
<li class="editing">
<div class="view">
<input class="toggle" type="checkbox"/>
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀"/>
</li>
<li class="completed">
<div class="view">
<input class="toggle" type="checkbox" checked/>
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀"/>
</li>
</ul>
```

Expand All @@ -74,7 +78,8 @@

#### <img alt="Tip" src="https://img.shields.io/static/v1.svg?label=&message=Tip&style=flat-square&color=673ab8"> 로컬에서 서버 띄워서 손쉽게 static resources 변경 및 확인하는 방법

로컬에서 웹서버를 띄워 html, css, js 등을 실시간으로 손쉽게 테스트해 볼 수 있습니다. 이를 위해서는 우선 npm이 설치되어 있어야 합니다. 구글에 `npm install` 이란 키워드로 각자의 운영체제에 맞게끔 npm을 설치해주세요. 이후 아래의 명령어를 통해 실시간으로 웹페이지를 테스트해볼 수 있습니다.
로컬에서 웹서버를 띄워 html, css, js 등을 실시간으로 손쉽게 테스트해 볼 수 있습니다. 이를 위해서는 우선 npm이 설치되어 있어야 합니다.
구글에 `npm install` 이란 키워드로 각자의 운영체제에 맞게끔 npm을 설치해주세요. 이후 아래의 명령어를 통해 실시간으로 웹페이지를 테스트해볼 수 있습니다.

```
npm install -g live-server
Expand Down
85 changes: 56 additions & 29 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,38 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>이벤트 - TODOS</title>
<link rel="stylesheet" href="./src/css/style.css" />
</head>
<body>
<div class="todoapp">
<h1>TODOS</h1>
<input
id="new-todo-title"
class="new-todo"
placeholder="할일을 추가해주세요"
autofocus
/>
<main>
<input class="toggle-all" type="checkbox" />
<link rel="stylesheet" href="./src/css/style.css"/>
</head>

<body>
<div class="todoapp">
<h1>TODOS</h1>
<input id="new-todo-title" class="new-todo" placeholder="할일을 추가해주세요" autofocus/>
<main>
<input class="toggle-all" type="checkbox"/>
<ul id="todo-list" class="todo-list"></ul>
<div class="count-container">
<span class="todo-count">총 <strong>0</strong> 개</span>
<ul class="filters">
<li>
<a class="all selected" href="/#">전체보기</a>
<span class="todo-count">총 <strong id="todo-count-value">0</strong> 개</span>
<ul class="filters">
<li>
<a class="all selected" href="#">전체보기</a>
</li>
<li>
<a class="active" href="#active">해야할 일</a>
</li>
<li>
<a class="completed" href="#completed">완료한 일</a>
</li>
</ul>
</div>
</main>
<div>
<ul id="todo-list-template" class="todo-list-template" style="display: none">
<li class="new-template">
<div class="view">
<input class="toggle" type="checkbox"/>
<label class="label">새로운 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="새로운 타이틀"/>
</li>
<li>
<a class="active" href="#active">해야할 일</a>
<li class="editing-template">
<div class="view">
<input class="toggle" type="checkbox"/>
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀"/>
</li>
<li>
<a class="completed" href="#completed">완료한 일</a>
<li class="completed-template">
<div class="view">
<input class="toggle" type="checkbox" checked/>
<label class="label">완료된 타이틀</label>
<button class="destroy"></button>
</div>
<input class="edit" value="완료된 타이틀"/>
</li>
</ul>
</div>
</main>
</ul>
</div>
</body>
</html>
</div>
<script type="text/javascript" src="./src/javascript/todo.js"></script>
</body>

</html>
131 changes: 131 additions & 0 deletions src/javascript/todo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
function makeNewTodoLi() {
return function (e) {
if (e.key === 'Enter') {
clone(this.value);
this.value = "";
}
};
}

function clone(value) {
const newTodoListElement = document.getElementsByClassName(
'new-template')[0].cloneNode(true);
newTodoListElement.id = "new";
newTodoListElement.childNodes[1].childNodes[3].textContent = value;
newTodoListElement.childNodes[3].value = value;
document.getElementById('todo-list').appendChild(newTodoListElement);
updateTotalCount()
}

function updateTotalCount() {
document.getElementById('todo-count-value').textContent = getListCount();

}

function changeOrDeleteLi() {
return function (e) {
if (e.target && e.target.className === "toggle") {
if (e.target.checked === true) {
e.target.parentNode.parentNode.className = "completed"
return;
}
e.target.parentNode.parentNode.className = "new"
}

if (e.target && e.target.className === "destroy") {
if (confirm('정말로 삭제하시겠습니까?') === true) {
const parentElement = e.target.parentNode.parentNode.parentNode;
parentElement.removeChild(e.target.parentNode.parentNode)
updateTotalCount()
}
}
};
}

function changeLiToInput() {
return function (e) {
if (e.target && e.target.className === "label") {
e.target.parentNode.parentNode.className = "editing"
}
};
}

function changeInputToLi() {
return function (e) {
if (e.key === 'Enter') {
if (e.target && e.target.className === "edit") {
let value = e.target.value;
let parentNode = e.target.parentNode;
parentNode.className = "new"
parentNode.childNodes[1].childNodes[3].textContent = value;
}
} else if (e.key === 'Esc' || e.key === 'Escape' || e.key === 27) {
if (e.target && e.target.className === "edit") {
let parentNode = e.target.parentNode;
parentNode.className = "new"
}
}
};
}

function getListCount() {
let childNodes = document.getElementById('todo-list').childNodes;
let count = 0;
for (let i = 0; i < childNodes.length; i++) {
count++;
}
return count;
}

function applyFilterBorderColor(hash) {
let child = document.getElementsByClassName('filters')[0].childNodes;
if (hash === "") {
child[1].childNodes[1].className = "all selected";
child[3].childNodes[1].className = "active";
child[5].childNodes[1].className = "completed";
} else if (hash === "#active") {
child[1].childNodes[1].className = "all";
child[3].childNodes[1].className = "active selected";
child[5].childNodes[1].className = "completed";
} else if (hash === "#completed") {
child[1].childNodes[1].className = "all";
child[3].childNodes[1].className = "active";
child[5].childNodes[1].className = "completed selected";
}
}

function filter(hash) {
let todo_list = document.getElementById('todo-list').childNodes;
for (let i = 0; i < todo_list.length; i++) {
const name = todo_list[i].className;
if (!name.includes(hash)) {
todo_list[i].style.display = 'none';
} else {
todo_list[i].style.display = 'block';
}
}
}

window.onhashchange = function () {
const hash = window.location.hash;
applyFilterBorderColor(hash);

if (hash === "") {
filter("e")
} else if (hash === "#active") {
filter("new")
} else if (hash === "#completed") {
filter("completed")
}
};

document.getElementById('new-todo-title').addEventListener('keypress',
makeNewTodoLi());
document.getElementById('todo-list').addEventListener('click',
changeOrDeleteLi());
document.getElementById('todo-list').addEventListener('dblclick',
changeLiToInput());
document.getElementById('todo-list').addEventListener('keypress',
changeInputToLi());
document.getElementById('todo-list').addEventListener('keydown',
changeInputToLi());