기능 구현을 목적으로 만든 프로젝트 입니다
앞으로 스터디를 통해 배워나갈 (prototype, class)등을 사용하여 리팩토링을 진행 할 예정입니다
- 내용을 입력하고 시간을 선택하면 항목이 생성됩니다
- 생성된 항목은 선택한 시간이 지나면 펑~ 삭제됩니다
- 각 항목의 남아있는 시간이 실시간으로 나타납니다
- 항목들은 남아있는 시간 내림차순으로 정렬되어 나옵니다
- 각 항목에는 삭제버튼이 있고 클릭시 바로 삭제됩니다
- 각 항목에는 시간을 5초 연장하는 버튼이 있습니다
- 각 항목에는 시간을 중지하는 버튼이 있습니다. 중지하면 시작버튼이 나오고 시작버튼을 클릭하면 해당 항목의 시간이 다시 흐릅니다
- 전체 펑 리스트를 요약하여 출력합니다. 항목의 총 갯수와 평균 남은시간을 출력합니다
- 초기화 버튼을 제공합니다. 모든 항목이 삭제됩니다
- 모든 항목을 그대로 복사하여 2배로 만드는 버튼을 제공합니다
- 전체 항목을 중지하는 버튼을 제공합니다. 이미 중지된 항목은 영향이 없습니다
- 전체 항목을 시작하는 버튼을 제공합니다. 작동하고 있는 항목은 영향이 없습니다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PUNG</title>
<style>
.pungList {
padding-left: 0;
}
.pungList > li {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.pungList > li > div {
margin: 0 10px;
}
</style>
</head>
<body>
<h1>pung list</h1>
<div class="pungAdd">
<input type="text" class="pungContent" />
<button type="button" data-second="5">5초</button>
<button type="button" data-second="10">10초</button>
<button type="button" data-second="20">20초</button>
</div>
<div>
<p>총: <span id="pungCount">0</span> 건 평균 남은시간: <span id="pungAverge">0.0</span> 초</p>
<button class="pungReset">초기화</button>
<button class="pungDouble">x2</button>
<button class="pungSecondPlusAll" data-second="5">전체+5</button>
<button class="pungStopAll">전체 중지</button>
<button class="pungStartAll">전체 시작</button>
</div>
<ul class="pungList"></ul>
<script src="./js/pung-list.js"></script>
</body>
</html>
const pungList = {
pungLists: [],
timerLists: {},
pungListsElement: null,
// INITIALIZE ==============================================================================
init: function () {
this.initElement();
},
initElement: function () {
const pungContent = document.querySelector(".pungContent");
const pungAdds = document.querySelectorAll(".pungAdd > button");
const pungReset = document.querySelector(".pungReset");
const pungDouble = document.querySelector(".pungDouble");
const pungSecondPlusAll = document.querySelector(".pungSecondPlusAll");
const pungStopAll = document.querySelector(".pungStopAll");
const pungStartAll = document.querySelector(".pungStartAll");
this.pungListsElement = document.querySelector(".pungList");
pungAdds.forEach(pungAdd => {
pungAdd.addEventListener("click", this.handleClickTimer.bind(this, pungContent));
});
pungReset.addEventListener("click", this.handleClickRemoveAll.bind(this));
pungDouble.addEventListener("click", this.handleClickListDoubleCopy.bind(this));
pungSecondPlusAll.addEventListener("click", this.handleClickSecondPlusAll.bind(this));
pungStopAll.addEventListener("click", this.handleClickStopAll.bind(this));
pungStartAll.addEventListener("click", this.handleClickStartAll.bind(this));
},
}
// DATA ==============================================================================
.
..
...
add: function (options) {
const { content, timer, isToggle, timerID } = options;
const newList = { id: `pung-list-${crypto.randomUUID()}`, isToggle, content, timer, timerID };
this.pungLists = this.pungLists.concat(newList);
this.pungLists.sort((a, b) => {
return a.timer - b.timer;
});
this.addView(newList);
},
remove: function (id) {
const removeList = this.getTarget(id);
const removeListIdx = this.getTargetIdx(id);
this.pungLists.splice(removeListIdx, 1);
this.setTimerClear(removeList.timerID);
this.setPungListAverge(removeList.timer);
this.setPungListCounter();
this.removeView(id);
},
update: function (id) {
const updateList = this.getTarget(id);
updateList.timer += 5;
this.setTimerClear(updateList.timerID);
this.updateView(id, updateList.timer);
if (!updateList.isToggle) {
this.setTimer(id, updateList.timer);
}
},
toggle: function (id) {
const toggleList = this.getTarget(id);
const { timer, timerID } = toggleList;
let { isToggle } = toggleList;
toggleList.isToggle = !toggleList.isToggle;
if (toggleList.isToggle) {
this.setTimerClear(toggleList.timerID);
}
else {
this.setTimer(id, toggleList.timer);
}
this.toggleView(id, toggleList.isToggle);
},
stop: function (id) {
const stopList = this.getTarget(id);
stopList.isToggle = true;
this.setTimerClear(stopList.timerID);
this.stopView(id);
},
start: function (id) {
const startList = this.getTarget(id);
startList.isToggle = false;
this.setTimer(id, startList.timer);
this.startView(id);
},
...
..
.
// VIEW ==============================================================================
.
..
...
addView: function (viewData) {
const { id, content, isToggle, timer } = viewData;
const liElement = document.createElement("li");
liElement.setAttribute("id", id);
const template = `
<div class="pungListContent">${content}</div>
<div class="pungListTimer">${timer}초</div>
<div class="pungListEtc">
<button type="button" class="pungListTimerPlus">+5초</button>
<button type="button" class="pungListToggle">${isToggle ? '시작' : '중지'}</button>
<button type="button" class="pungListRemove">삭제</button>
</div>
`;
liElement.innerHTML = template;
const afterNodeIdx = this.pungLists.findIndex(x => x.id === id) + 1;
const afterNodeID = this.pungLists[afterNodeIdx] && this.pungLists[afterNodeIdx].id;
if (afterNodeID) {
const afterNode = document.querySelector(`#${afterNodeID}`);
this.pungListsElement.insertBefore(liElement, afterNode);
}
else {
this.pungListsElement.appendChild(liElement);
}
this.setTimer(id, timer);
this.bindEventNewList(id);
},
removeView: function (id) {
const removeElement = document.querySelector(`#${id}`);
this.pungListsElement.removeChild(removeElement);
},
updateView: function (id, timer) {
const updateElement = document.querySelector(`#${id} .pungListTimer`);
updateElement.textContent = `${timer}초`;
this.setPungListAverge(timer);
},
toggleView: function (id, isToggle) {
const toggleElement = document.querySelector(`#${id} .pungListEtc .pungListToggle`);
if (isToggle) {
toggleElement.textContent = "시작";
}
else {
toggleElement.textContent = "중지";
}
},
stopView: function (id) {
const stopElement = document.querySelector(`#${id} .pungListEtc .pungListToggle`);
stopElement.textContent = "시작";
},
startView: function (id) {
const startElement = document.querySelector(`#${id} .pungListEtc .pungListToggle`);
startElement.textContent = "중지";
},
...
..
.
// HANDLER ==============================================================================
.
..
...
handleClickTimer: function (contentTarget, oEvent) {
const { value } = contentTarget;
const { target } = oEvent;
const { second } = target.dataset;
if (!value) {
alert('내용을 입력해주세요!!');
return;
}
this.add({ content: value, timer: Number(second), timerID: null, isToggle: false });
contentTarget.value = "";
contentTarget.focus();
},
handleClickTimerPlus: function (id) {
this.update(id);
},
handleClickTimerToggle: function (id) {
this.toggle(id);
},
handleClickTimerRemove: function (id) {
this.remove(id);
},
handleClickListDoubleCopy: function () {
let copyLists = [];
copyLists = copyLists.concat(this.pungLists);
copyLists.forEach(copyList => {
this.add({ content: copyList.content, timer: copyList.timer, timerID: null, isToggle: false });
});
},
handleClickSecondPlusAll: function () {
this.pungLists.forEach(pungList => {
this.update(pungList.id);
});
},
handleClickStopAll: function () {
this.pungLists.forEach(pungList => {
this.stop(pungList.id);
});
},
handleClickStartAll: function () {
this.pungLists.forEach(pungList => {
this.start(pungList.id);
});
},
handleClickRemoveAll: function () {
this.pungLists.forEach(pungList => {
this.setTimerClear(pungList.timerID);
});
this.pungLists = []; // 초기화
this.pungListsElement.innerHTML = "";
this.setPungListCounter();
this.setPungListAverge();
},
...
..
.
.
..
...
setTimer: function (id, timer) {
const targetList = this.getTarget(id);
this.setPungListCounter();
this.setPungListAverge(timer);
const timerID = setInterval(() => {
const listTimer = document.querySelector(`#${id} .pungListTimer`);
if (timer < 2) {
this.remove(id);
this.setPungListAverge(timer);
this.setPungListCounter();
return;
}
timer--;
listTimer.textContent = `${timer}초`;
targetList.timer = timer;
this.setPungListAverge(timer);
this.setPungListCounter();
}, 1000);
targetList.timerID = timerID;
targetList.timer = timer;
},
setTimerClear: function (timerID) {
clearInterval(timerID);
timerID = null;
},
setPungListCounter: function () {
const countElement = document.querySelector("#pungCount");
countElement.textContent = this.pungLists.length;
},
setPungListAverge: function () {
const avergeElement = document.querySelector("#pungAverge");
let averge;
let avergeSum = 0;
this.pungLists.forEach(pungList => {
avergeSum += pungList.timer;
});
averge = avergeSum / this.pungLists.length;
if(!averge) {
averge = 0;
}
avergeElement.textContent = averge.toFixed(1);
},
...
..
.
.
..
...
getTarget: function (id) {
return this.pungLists.filter(pungList => pungList.id === id)[0];
},
getTargetIdx: function (id) {
return this.pungLists.findIndex(pungList => pungList.id === id);
},
...
..
.
2022.09.20
<전체삭제 / 전체+5초> 기능 오류 수정
handleClickRemoveAll 기능 추가적인 리팩토링 필요